File Coverage

blib/lib/CallGraph.pm
Criterion Covered Total %
statement 49 63 77.7
branch 14 24 58.3
condition 1 3 33.3
subroutine 11 13 84.6
pod 9 9 100.0
total 84 112 75.0


line stmt bran cond sub pod time code
1             package CallGraph;
2              
3             $VERSION = '0.55';
4              
5 1     1   6 use strict;
  1         2  
  1         30  
6 1     1   5 use warnings;
  1         1  
  1         31  
7              
8 1     1   6 use Carp;
  1         2  
  1         102  
9 1     1   568 use CallGraph::Node;
  1         3  
  1         821  
10              
11             =head1 NAME
12              
13             CallGraph - create, navigate, and dump the call graph for a program
14              
15             =head1 SYNOPSIS
16              
17             # note: you need a subclass for the language you are using
18             use CallGraph::Lang::Fortran;
19             my $graph = CallGraph::Lang::Fortran->new(files => [glob('*.f')]);
20             print $graph->dump;
21              
22             # navigate the call graph...
23             my $root = $graph->root; # returns a CallGraph::Node object
24             my (@calls) = $root->calls;
25            
26             # if you want to create your own language subclass:
27             package CallGraph::Lang::MyLanguage;
28             use base 'CallGraph';
29             # must define the parse method
30             sub parse {
31             my ($self, $fh) = @_;
32             while (<$fh>) {
33             # add subroutines and calls by using
34             # $self->new_sub and $self->add_call
35             }
36             }
37              
38             =head1 DESCRIPTION
39              
40             This module creates a "call graph" for a program. Please note that you need
41             another module to actually parse your program and add the calls by using
42             the CallGraph methods. The current distribution includes a module for parsing
43             Fortran 77, L.
44              
45             =head1 METHODS
46              
47             =over
48              
49             =item CallGraph->new(option => value, ...)
50              
51             Create a new CallGraph object. The following options are available:
52              
53             =over
54              
55             =item files => $file1
56              
57             =item files => [$file1, $file2...]
58              
59             Reads and parses the given files. $file1, etc. can be either filenames or
60             filehandles.
61              
62             =item lines => \@lines
63              
64             Parses the array reference, which is expected to be an array of program lines.
65             You can use this if you have already slurped your program into an array.
66              
67             =item dump_options => {option => value, ...}
68              
69             Pass the options to L when dumping the call graph.
70              
71             =back
72              
73             =cut
74              
75             sub new {
76 2     2 1 1702 my ($class, %opts) = @_;
77 2   33     20 my $self = bless {
78             dump_options => {},
79             }, ref $class || $class;
80 2 50       12 if (ref $opts{files}) {
    50          
81 0         0 $self->add_files(@{$opts{files}})
  0         0  
82             } elsif ($opts{files}) {
83 2         14 $self->add_files($opts{files});
84             }
85 2 50       8 if (ref $opts{lines}) {
86 0         0 $self->add_lines($opts{lines});
87             }
88 2 50       5 if (ref $opts{dump_options}) {
89 0         0 $self->{dump_options} = $opts{dump_options};
90             }
91 2         7 $self;
92             }
93              
94             =item $graph->add_files($file1, $file2, ...)
95              
96             Reads and parses the given files. $file1, etc. can be either filenames or
97             filehandles.
98              
99             =cut
100              
101             sub add_files {
102 2     2 1 5 my ($self, @fnames) = @_;
103 2         3 for my $fname (@fnames) {
104 2         4 my $fh;
105 2 50       5 if (ref $fname) {
106 0         0 $fh = $fname;
107             } else {
108 2 50       94 open $fh, "<", $fname or croak "couldn't open $fname: $!";
109             }
110 2         11 $self->parse($fh);
111             }
112             }
113              
114             =item $graph->add_lines(\@lines)
115              
116             Parses the array reference, which is expected to be an array of program lines.
117             You can use this if you have already slurped your program into an array.
118              
119             =cut
120              
121             sub add_lines {
122 0     0 1 0 my ($self, $lines) = @_;
123 0         0 my $f = join "", @$lines;
124 0 0       0 open my $fh, "<", \$f or croak "couldn't open: $!";
125 0         0 $self->parse($fh);
126             }
127              
128             =item $graph->add_call($from, $to)
129              
130             Add a call (a link) to the graph. $from and $to must be subroutine I.
131             The nodes are created automatically (by calling new_sub) if needed, with
132             type 'external' (meaning that they haven't been defined explicitly yet).
133              
134             =cut
135              
136             sub add_call {
137 16     16 1 32 my ($self, $from, $to) = @_;
138 16         31 my $sub_to = $self->new_sub(name => $to);
139 16         35 my $sub_from = $self->new_sub(name => $from);
140 16         41 $sub_from->add_call($sub_to);
141             }
142              
143             =item my $sub = $graph->get_sub($sub_name)
144              
145             Returns the L object for the subroutine named $sub_name.
146             Note that there can be only one subroutine with a given name in a call
147             graph.
148              
149             =cut
150              
151             sub get_sub {
152 45     45 1 51 my ($self, $name) = @_;
153 45         120 $self->{'index'}{$name};
154             }
155              
156             =item my @subs = $graph->subs
157              
158             Returns the list of all the subroutines contained in the graph, as
159             L objects.
160              
161             =cut
162              
163             sub subs {
164 0     0 1 0 my ($self) = @_;
165 0         0 @{$self->{'index'}}{sort keys %{$self->{'index'}}};
  0         0  
  0         0  
166             }
167              
168             =item my $root = $graph->root;
169              
170             =item $graph->root($new_root);
171              
172             Get or set the root of the call graph. $root is a CallGraph::Node object;
173             $new_root can be either an object or a subroutine name.
174              
175             =cut
176              
177             sub root {
178 8     8 1 12 my ($self, $root) = @_;
179 8 100       18 if ($root) {
180 2 50       8 ($self->{root}) = ref $root ? $root : $self->get_sub($root);
181 2         5 $self;
182             } else {
183 6         12 $self->{root};
184             }
185             }
186              
187             =item my $sub = $graph->new_sub(name => $sub_name, [type => $type])
188              
189             Create and add a new subroutine (a L object) to the graph.
190             There can only be one subroutine with a given name; if new_sub is called
191             with a name that has been used before, it returnes the previously existing
192             object (note that the type of an existing object can be changed by this call).
193              
194             If the type is not specified when a subroutine is first created, it defaults to
195             'external'.
196              
197             =cut
198              
199             sub new_sub {
200 45     45 1 97 my ($self, %opts) = @_;
201 45         53 my $name = $opts{name};
202 45         53 my $sub;
203 45 100       83 if ($sub = $self->get_sub($name)) {
204 30 100       65 if ($opts{type}) { # change type?
205 11         26 $sub->type($opts{type});
206             }
207             } else {
208 15         53 $sub = CallGraph::Node->new(type => 'external', %opts);
209 15         39 $self->{'index'}{$name} = $sub;
210             }
211 45         100 $sub;
212             }
213              
214             =item my $dump = $graph->dump(option => value, ...)
215              
216             Dump the call graph into a string representation. The options are passed
217             to L. The root of the graph must be defined for dump to work.
218              
219             =cut
220              
221             sub dump {
222 6     6 1 4181 my ($self, %opts) = @_;
223 6 50       22 unless ($self->{root}) { croak ref($self) . "->dump: undefined root" }
  0         0  
224 6         14 $self->root->dump(%{$self->{dump_options}}, %opts);
  6         25  
225             }
226              
227             1;
228              
229             =back
230              
231             =head1 VERSION
232              
233             0.55
234              
235             =head1 SEE ALSO
236              
237             L, L, L
238              
239             =head1 AUTHOR
240              
241             Ivan Tubert Eitub@cpan.orgE
242              
243             =head1 COPYRIGHT
244              
245             Copyright (c) 2004 Ivan Tubert. All rights reserved. This program is free
246             software; you can redistribute it and/or modify it under the same terms as
247             Perl itself.
248              
249             =cut
250              
251