In mr.dunstan's particular case, perhaps "half as useful" is just enough.
If I were creating a tool to find undefined subs, and that tool was only to be used by myself and other Perl programmers within my (hypothetical) company, I could tune it to our site standards. We know which directories hold our in-house modules, and what AUTOLOADs those modules do. I would design for zero false negatives, and then tweak to reduce the false positives. I think the result would be useful, though imperfect.
I have included a working example below. It uses B::Xref to get a listing of subroutines defined or used in the analysed program, including any modules used. Simply listing the subroutines used, but not defined, would clutter the list with runtime-defined subroutines from modules in the Perl library. I get around this by populating %known with the full pathnames of all the modules in @INC, except for those in the current directory, and skipping over the 'subused' lines from those files. You could add another hash to skip over known AUTOLOADed subs from your own modules.
This is a proof-of-concept; much more could be done with a little more code. This version does not even tell you where the undefined subs occurred. It is lightweight enough to be cloned and hacked for multiple projects without creating maintenance issues.
test.plMightyMod.pmuse MightyMod; use XML::Simple; my $y = BadSub(0); my $z = GoodSub(0); print "$y $z";
Find_Undefined_Subroutines.plpackage MightyMod; use strict; require Exporter; our @EXPORT = qw(GoodSub); our @ISA = qw(Exporter); sub GoodSub { return 42 + LostSub(@_); } 1;
Output:#!/usr/bin/perl -w use strict; use File::Find; my %known; find( sub{$known{$File::Find::name}=1 if /\.pm$/}, grep {$_ ne '.'} @INC ); my $pgm = shift or die; my @xref = `perl -MO=Xref,-r $pgm 2>/dev/null` or die; # Xref data looks like this: # test.pl (definitions) 5 main & GoodSub subdef # test.pl (main) 4 (lexical) $ y intro # test.pl (main) 4 main & BadSub subused my %h; foreach (@xref) { my ($file, $where, $line, $package, $sym, $name, $how) = split; next if $how eq 'subused' and $known{$file}; $h{$how}{$name}++; } foreach (sort keys %{$h{subused}}) { print "$_\n" unless $h{subdef}{$_}; }
$ ./Find_Undefined_Subroutines.pl test.pl BadSub LostSub
By the way, B::Lint has an option, undefined-subs, which is supposed to do something similar to my code, but I could not make it find any errors. Perhaps it is because all my Perl interpreters are threaded; B::Lint's documentation says 'This module doesn't work correctly on thread-enabled perls'.
In reply to Re: Compile-time checking for undef subroutines?
by Util
in thread Compile-time checking for undef subroutines?
by mr.dunstan
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |