How can I smoke out undefined subroutines?

To find calls to subs that aren't defined at compile time, you can use B::Lint as follows:

a.pl:

use List::Util qw( min );

sub defined_sub { }
sub defined_later;
sub undefined_sub;

defined_sub();
defined_later();
undefined_sub();
undeclared_sub();
min();
max();              # XXX Didn't import
List::Util::max();
List::Util::mac();  # XXX Typo!

sub defined_later { }

Test:

$ perl -MO=Lint,undefined-subs a.pl
Undefined subroutine 'undefined_sub' called at a.pl line 9
Nonexistent subroutine 'undeclared_sub' called at a.pl line 10
Nonexistent subroutine 'max' called at a.pl line 12
Nonexistent subroutine 'List::Util::mac' called at a.pl line 14
a.pl syntax OK

Note that this is just for sub calls. Method calls (such as Class->method and method Class) aren't checked. But you are asking about sub calls.

Note that foo $x is a valid method call (using the indirect method call syntax) meaning $x->foo if foo isn't a valid function or sub, so B::Lint won't catch that. But it will catch foo($x).


What you're asking for is in at least some sense impossible. Consider the following code snippet:

( rand()<0.5 ? *foo : *bar } = sub { say "Hello World!" };

foo();

There is a 50% chance that this will run OK, and a 50% chance that it will give an "Undefined subroutine" error. The decision is made at runtime, so it's not possible to tell before that what it will be. This is of course a contrived case to demonstrate a point, but runtime (or compile-time) generation of subroutines is not that uncommon in real code. For an example, look at how Moose adds functions that create methods. Static source code analysis will never be able to fully analyze such code.

B::Lint is probably about as good as something pre-runtime can get.


Perhaps Subroutines::ProhibitCallsToUndeclaredSubs policy from Perl::Critic can help

This Policy checks that every unqualified subroutine call has a matching subroutine declaration in the current file, or that it explicitly appears in the import list for one of the included modules.

This "policy" is a part of Perl::Critic::StricterSubs, which needs to be installed. There are a few more policies there. This is considered a severity 4 violation, so you can do

perlcritic -4 script.pl

and parse the output for neither declared nor explicitly imported, or use

perlcritic -4 --single-policy ProhibitCallsToUndeclaredSubs script.pl

Some legitimate uses are still flagged, since it requires all subs to be imported explicitly.

This is a static analyzer, which I think should fit your purpose.