If you have a test suite that has almost 100% code coverage, you can use it to find all call sites.
Given the argument for the position in the freeze frame, the built-in caller returns
- Caller Package Name
- File name
- Line number
- Full Submenu
- ... and a few more
Now we can add some code that registers the position of calls. We can either put the result in some data structure for automatic processing, or write the report to a log file. For instance.
sub this_logs { { # seperate scope to not pollute your sub state $log_fh //= do { open my $fh, ">", "record_callsites.log"; # assuming autodie; $fh; }; state $seen = {}; my (undef, undef, undef, $sub) = caller(1); my ($package, $file, $line, ) = caller(0); my $site = $sub ? "$sub()" : "pkg $package"; unless ($seen->{$file}{$line}++) { say {$log_fh} "CALL from $site at $file line $line"; } } my ($param1, $param2) = @_; # etc }
Assuming all your code was
this_logs(1, 2, 3); # direct call foo(); # call from same package my $sub = "this_" . "logs"; baz($sub); # call by name Foo::bar(); # call from different package foo(); # duplicate call sub foo { return this_logs(5, 6, 7); } sub baz { shift()->(1, 2, 3); # no strict refs for this, please }; package Foo; sub bar { main::this_logs(); }
This will create a log file.
CALL from pkg main at - line 20 CALL from main::foo() at - line 28 CALL from main::baz() at - line 31 CALL from Foo::bar() at - line 3
(File name means STDIN)
Therefore, given the appropriate test suite, it can find call sites for which the grepped command cannot be run.
If you have a non-monotic editor, you can also issue a script that opens each file one by one and positions the cursor on the correct line:
say "kate -l $line $file"; say "vim +$line $file";