не может быть сделано в общем случае:
my $obj = Obj->new;
my $method = some_external_source();
$obj->$method();
Однако, это должно быть довольно легко получить большое количество случаев (запустить эту программу на себе):
#!/usr/bin/perl
use strict;
use warnings;
sub foo {
bar();
baz(quux());
}
sub bar {
baz();
}
sub baz {
print "foo\n";
}
sub quux {
return 5;
}
my %calls;
while (<>) {
next unless my ($name) = /^sub (\S+)/;
while (<>) {
last if /^}/;
next unless my @funcs = /(\w+)\(/g;
push @{$calls{$name}}, @funcs;
}
}
use Data::Dumper;
print Dumper \%calls;
Заметим, что это не попадает
- вызовы функций, которые не используют круглые скобки (например,
print "foo\n";
)
- вызывает функции, которые разыменованы (например,
$coderef->()
)
- вызовы методов, которые являются строками (например
$obj->$method()
)
- называет Бип открытую скобку на другой линии
- другие вещи, которые я не думал о
Это неправильно ловит
- прокомментировал функции (например
#foo()
)
- некоторых строк (например,
"foo()"
)
- других вещей, которые я не думал о
Если вы хотите лучшее решение, чем тот бесполезный хак, настало время, чтобы начать поиск в PPI
, но даже это будет иметь проблемы с вещами, как $obj->$method()
.
Просто потому, что мне было скучно, вот версия, которая использует PPI
. Он находит только вызовы функций (а не вызовы методов). Он также не пытается сохранить имена подпрограмм уникальными (т.если вы вызываете одну и ту же подпрограмму более одного раза, она будет отображаться более одного раза).
#!/usr/bin/perl
use strict;
use warnings;
use PPI;
use Data::Dumper;
use Scalar::Util qw/blessed/;
sub is {
my ($obj, $class) = @_;
return blessed $obj and $obj->isa($class);
}
my $program = PPI::Document->new(shift);
my $subs = $program->find(
sub { $_[1]->isa('PPI::Statement::Sub') and $_[1]->name }
);
die "no subroutines declared?" unless $subs;
for my $sub (@$subs) {
print $sub->name, "\n";
next unless my $function_calls = $sub->find(
sub {
$_[1]->isa('PPI::Statement') and
$_[1]->child(0)->isa("PPI::Token::Word") and
not (
$_[1]->isa("PPI::Statement::Scheduled") or
$_[1]->isa("PPI::Statement::Package") or
$_[1]->isa("PPI::Statement::Include") or
$_[1]->isa("PPI::Statement::Sub") or
$_[1]->isa("PPI::Statement::Variable") or
$_[1]->isa("PPI::Statement::Compound") or
$_[1]->isa("PPI::Statement::Break") or
$_[1]->isa("PPI::Statement::Given") or
$_[1]->isa("PPI::Statement::When")
)
}
);
print map { "\t" . $_->child(0)->content . "\n" } @$function_calls;
}
http://stackoverflow.com/questions/1270477/how-can-i-generate-call-graphs-for-perl-modules-and-scripts –
Это один специально просят ** Статический анализ **. Другой не указывает, является ли он статичным или нет. –
Поскольку нет окончательного ответа, я заменяю это на CW. –