Development to pre-alpha4
[p5sagit/p5-mst-13.2.git] / B / Xref.pm
CommitLineData
79ee8297 1package B::Xref;
2
3=head1 NAME
4
5B::Xref - Generates cross reference reports for Perl programs
6
7=head1 SYNOPSIS
8
9perl -MO=Xref[,OPTIONS] foo.pl
10
11=head1 DESCRIPTION
12
13The B::Xref module is used to generate a cross reference listing of all
14definitions and uses of variables, subroutines and formats in a Perl program.
15It is implemented as a backend for the Perl compiler.
16
17The report generated is in the following format:
18
19 File filename1
20 Subroutine subname1
21 Package package1
22 object1 C<line numbers>
23 object2 C<line numbers>
24 ...
25 Package package2
26 ...
27
28Each B<File> section reports on a single file. Each B<Subroutine> section
29reports on a single subroutine apart from the special cases
30"(definitions)" and "(main)". These report, respectively, on subroutine
31definitions found by the initial symbol table walk and on the main part of
32the program or module external to all subroutines.
33
34The report is then grouped by the B<Package> of each variable,
35subroutine or format with the special case "(lexicals)" meaning
36lexical variables. Each B<object> name (implicitly qualified by its
37containing B<Package>) includes its type character(s) at the beginning
38where possible. Lexical variables are easier to track and even
39included dereferencing information where possible.
40
41The C<line numbers> are a comma separated list of line numbers (some
42preceded by code letters) where that object is used in some way.
43Simple uses aren't preceded by a code letter. Introductions (such as
44where a lexical is first defined with C<my>) are indicated with the
45letter "i". Subroutine and method calls are indicated by the character
46"&". Subroutine definitions are indicated by "s" and format
47definitions by "f".
48
49=head1 OPTIONS
50
51Option words are separated by commas (not whitespace) and follow the
52usual conventions of compiler backend options.
53
54=over 8
55
56=item C<-oFILENAME>
57
58Directs output to C<FILENAME> instead of standard output.
59
60=item C<-r>
61
62Raw output. Instead of producing a human-readable report, outputs a line
63in machine-readable form for each definition/use of a variable/sub/format.
64
65=item C<-D[tO]>
66
67(Internal) debug options, probably only useful if C<-r> included.
68The C<t> option prints the object on the top of the stack as it's
69being tracked. The C<O> option prints each operator as it's being
70processed in the execution order of the program.
71
72=back
73
74=head1 BUGS
75
76Non-lexical variables are quite difficult to track through a program.
77Sometimes the type of a non-lexical variable's use is impossible to
78determine. Introductions of non-lexical non-scalars don't seem to be
79reported properly.
80
81=head1 AUTHOR
82
83Malcolm Beattie, mbeattie@sable.ox.ac.uk.
84
85=cut
86
87use strict;
f64a6365 88use B qw(peekop class comppadlist main_start svref_2object walksymtable);
79ee8297 89
90# Constants (should probably be elsewhere)
91sub OPpLVAL_INTRO () { 128 }
92sub SVf_POK () { 0x40000 }
93
94sub UNKNOWN { ["?", "?", "?"] }
95
96my @pad; # lexicals in current pad
97 # as ["(lexical)", type, name]
98my %done; # keyed by $$op: set when each $op is done
99my $top = UNKNOWN; # shadows top element of stack as
100 # [pack, type, name] (pack can be "(lexical)")
101my $file; # shadows current filename
102my $line; # shadows current line number
103my $subname; # shadows current sub name
104my %table; # Multi-level hash to record all uses etc.
105my @todo = (); # List of CVs that need processing
106
107my %code = (intro => "i", used => "",
108 subdef => "s", subused => "&",
109 formdef => "f", meth => "->");
110
111
112# Options
113my ($debug_op, $debug_top, $nodefs, $raw);
114
115sub process {
116 my ($var, $event) = @_;
117 my ($pack, $type, $name) = @$var;
118 if ($type eq "*") {
119 if ($event eq "used") {
120 return;
121 } elsif ($event eq "subused") {
122 $type = "&";
123 }
124 }
125 $type =~ s/(.)\*$/$1/g;
126 if ($raw) {
127 printf "%-16s %-12s %5d %-12s %4s %-16s %s\n",
128 $file, $subname, $line, $pack, $type, $name, $event;
129 } else {
130 # Wheee
131 push(@{$table{$file}->{$subname}->{$pack}->{$type.$name}->{$event}},
132 $line);
133 }
134}
135
136sub load_pad {
137 my $padlist = shift;
138 my ($namelistav, @namelist, $ix);
139 @pad = ();
140 return if class($padlist) eq "SPECIAL";
141 ($namelistav) = $padlist->ARRAY;
142 @namelist = $namelistav->ARRAY;
143 for ($ix = 1; $ix < @namelist; $ix++) {
144 my $namesv = $namelist[$ix];
145 next if class($namesv) eq "SPECIAL";
146 my ($type, $name) = $namesv->PV =~ /^(.)(.*)$/;
147 $pad[$ix] = ["(lexical)", $type, $name];
148 }
149}
150
151sub xref {
152 my $start = shift;
153 my $op;
154 for ($op = $start; $$op; $op = $op->next) {
155 last if $done{$$op}++;
156 warn sprintf("top = [%s, %s, %s]\n", @$top) if $debug_top;
157 warn peekop($op), "\n" if $debug_op;
158 my $ppname = $op->ppaddr;
159 if ($ppname =~ /^pp_(or|and|mapwhile|grepwhile)$/) {
160 xref($op->other);
161 } elsif ($ppname eq "pp_match" || $ppname eq "pp_subst") {
162 xref($op->pmreplstart);
163 } elsif ($ppname eq "pp_substcont") {
164 xref($op->other->pmreplstart);
165 $op = $op->other;
166 redo;
167 } elsif ($ppname eq "pp_cond_expr") {
168 # pp_cond_expr never returns op_next
169 xref($op->true);
170 $op = $op->false;
171 redo;
172 } elsif ($ppname eq "pp_enterloop") {
173 xref($op->redoop);
174 xref($op->nextop);
175 xref($op->lastop);
176 } elsif ($ppname eq "pp_subst") {
177 xref($op->pmreplstart);
178 } else {
179 no strict 'refs';
180 &$ppname($op) if defined(&$ppname);
181 }
182 }
183}
184
185sub xref_cv {
186 my $cv = shift;
187 my $pack = $cv->GV->STASH->NAME;
188 $subname = ($pack eq "main" ? "" : "$pack\::") . $cv->GV->NAME;
189 load_pad($cv->PADLIST);
190 xref($cv->START);
191 $subname = "(main)";
192}
193
194sub xref_object {
195 my $cvref = shift;
196 xref_cv(svref_2object($cvref));
197}
198
199sub xref_main {
200 $subname = "(main)";
201 load_pad(comppadlist);
202 xref(main_start);
203 while (@todo) {
204 xref_cv(shift @todo);
205 }
206}
207
208sub pp_nextstate {
209 my $op = shift;
210 $file = $op->filegv->SV->PV;
211 $line = $op->line;
212 $top = UNKNOWN;
213}
214
215sub pp_padsv {
216 my $op = shift;
217 $top = $pad[$op->targ];
218 process($top, $op->private & OPpLVAL_INTRO ? "intro" : "used");
219}
220
221sub pp_padav { pp_padsv(@_) }
222sub pp_padhv { pp_padsv(@_) }
223
224sub deref {
225 my ($var, $as) = @_;
226 $var->[1] = $as . $var->[1];
227 process($var, "used");
228}
229
230sub pp_rv2cv { deref($top, "&"); }
231sub pp_rv2hv { deref($top, "%"); }
232sub pp_rv2sv { deref($top, "\$"); }
233sub pp_rv2av { deref($top, "\@"); }
234sub pp_rv2gv { deref($top, "*"); }
235
236sub pp_gvsv {
237 my $op = shift;
238 my $gv = $op->gv;
239 $top = [$gv->STASH->NAME, '$', $gv->NAME];
240 process($top, $op->private & OPpLVAL_INTRO ? "intro" : "used");
241}
242
243sub pp_gv {
244 my $op = shift;
245 my $gv = $op->gv;
246 $top = [$gv->STASH->NAME, "*", $gv->NAME];
247 process($top, $op->private & OPpLVAL_INTRO ? "intro" : "used");
248}
249
250sub pp_const {
251 my $op = shift;
252 my $sv = $op->sv;
253 $top = ["?", "", $sv->FLAGS & SVf_POK ? $sv->PV : "?"];
254}
255
256sub pp_method {
257 my $op = shift;
258 $top = ["(method)", "->".$top->[1], $top->[2]];
259}
260
261sub pp_entersub {
262 my $op = shift;
263 if ($top->[1] eq "m") {
264 process($top, "meth");
265 } else {
266 process($top, "subused");
267 }
268 $top = UNKNOWN;
269}
270
271#
272# Stuff for cross referencing definitions of variables and subs
273#
274
275sub B::GV::xref {
276 my $gv = shift;
277 my $cv = $gv->CV;
f64a6365 278 if ($$cv) {
79ee8297 279 #return if $done{$$cv}++;
280 $file = $gv->FILEGV->SV->PV;
281 $line = $gv->LINE;
282 process([$gv->STASH->NAME, "&", $gv->NAME], "subdef");
283 push(@todo, $cv);
284 }
285 my $form = $gv->FORM;
f64a6365 286 if ($$form) {
79ee8297 287 return if $done{$$form}++;
288 $file = $gv->FILEGV->SV->PV;
289 $line = $gv->LINE;
290 process([$gv->STASH->NAME, "", $gv->NAME], "formdef");
291 }
292}
293
294sub xref_definitions {
295 my ($pack, %exclude);
296 return if $nodefs;
297 $subname = "(definitions)";
298 foreach $pack (qw(B O AutoLoader DynaLoader Config DB VMS
299 strict vars FileHandle Exporter Carp)) {
300 $exclude{$pack."::"} = 1;
301 }
302 no strict qw(vars refs);
303 walksymtable(\%{"main::"}, "xref", sub { !defined($exclude{$_[0]}) });
304}
305
306sub output {
307 return if $raw;
308 my ($file, $subname, $pack, $name, $ev, $perfile, $persubname,
309 $perpack, $pername, $perev);
310 foreach $file (sort(keys(%table))) {
311 $perfile = $table{$file};
312 print "File $file\n";
313 foreach $subname (sort(keys(%$perfile))) {
314 $persubname = $perfile->{$subname};
315 print " Subroutine $subname\n";
316 foreach $pack (sort(keys(%$persubname))) {
317 $perpack = $persubname->{$pack};
318 print " Package $pack\n";
319 foreach $name (sort(keys(%$perpack))) {
320 $pername = $perpack->{$name};
321 my @lines;
322 foreach $ev (qw(intro formdef subdef meth subused used)) {
323 $perev = $pername->{$ev};
324 if (defined($perev) && @$perev) {
325 my $code = $code{$ev};
326 push(@lines, map("$code$_", @$perev));
327 }
328 }
329 printf " %-16s %s\n", $name, join(", ", @lines);
330 }
331 }
332 }
333 }
334}
335
336sub compile {
337 my @options = @_;
338 my ($option, $opt, $arg);
339 OPTION:
340 while ($option = shift @options) {
341 if ($option =~ /^-(.)(.*)/) {
342 $opt = $1;
343 $arg = $2;
344 } else {
345 unshift @options, $option;
346 last OPTION;
347 }
348 if ($opt eq "-" && $arg eq "-") {
349 shift @options;
350 last OPTION;
351 } elsif ($opt eq "o") {
352 $arg ||= shift @options;
353 open(STDOUT, ">$arg") or return "$arg: $!\n";
354 } elsif ($opt eq "d") {
355 $nodefs = 1;
356 } elsif ($opt eq "r") {
357 $raw = 1;
358 } elsif ($opt eq "D") {
359 $arg ||= shift @options;
360 foreach $arg (split(//, $arg)) {
361 if ($arg eq "o") {
362 B->debug(1);
363 } elsif ($arg eq "O") {
364 $debug_op = 1;
365 } elsif ($arg eq "t") {
366 $debug_top = 1;
367 }
368 }
369 }
370 }
371 if (@options) {
372 return sub {
373 my $objname;
374 xref_definitions();
375 foreach $objname (@options) {
376 $objname = "main::$objname" unless $objname =~ /::/;
377 eval "xref_object(\\&$objname)";
378 die "xref_object(\\&$objname) failed: $@" if $@;
379 }
380 output();
381 }
382 } else {
383 return sub {
384 xref_definitions();
385 xref_main();
386 output();
387 }
388 }
389}
390
3911;