File Coverage

blib/lib/Devel/Caller.pm
Criterion Covered Total %
statement 89 95 93.6
branch 43 66 65.1
condition 11 16 68.7
subroutine 12 12 100.0
pod 4 5 80.0
total 159 194 81.9


line stmt bran cond sub pod time code
1 1     1   57669 use strict;
  1         2  
  1         154  
2             package Devel::Caller;
3 1     1   6 use warnings;
  1         2  
  1         35  
4 1     1   6 use B qw( peekop );
  1         6  
  1         88  
5 1     1   9228 use PadWalker ();
  1         6486  
  1         29  
6 1     1   13 use XSLoader;
  1         2  
  1         24  
7 1     1   6 use base qw( Exporter );
  1         1  
  1         122  
8 1     1   24 use 5.008;
  1         3  
  1         1516  
9              
10             our $VERSION = '2.06';
11             XSLoader::load __PACKAGE__, $VERSION;
12              
13             our @EXPORT_OK = qw( caller_cv caller_args caller_vars called_with called_as_method );
14              
15             sub caller_cv {
16 52     52 1 661 my $level = shift;
17 52         122 my $cx = PadWalker::_upcontext($level + 1);
18 52 100       163 return unless $cx;
19 8         30 return _context_cv($cx);
20             }
21              
22             our $DEBUG = 0;
23              
24             # scan forward through the ops noting the pushmark or a padrange ops.
25             # These indicate the start of a subroutine call. We're looking for the most
26             # recent one before the subroutine invocation (the entersub).
27             sub scan_forward {
28 47     47 0 49 my $op = shift;
29 47 50       357 die "was expecting a pushmark or a padrange, not a " . $op->name
30             if ($op->name !~ /^(?:pushmark|padrange)$/);
31              
32 47         59 my @stack;
33 47   66     363 for (; $op && $op->name ne 'entersub'; $op = $op->next) {
34 289 50       550 print "SCAN ", peekop($op), "\n" if $DEBUG;
35 289 100 100     3430 if ($op->name eq "pushmark" or $op->name eq "padrange") {
36 97 50       183 print " PUSH\n" if $DEBUG;
37 97         947 push @stack, $op;
38             }
39 0         0 elsif (0) { # op consumes a mark
40             print " POP\n" if $DEBUG;
41             pop @stack;
42             }
43             }
44 47         135 return pop @stack;
45             }
46              
47             *caller_vars = \&called_with;
48             sub called_with {
49 47     47 1 44849 my $level = shift;
50 47         67 my $want_names = shift;
51              
52 47         288 my $op = _context_op( PadWalker::_upcontext( $level + 1 ));
53 47         111 my $cv = caller_cv( $level + 2 );
54 47 100       221 my $pad = $cv ? B::svref_2object( $cv )->PADLIST : B::comppadlist;
55 47         167 my $padn = $pad->ARRAYelt( 0 );
56 47         128 my $padv = $pad->ARRAYelt( 1 );
57              
58 47 50       115 print "Context OP: ", peekop($op), "\n" if $DEBUG;
59 47         80 $op = scan_forward( $op );
60 47 50       101 print "Scanned forward to ", peekop($op), "\n" if $DEBUG;
61              
62 47         50 my @return;
63             my $prev;
64              
65             # We're scanning through looking for ops which are pushing
66             # variables onto the stack (/pad(sv|av|hv)/ push from the pad,
67             # /gvsv|rv2([ahg]v/ are from globs.
68 47   66     297 for (; $op && $op->name ne 'entersub'; ($prev = $op) && ($op = $op->next)) {
      50        
69 216 50       417 printf "Loop: %s %s targ: %d\n", peekop($op), $op->name, $op->targ if $DEBUG;
70              
71 216 100       801 if ($op->name eq "padrange") {
72             # A padrange is a 5.17 optimisation that uses a single op to
73             # load multiple pad variables onto the stack. The old ops
74             # are preserved and are reachable as the padrange's sibling
75             # so that B::Deparse can pessimise it back to that state.
76             #
77             # http://perl5.git.perl.org/perl.git/commitdiff/0fe870f5
78             # http://perl5.git.perl.org/perl.git/commitdiff/a7fd8ef6
79             #
80             # We could use the B::Deparse method, but it's probably simpler if
81             # we just reassign $op.
82 24 50       52 print "padrange, diverting down ", $prev->sibling, "\n" if $DEBUG;
83 24         91 $op = $op->sibling;
84             }
85              
86 216 100       3190 if ($op->name =~ "pad(sv|av|hv)") {
    100          
    100          
87 50 100       597 if ($op->next->next->name eq "sassign") {
88 6 50       19 print "sassign in two ops, this is the target skipping\n" if $DEBUG;
89 6         64 next;
90             }
91              
92 44 50       118 print "Copying from pad\n" if $DEBUG;
93 44 100       81 if ($want_names) {
94 41         302 push @return, $padn->ARRAYelt( $op->targ )->PVX;
95             }
96             else {
97 3         39 push @return, $padv->ARRAYelt( $op->targ )->object_2svref;
98             }
99 44         493 next;
100             }
101             elsif ($op->name =~ /gvsv|rv2(av|hv|gv)/) {
102 23 50       171 if ($op->next->next->name eq "sassign") {
103 0 0       0 print "sassign in two ops, this is the target, skipping\n" if $DEBUG;
104 0         0 next;
105             }
106              
107 23 100       106 my $consider = ($op->name eq "gvsv") ? $op : $prev;
108 23         888 my $gv;
109              
110 23 50       49 if (ref $consider eq 'B::PADOP') {
111 0 0       0 print "GV is really a padgv\n" if $DEBUG;
112 0         0 $gv = $padv->ARRAYelt( $consider->padix );
113 0 0       0 print "NEW GV $gv\n" if $DEBUG;
114             }
115             else {
116 23         84 $gv = $consider->gv;
117             }
118              
119 23 50       50 print "consider: $consider ", $consider->name, " gv $gv\n"
120             if $DEBUG;
121              
122 23 100       37 if ($want_names) {
123 20         70 my %sigils = (
124             "gvsv" => '$',
125             "rv2av" => '@',
126             "rv2hv" => '%',
127             "rv2gv" => '*',
128             );
129              
130 20         244 push @return, $sigils{ $op->name } . $gv->STASH->NAME . "::" . $gv->SAFENAME;
131             }
132             else {
133 3         20 my %slots = (
134             "gvsv" => 'SCALAR',
135             "rv2av" => 'ARRAY',
136             "rv2hv" => 'HASH',
137             "rv2gv" => 'GLOB',
138             );
139 3         4 push @return, *{ $gv->object_2svref }{ $slots{ $op->name} };
  3         34  
140             }
141              
142 23         262 next;
143             }
144             elsif ($op->name eq "const") {
145 6 100       56 if ($op->next->next->name eq "sassign") {
146 3 50       8 print "sassign in two ops, this is the target, skipping\n" if $DEBUG;
147 3         36 next;
148             }
149              
150 3 50       9 push @return, $want_names ? undef : $op->sv;
151 3         31 next;
152             }
153             }
154 47         313 return @return;
155             }
156              
157              
158             sub called_as_method {
159 3   50 3 1 1593 my $level = shift || 0;
160 3         18 my $op = _context_op( PadWalker::_upcontext( $level + 1 ));
161              
162 3 50       10 print "called_as_method: $op\n" if $DEBUG;
163 3 50       18 die "was expecting a pushmark or pad, not a ". $op->name
164             unless $op->name eq "pushmark";
165 3   66     183 while (($op = $op->next) && ($op->name ne "entersub")) {
166 6 50       18 print "method: ", $op->name, "\n" if $DEBUG;
167 6 100       61 return 1 if $op->name =~ /^method(?:_named)?$/;
168             }
169 1         7 return;
170             }
171              
172              
173             sub caller_args {
174 1     1 1 446 my $level = shift;
175             package DB;
176 1         8 () = caller( $level + 1 );
177             return @DB::args
178 1         7 }
179              
180             1;
181             __END__
182              
183              
184             =head1 NAME
185              
186             Devel::Caller - meatier versions of C<caller>
187              
188             =head1 SYNOPSIS
189              
190             use Devel::Caller qw(caller_cv);
191             $foo = sub { print "huzzah\n" if $foo == caller_cv(0) };
192             $foo->(); # prints huzzah
193              
194             use Devel::Caller qw(called_with);
195             sub foo { print called_with(0,1); }
196             foo( my @foo ); # should print '@foo'
197              
198             =head1 DESCRIPTION
199              
200             =over
201              
202             =item caller_cv($level)
203              
204             C<caller_cv> gives you the coderef of the subroutine being invoked at
205             the call frame indicated by the value of $level
206              
207             =item caller_args($level)
208              
209             Returns the arguments passed into the caller at level $level
210              
211             =item caller_vars( $level, $names )
212             =item called_with($level, $names)
213              
214             C<called_with> returns a list of references to the original arguments
215             to the subroutine at $level. if $names is true, the names of the
216             variables will be returned instead
217              
218             constants are returned as C<undef> in both cases
219              
220             =item called_as_method($level)
221              
222             C<called_as_method> returns true if the subroutine at $level was
223             called as a method.
224              
225             =back
226              
227             =head1 BUGS
228              
229             All of these routines are susceptible to the same limitations as
230             C<caller> as described in L<perlfunc/caller>
231              
232             The deparsing of the optree perfomed by called_with is fairly simple-minded
233             and so a bit flaky.
234              
235             =over
236              
237             =item
238              
239             As a version 2.0 of Devel::Caller we no longer maintain compatibility with
240             versions of perl earlier than 5.8.2. Older versions continue to be available
241             from CPAN and backpan.
242              
243             =back
244              
245             =head1 SEE ALSO
246              
247             L<perlfunc/caller>, L<PadWalker>, L<Devel::Peek>
248              
249             =head1 AUTHOR
250              
251             Richard Clamp <richardc@unixbeard.net> with close reference to
252             PadWalker by Robin Houston
253              
254             =head1 COPYRIGHT
255              
256             Copyright (c) 2002, 2003, 2006, 2007, 2008, 2010, 2013 Richard Clamp.
257             All Rights Reserved.
258              
259             This module is free software. It may be used, redistributed and/or
260             modified under the same terms as Perl itself.
261              
262             =cut