File Coverage

blib/lib/App/FindCallers.pm
Criterion Covered Total %
statement 12 14 85.7
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 17 19 89.4


line stmt bran cond sub pod time code
1             package App::FindCallers;
2             # ABSTRACT: Find the callers of a given function in a directory tree
3              
4             our $VERSION = '0.02';
5              
6 1     1   13249 use 5.010;
  1         2  
7 1     1   3 use strict;
  1         1  
  1         15  
8 1     1   2 use warnings;
  1         4  
  1         18  
9              
10 1     1   3 use File::Find;
  1         1  
  1         55  
11 1     1   769 use PPI;
  0            
  0            
12              
13             sub report {
14             my ($filename, $f, $nestlevel) = @_;
15             my $indent = " " x $nestlevel;
16             my $message = "Called from";
17             if ($nestlevel) {
18             $message = "Defined in"
19             }
20             my $location = $filename . ":" . $f->line_number;
21              
22             printf "%s%s %s() in %s\n", $indent, $message, $f->name, $location;
23             }
24              
25             sub find_in_file {
26             my ($function, $filename, $cb) = @_;
27             $cb ||= \&report;
28             my $document = PPI::Document->new($filename);
29             unless ($document) {
30             say "Failed to parse $filename " . PPI::Document->errstr;
31             return;
32             }
33             $document->index_locations;
34             my $references = $document->find(sub {
35             $_[1]->isa('PPI::Token::Word') and $_[1]->content eq $function
36             });
37             return unless $references;
38             for my $f (@$references) {
39             my $nestlevel = 0;
40             while ($f = $f->parent) {
41             # XXX this makes skip the declaration of said sub,
42             # but also makes it not detect recursive calls
43             if ($f->isa('PPI::Statement::Sub') and $f->name ne $function) {
44             $cb->($filename, $f, $nestlevel);
45             $nestlevel++;
46             }
47             };
48             }
49             }
50              
51             sub main {
52             my ($funcname, $directory, $cb) = @_;
53             $directory ||= '.';
54             find({ wanted => sub {
55             if (/\.p[lm]$/) {
56             find_in_file $funcname, $_;
57             }
58             }, follow => 1, no_chdir => 1 }, $directory);
59             }
60              
61             1;
62              
63             __END__