Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

finding subroutine dependencies?

by Anonymous Monk
on Oct 01, 2009 at 21:30 UTC ( #798738=perlquestion: print w/replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have been looking at some rudimentary code analysis of local Perl code. I had been getting by on the cheap by finding the beginning & end of subroutines by counting braces followed by looking for calls of the subroutines found within the same file.

The problem becomes magnitudes harder when I have started looking at looking at multiple modules at the same time. If modules A & B both define get_width(), the following becomes impossible to resolve:

sub is_too_large { my ($a, $b) = @_; return $a->get_width() > $b->get_width(); }

Do any of you smart people have any thoughts on how I can approach this problem? If there are CPAN modules which can help, I haven't found them yet.

Any insights offered would certainly be appreciated.

Replies are listed 'Best First'.
Re: finding subroutine dependencies?
by Joost (Canon) on Oct 01, 2009 at 21:52 UTC

      Covering all code paths is not necessarily possible. The range of possible value may be environment dependent and too large to test in any reasonable amount of time. Consider the following:

      sub makeUserSelectedObjectDance { # ENVIRONMENT DEPENDENT!!! # any class in @INC that has a dance method will be accepted my ($sClass) = @_; return if ! ($sClass->can('dance')); my $oDancer = $sClass->new(); $oDancer->dance(); return $oSomething; }

      or consider this routine which allows any valid combination of class and method. This kind of thing isn't all that uncommon when coding event-driven frameworks:

      sub applyUserSelectedActionToUserSelectedTarget { # ENVIRONMENT DEPENDENT!!! - relative to codebase size and contents # number of valid parings of class and method can be quite large # in a large codebase my ($sClass, $sMethod) = @_; my $crMethod = $sClass->can($sMethod); return if ! $crMethod; my $oSomething = $sClass->new(); $oSomething->$crMethod(); return $oSomething; }

      Best, beth

      Devel::NYTProf has worked wonders for me in similar situations - especially if you include the nytprofhtml program, which makes a browsable, annotated html document for all the code usage, including summary lists of all code called, how many times etc..., which will give you the dependancies you need.

      Although as Joost says this obviously depends on the tests being up to scratch!

      Just a something something...
Re: finding subroutine dependencies?
by moritz (Cardinal) on Oct 01, 2009 at 22:08 UTC
    That's a problem that can't be solved without running the code, and even approximate solutions are very hard to come by. We've had lots of discussion about that, see static analysis.

    For better parsing I can recommend PPI, which parses Perl as good as you can without executing it.

    Perl 6 - links to (nearly) everything that is Perl 6.
Re: finding subroutine dependencies?
by jakobi (Pilgrim) on Oct 01, 2009 at 22:51 UTC
    One trivial illustration of the problems, even ignoring the works of art created as part of the obfuscated perl contents:
    sub craziness_lurks_here{ # do not count } me, I'm in a comment, not a '-ed string warn "a parens }?\n"; print <<EOF; } EOF }

    Statical: So counting parens on the cheap w/o full parsing (maybe -> Deparse, B, ...) is a problem. If you've a kind of contract with your script authors (they write what you can match), you could get away with just regex hacking for a partial 70% job (extending /sub\+\w\s+(/ to match trivial sub definitions. Similar with sub uses), maybe enough for your use.

    Dynamics: But you still miss (or in general at least cannot determine the sub used in) say sub-references in assignments... but AFAICS this is outside the possibilities of static analysis for both practical and general cases, at least when excluding the most trivial examples (static code validation with theorem provers should still be fairly restricted, even though I didn't follow advances in that area for more than a few years now). Which pretty much closes the circle and leads back to the remarks of my fellow monks above.

    Update: on reading the answer below and the regexes I didn't add above with e.g. /\{{3}/, I just remembered that nowadays we can also have perl5 code run within a regex itself, /(?{print "}"})/ I'd assume. Not to mention the older and more traditional while loop replacement:

    while(s/\{/\}/gio){$b=~//;some-more-code-here} # vs s/\{/do{some-other-regexes+some-more-code-here;"}"}/egi # (don't use delimeters like s{}{}ige, that way you'd # loose the construct's intended capriciousness :> )


      So counting parens on the cheap w/o full parsing (maybe -> Deparse, B, ...) is a problem.

      I had resolved this problem by running all code through perltidy -dac first. An additional problem is whether braces might occur with strings. This can be dealt with by reducing all strings to null before running through perltidy. The only other possibility I can think of would be braces appearing with regular expressions, but thus far, I hadn't run into enough occurrences to warrant figuring out a solution yet.

      Thanks everyone for your responses. I'll look more at the CPAN references mentioned earlier later tonight.

Re: finding subroutine dependencies?
by Khen1950fx (Canon) on Oct 02, 2009 at 09:52 UTC
    For what you want to do, I think that you should try countperl.

    countperl /path/to/

    Seems too easy, doesn't it:-).

      While countperl has some interesting metrics, it doesn't appear to provide the information I'm needing.

      I'm looking for dependency information (what function calls what...) such that we can ascertain that changes in function A may have ramifications on B, C, D, etc.

      I do appreciate the reference to PPI. Maybe, just maybe this can help coupled with doing some profiling. I'm simply going to have to look into this further.

      Thanks, all!

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://798738]
Approved by ikegami
Front-paged by moritz
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (6)
As of 2018-06-21 18:37 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (118 votes). Check out past polls.