Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/PPI/Node.pm |
Statements | Executed 3539983 statements in 4.21s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
3668 | 6 | 4 | 3.37s | 6.01s | find | PPI::Node::
1160 | 2 | 2 | 821ms | 1.40s | find_first | PPI::Node::
32942 | 4 | 3 | 642ms | 931ms | tokens (recurses: max depth 15, inclusive time 3.16s) | PPI::Node::
16471 | 2 | 2 | 601ms | 999ms | DESTROY (recurses: max depth 1, inclusive time 81.6ms) | PPI::Node::
29896 | 21 | 8 | 265ms | 311ms | schild | PPI::Node::
9627 | 2 | 1 | 150ms | 178ms | schildren | PPI::Node::
4828 | 2 | 1 | 140ms | 160ms | _wanted | PPI::Node::
9610 | 5 | 2 | 61.5ms | 127ms | location | PPI::Node::
2076 | 3 | 3 | 56.3ms | 82.0ms | content (recurses: max depth 5, inclusive time 30.8ms) | PPI::Node::
2404 | 3 | 3 | 4.84ms | 4.84ms | children | PPI::Node::
144 | 1 | 1 | 842µs | 842µs | new | PPI::Node::
144 | 1 | 1 | 361µs | 361µs | first_element | PPI::Node::
1 | 1 | 1 | 12µs | 12µs | BEGIN@59 | PPI::Node::
1 | 1 | 1 | 11µs | 24µs | BEGIN@51 | PPI::Node::
1 | 1 | 1 | 7µs | 48µs | BEGIN@58 | PPI::Node::
1 | 1 | 1 | 7µs | 28µs | BEGIN@53 | PPI::Node::
1 | 1 | 1 | 7µs | 42µs | BEGIN@55 | PPI::Node::
2 | 1 | 1 | 5µs | 5µs | child | PPI::Node::
1 | 1 | 1 | 3µs | 3µs | BEGIN@56 | PPI::Node::
1 | 1 | 1 | 3µs | 3µs | BEGIN@52 | PPI::Node::
1 | 1 | 1 | 3µs | 3µs | BEGIN@54 | PPI::Node::
0 | 0 | 0 | 0s | 0s | __ANON__[:508] | PPI::Node::
0 | 0 | 0 | 0s | 0s | __ANON__[:715] | PPI::Node::
0 | 0 | 0 | 0s | 0s | __ANON__[:724] | PPI::Node::
0 | 0 | 0 | 0s | 0s | __ANON__[:740] | PPI::Node::
0 | 0 | 0 | 0s | 0s | __ANON__[:756] | PPI::Node::
0 | 0 | 0 | 0s | 0s | __add_element | PPI::Node::
0 | 0 | 0 | 0s | 0s | __insert_after_child | PPI::Node::
0 | 0 | 0 | 0s | 0s | __insert_before_child | PPI::Node::
0 | 0 | 0 | 0s | 0s | __link_children | PPI::Node::
0 | 0 | 0 | 0s | 0s | __position | PPI::Node::
0 | 0 | 0 | 0s | 0s | __replace_child | PPI::Node::
0 | 0 | 0 | 0s | 0s | add_element | PPI::Node::
0 | 0 | 0 | 0s | 0s | clone | PPI::Node::
0 | 0 | 0 | 0s | 0s | contains | PPI::Node::
0 | 0 | 0 | 0s | 0s | elements | PPI::Node::
0 | 0 | 0 | 0s | 0s | find_any | PPI::Node::
0 | 0 | 0 | 0s | 0s | last_element | PPI::Node::
0 | 0 | 0 | 0s | 0s | prune | PPI::Node::
0 | 0 | 0 | 0s | 0s | remove_child | PPI::Node::
0 | 0 | 0 | 0s | 0s | scope | PPI::Node::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package PPI::Node; | ||||
2 | |||||
3 | =pod | ||||
4 | |||||
5 | =head1 NAME | ||||
6 | |||||
7 | PPI::Node - Abstract PPI Node class, an Element that can contain other Elements | ||||
8 | |||||
9 | =head1 INHERITANCE | ||||
10 | |||||
11 | PPI::Node | ||||
12 | isa PPI::Element | ||||
13 | |||||
14 | =head1 SYNOPSIS | ||||
15 | |||||
16 | # Create a typical node (a Document in this case) | ||||
17 | my $Node = PPI::Document->new; | ||||
18 | |||||
19 | # Add an element to the node( in this case, a token ) | ||||
20 | my $Token = PPI::Token::Word->new('my'); | ||||
21 | $Node->add_element( $Token ); | ||||
22 | |||||
23 | # Get the elements for the Node | ||||
24 | my @elements = $Node->children; | ||||
25 | |||||
26 | # Find all the barewords within a Node | ||||
27 | my $barewords = $Node->find( 'PPI::Token::Word' ); | ||||
28 | |||||
29 | # Find by more complex criteria | ||||
30 | my $my_tokens = $Node->find( sub { $_[1]->content eq 'my' } ); | ||||
31 | |||||
32 | # Remove all the whitespace | ||||
33 | $Node->prune( 'PPI::Token::Whitespace' ); | ||||
34 | |||||
35 | # Remove by more complex criteria | ||||
36 | $Node->prune( sub { $_[1]->content eq 'my' } ); | ||||
37 | |||||
38 | =head1 DESCRIPTION | ||||
39 | |||||
40 | The C<PPI::Node> class provides an abstract base class for the Element | ||||
41 | classes that are able to contain other elements L<PPI::Document>, | ||||
42 | L<PPI::Statement>, and L<PPI::Structure>. | ||||
43 | |||||
44 | As well as those listed below, all of the methods that apply to | ||||
45 | L<PPI::Element> objects also apply to C<PPI::Node> objects. | ||||
46 | |||||
47 | =head1 METHODS | ||||
48 | |||||
49 | =cut | ||||
50 | |||||
51 | 2 | 19µs | 2 | 36µs | # spent 24µs (11+12) within PPI::Node::BEGIN@51 which was called:
# once (11µs+12µs) by PPI::Element::BEGIN@30 at line 51 # spent 24µs making 1 call to PPI::Node::BEGIN@51
# spent 12µs making 1 call to strict::import |
52 | 2 | 17µs | 1 | 3µs | # spent 3µs within PPI::Node::BEGIN@52 which was called:
# once (3µs+0s) by PPI::Element::BEGIN@30 at line 52 # spent 3µs making 1 call to PPI::Node::BEGIN@52 |
53 | 2 | 23µs | 2 | 49µs | # spent 28µs (7+21) within PPI::Node::BEGIN@53 which was called:
# once (7µs+21µs) by PPI::Element::BEGIN@30 at line 53 # spent 28µs making 1 call to PPI::Node::BEGIN@53
# spent 21µs making 1 call to Exporter::import |
54 | 2 | 18µs | 1 | 3µs | # spent 3µs within PPI::Node::BEGIN@54 which was called:
# once (3µs+0s) by PPI::Element::BEGIN@30 at line 54 # spent 3µs making 1 call to PPI::Node::BEGIN@54 |
55 | 2 | 19µs | 2 | 78µs | # spent 42µs (7+35) within PPI::Node::BEGIN@55 which was called:
# once (7µs+35µs) by PPI::Element::BEGIN@30 at line 55 # spent 42µs making 1 call to PPI::Node::BEGIN@55
# spent 36µs making 1 call to Exporter::import |
56 | 2 | 19µs | 1 | 3µs | # spent 3µs within PPI::Node::BEGIN@56 which was called:
# once (3µs+0s) by PPI::Element::BEGIN@30 at line 56 # spent 3µs making 1 call to PPI::Node::BEGIN@56 |
57 | |||||
58 | 2 | 40µs | 2 | 90µs | # spent 48µs (7+41) within PPI::Node::BEGIN@58 which was called:
# once (7µs+41µs) by PPI::Element::BEGIN@30 at line 58 # spent 48µs making 1 call to PPI::Node::BEGIN@58
# spent 41µs making 1 call to vars::import |
59 | # spent 12µs within PPI::Node::BEGIN@59 which was called:
# once (12µs+0s) by PPI::Element::BEGIN@30 at line 63 | ||||
60 | 1 | 300ns | $VERSION = '1.215'; | ||
61 | 1 | 8µs | @ISA = 'PPI::Element'; | ||
62 | 1 | 4µs | *_PARENT = *PPI::Element::_PARENT; | ||
63 | 1 | 1.70ms | 1 | 12µs | } # spent 12µs making 1 call to PPI::Node::BEGIN@59 |
64 | |||||
- - | |||||
69 | ##################################################################### | ||||
70 | # The basic constructor | ||||
71 | |||||
72 | # spent 842µs within PPI::Node::new which was called 144 times, avg 6µs/call:
# 144 times (842µs+0s) by PPI::Document::new at line 153 of PPI/Document.pm, avg 6µs/call | ||||
73 | 144 | 119µs | my $class = ref $_[0] || $_[0]; | ||
74 | 144 | 959µs | bless { children => [] }, $class; | ||
75 | } | ||||
76 | |||||
- - | |||||
81 | ##################################################################### | ||||
82 | # PDOM Methods | ||||
83 | |||||
84 | =pod | ||||
85 | |||||
86 | =head2 scope | ||||
87 | |||||
88 | The C<scope> method returns true if the node represents a lexical scope | ||||
89 | boundary, or false if it does not. | ||||
90 | |||||
91 | =cut | ||||
92 | |||||
93 | ### XS -> PPI/XS.xs:_PPI_Node__scope 0.903+ | ||||
94 | sub scope { '' } | ||||
95 | |||||
96 | =pod | ||||
97 | |||||
98 | =head2 add_element $Element | ||||
99 | |||||
100 | The C<add_element> method adds a L<PPI::Element> object to the end of a | ||||
101 | C<PPI::Node>. Because Elements maintain links to their parent, an | ||||
102 | Element can only be added to a single Node. | ||||
103 | |||||
104 | Returns true if the L<PPI::Element> was added. Returns C<undef> if the | ||||
105 | Element was already within another Node, or the method is not passed | ||||
106 | a L<PPI::Element> object. | ||||
107 | |||||
108 | =cut | ||||
109 | |||||
110 | sub add_element { | ||||
111 | my $self = shift; | ||||
112 | |||||
113 | # Check the element | ||||
114 | my $Element = _INSTANCE(shift, 'PPI::Element') or return undef; | ||||
115 | $_PARENT{refaddr $Element} and return undef; | ||||
116 | |||||
117 | # Add the argument to the elements | ||||
118 | push @{$self->{children}}, $Element; | ||||
119 | Scalar::Util::weaken( | ||||
120 | $_PARENT{refaddr $Element} = $self | ||||
121 | ); | ||||
122 | |||||
123 | 1; | ||||
124 | } | ||||
125 | |||||
126 | # In a typical run profile, add_element is the number 1 resource drain. | ||||
127 | # This is a highly optimised unsafe version, for internal use only. | ||||
128 | sub __add_element { | ||||
129 | Scalar::Util::weaken( | ||||
130 | $_PARENT{refaddr $_[1]} = $_[0] | ||||
131 | ); | ||||
132 | push @{$_[0]->{children}}, $_[1]; | ||||
133 | } | ||||
134 | |||||
135 | =pod | ||||
136 | |||||
137 | =head2 elements | ||||
138 | |||||
139 | The C<elements> method accesses all child elements B<structurally> within | ||||
140 | the C<PPI::Node> object. Note that in the base of the L<PPI::Structure> | ||||
141 | classes, this C<DOES> include the brace tokens at either end of the | ||||
142 | structure. | ||||
143 | |||||
144 | Returns a list of zero or more L<PPI::Element> objects. | ||||
145 | |||||
146 | Alternatively, if called in the scalar context, the C<elements> method | ||||
147 | returns a count of the number of elements. | ||||
148 | |||||
149 | =cut | ||||
150 | |||||
151 | sub elements { | ||||
152 | if ( wantarray ) { | ||||
153 | return @{$_[0]->{children}}; | ||||
154 | } else { | ||||
155 | return scalar @{$_[0]->{children}}; | ||||
156 | } | ||||
157 | } | ||||
158 | |||||
159 | =pod | ||||
160 | |||||
161 | =head2 first_element | ||||
162 | |||||
163 | The C<first_element> method accesses the first element structurally within | ||||
164 | the C<PPI::Node> object. As for the C<elements> method, this does include | ||||
165 | the brace tokens for L<PPI::Structure> objects. | ||||
166 | |||||
167 | Returns a L<PPI::Element> object, or C<undef> if for some reason the | ||||
168 | C<PPI::Node> object does not contain any elements. | ||||
169 | |||||
170 | =cut | ||||
171 | |||||
172 | # Normally the first element is also the first child | ||||
173 | # spent 361µs within PPI::Node::first_element which was called 144 times, avg 3µs/call:
# 144 times (361µs+0s) by Perl::Critic::Document::AUTOLOAD at line 41 of Perl/Critic/Document.pm, avg 3µs/call | ||||
174 | 144 | 455µs | $_[0]->{children}->[0]; | ||
175 | } | ||||
176 | |||||
177 | =pod | ||||
178 | |||||
179 | =head2 last_element | ||||
180 | |||||
181 | The C<last_element> method accesses the last element structurally within | ||||
182 | the C<PPI::Node> object. As for the C<elements> method, this does include | ||||
183 | the brace tokens for L<PPI::Structure> objects. | ||||
184 | |||||
185 | Returns a L<PPI::Element> object, or C<undef> if for some reason the | ||||
186 | C<PPI::Node> object does not contain any elements. | ||||
187 | |||||
188 | =cut | ||||
189 | |||||
190 | # Normally the last element is also the last child | ||||
191 | sub last_element { | ||||
192 | $_[0]->{children}->[-1]; | ||||
193 | } | ||||
194 | |||||
195 | =pod | ||||
196 | |||||
197 | =head2 children | ||||
198 | |||||
199 | The C<children> method accesses all child elements lexically within the | ||||
200 | C<PPI::Node> object. Note that in the case of the L<PPI::Structure> | ||||
201 | classes, this does B<NOT> include the brace tokens at either end of the | ||||
202 | structure. | ||||
203 | |||||
204 | Returns a list of zero of more L<PPI::Element> objects. | ||||
205 | |||||
206 | Alternatively, if called in the scalar context, the C<children> method | ||||
207 | returns a count of the number of lexical children. | ||||
208 | |||||
209 | =cut | ||||
210 | |||||
211 | # In the default case, this is the same as for the elements method | ||||
212 | # spent 4.84ms within PPI::Node::children which was called 2404 times, avg 2µs/call:
# 1299 times (2.67ms+0s) by PPI::Statement::Variable::type at line 67 of PPI/Statement/Variable.pm, avg 2µs/call
# 1016 times (1.92ms+0s) by PPI::Statement::Sub::prototype at line 100 of PPI/Statement/Sub.pm, avg 2µs/call
# 89 times (245µs+0s) by PPI::Lexer::_lex_structure at line 1367 of PPI/Lexer.pm, avg 3µs/call | ||||
213 | 2404 | 7.03ms | wantarray ? @{$_[0]->{children}} : scalar @{$_[0]->{children}}; | ||
214 | } | ||||
215 | |||||
216 | =pod | ||||
217 | |||||
218 | =head2 schildren | ||||
219 | |||||
220 | The C<schildren> method is really just a convenience, the significant-only | ||||
221 | variation of the normal C<children> method. | ||||
222 | |||||
223 | In list context, returns a list of significant children. In scalar context, | ||||
224 | returns the number of significant children. | ||||
225 | |||||
226 | =cut | ||||
227 | |||||
228 | # spent 178ms (150+28.1) within PPI::Node::schildren which was called 9627 times, avg 18µs/call:
# 4817 times (60.9ms+14.2ms) by PPI::Lexer::_continues at line 705 of PPI/Lexer.pm, avg 16µs/call
# 4810 times (88.8ms+14.0ms) by PPI::Lexer::_continues at line 722 of PPI/Lexer.pm, avg 21µs/call | ||||
229 | 26055 | 36.5ms | 16428 | 14.0ms | return grep { $_->significant } @{$_[0]->{children}} if wantarray; # spent 8.47ms making 10537 calls to PPI::Element::significant, avg 804ns/call
# spent 5.49ms making 5891 calls to PPI::Token::Whitespace::significant, avg 933ns/call |
230 | 4817 | 837µs | my $count = 0; | ||
231 | 4817 | 4.87ms | foreach ( @{$_[0]->{children}} ) { | ||
232 | 16437 | 20.9ms | 16437 | 14.2ms | $count++ if $_->significant; # spent 8.64ms making 10544 calls to PPI::Element::significant, avg 819ns/call
# spent 5.53ms making 5893 calls to PPI::Token::Whitespace::significant, avg 939ns/call |
233 | } | ||||
234 | 4817 | 12.4ms | return $count; | ||
235 | } | ||||
236 | |||||
237 | =pod | ||||
238 | |||||
239 | =head2 child $index | ||||
240 | |||||
241 | The C<child> method accesses a child L<PPI::Element> object by its | ||||
242 | position within the Node. | ||||
243 | |||||
244 | Returns a L<PPI::Element> object, or C<undef> if there is no child | ||||
245 | element at that node. | ||||
246 | |||||
247 | =cut | ||||
248 | |||||
249 | # spent 5µs within PPI::Node::child which was called 2 times, avg 2µs/call:
# 2 times (5µs+0s) by Perl::Critic::Annotation::_init at line 116 of Perl/Critic/Annotation.pm, avg 2µs/call | ||||
250 | 2 | 7µs | $_[0]->{children}->[$_[1]]; | ||
251 | } | ||||
252 | |||||
253 | =pod | ||||
254 | |||||
255 | =head2 schild $index | ||||
256 | |||||
257 | The lexical structure of the Perl language ignores 'insignificant' items, | ||||
258 | such as whitespace and comments, while L<PPI> treats these items as valid | ||||
259 | tokens so that it can reassemble the file at any time. Because of this, | ||||
260 | in many situations there is a need to find an Element within a Node by | ||||
261 | index, only counting lexically significant Elements. | ||||
262 | |||||
263 | The C<schild> method returns a child Element by index, ignoring | ||||
264 | insignificant Elements. The index of a child Element is specified in the | ||||
265 | same way as for a normal array, with the first Element at index 0, and | ||||
266 | negative indexes used to identify a "from the end" position. | ||||
267 | |||||
268 | =cut | ||||
269 | |||||
270 | # spent 311ms (265+45.8) within PPI::Node::schild which was called 29896 times, avg 10µs/call:
# 6883 times (91.3ms+14.9ms) by PPI::Lexer::_add_element at line 1445 of PPI/Lexer.pm, avg 15µs/call
# 6883 times (42.5ms+6.88ms) by PPI::Lexer::_add_element at line 1444 of PPI/Lexer.pm, avg 7µs/call
# 3157 times (18.3ms+2.82ms) by PPI::Lexer::_round at line 990 of PPI/Lexer.pm, avg 7µs/call
# 2355 times (16.6ms+2.21ms) by PPI::Statement::Compound::type at line 194 of PPI/Statement/Compound.pm, avg 8µs/call
# 2273 times (12.5ms+1.91ms) by PPI::Lexer::_curly at line 1189 of PPI/Lexer.pm, avg 6µs/call
# 1520 times (8.78ms+1.42ms) by PPI::Lexer::_continues at line 705 of PPI/Lexer.pm, avg 7µs/call
# 1410 times (21.1ms+3.99ms) by PPI::Statement::Include::module at line 125 of PPI/Statement/Include.pm, avg 18µs/call
# 1268 times (6.48ms+1.13ms) by PPI::Statement::Include::type at line 92 of PPI/Statement/Include.pm, avg 6µs/call
# 1266 times (19.0ms+3.62ms) by PPI::Statement::Include::version at line 266 of PPI/Statement/Include.pm, avg 18µs/call
# 982 times (9.10ms+2.66ms) by Perl::Critic::Policy::Modules::RequireBarewordIncludes::violates at line 36 of Perl/Critic/Policy/Modules/RequireBarewordIncludes.pm, avg 12µs/call
# 587 times (5.69ms+1.57ms) by PPI::Statement::Compound::type at line 204 of PPI/Statement/Compound.pm, avg 12µs/call
# 359 times (2.20ms+319µs) by PPI::Lexer::_square at line 1026 of PPI/Lexer.pm, avg 7µs/call
# 329 times (3.52ms+903µs) by PPI::Lexer::_continues at line 750 of PPI/Lexer.pm, avg 13µs/call
# 144 times (3.85ms+273µs) by Perl::Critic::Document::AUTOLOAD at line 41 of Perl/Critic/Document.pm, avg 29µs/call
# 144 times (1.42ms+404µs) by PPI::Statement::Package::namespace at line 94 of PPI/Statement/Package.pm, avg 13µs/call
# 93 times (1.01ms+298µs) by PPI::Statement::Compound::type at line 197 of PPI/Statement/Compound.pm, avg 14µs/call
# 86 times (837µs+254µs) by Perl::Critic::Policy::Variables::RequireLexicalLoopIterators::violates at line 57 of Perl/Critic/Policy/Variables/RequireLexicalLoopIterators.pm, avg 13µs/call
# 86 times (407µs+75µs) by Perl::Critic::Policy::Variables::RequireLexicalLoopIterators::violates at line 53 of Perl/Critic/Policy/Variables/RequireLexicalLoopIterators.pm, avg 6µs/call
# 54 times (585µs+156µs) by PPI::Lexer::_curly at line 1253 of PPI/Lexer.pm, avg 14µs/call
# 16 times (177µs+35µs) by Perl::Critic::Annotation::_is_single_line_annotation_on_simple_statement at line 205 of Perl/Critic/Annotation.pm, avg 13µs/call
# once (7µs+2µs) by PPI::Lexer::_curly at line 1211 of PPI/Lexer.pm | ||||
271 | 29896 | 5.19ms | my $self = shift; | ||
272 | 29896 | 7.19ms | 16 | 18µs | my $idx = 0 + shift; # spent 18µs making 16 calls to Readonly::Scalar::FETCH, avg 1µs/call |
273 | 29896 | 9.90ms | my $el = $self->{children}; | ||
274 | 29896 | 5.55ms | if ( $idx < 0 ) { | ||
275 | 6189 | 778µs | my $cursor = 0; | ||
276 | 6189 | 2.31ms | while ( exists $el->[--$cursor] ) { | ||
277 | 6871 | 32.0ms | 6871 | 6.13ms | return $el->[$cursor] if $el->[$cursor]->significant and ++$idx >= 0; # spent 5.74ms making 6486 calls to PPI::Element::significant, avg 885ns/call
# spent 386µs making 385 calls to PPI::Token::Whitespace::significant, avg 1µs/call |
278 | } | ||||
279 | } else { | ||||
280 | 23707 | 2.08ms | my $cursor = -1; | ||
281 | 23707 | 6.02ms | while ( exists $el->[++$cursor] ) { | ||
282 | 43420 | 117ms | 43420 | 39.7ms | return $el->[$cursor] if $el->[$cursor]->significant and --$idx < 0; # spent 29.6ms making 33407 calls to PPI::Element::significant, avg 885ns/call
# spent 10.0ms making 9921 calls to PPI::Token::Whitespace::significant, avg 1µs/call
# spent 91µs making 92 calls to PPI::Token::Comment::significant, avg 988ns/call |
283 | } | ||||
284 | } | ||||
285 | 1827 | 11.7ms | undef; | ||
286 | } | ||||
287 | |||||
288 | =pod | ||||
289 | |||||
290 | =head2 contains $Element | ||||
291 | |||||
292 | The C<contains> method is used to determine if another L<PPI::Element> | ||||
293 | object is logically "within" a C<PPI::Node>. For the special case of the | ||||
294 | brace tokens at either side of a L<PPI::Structure> object, they are | ||||
295 | generally considered "within" a L<PPI::Structure> object, even if they are | ||||
296 | not actually in the elements for the L<PPI::Structure>. | ||||
297 | |||||
298 | Returns true if the L<PPI::Element> is within us, false if not, or C<undef> | ||||
299 | on error. | ||||
300 | |||||
301 | =cut | ||||
302 | |||||
303 | sub contains { | ||||
304 | my $self = shift; | ||||
305 | my $Element = _INSTANCE(shift, 'PPI::Element') or return undef; | ||||
306 | |||||
307 | # Iterate up the Element's parent chain until we either run out | ||||
308 | # of parents, or get to ourself. | ||||
309 | while ( $Element = $Element->parent ) { | ||||
310 | return 1 if refaddr($self) == refaddr($Element); | ||||
311 | } | ||||
312 | |||||
313 | ''; | ||||
314 | } | ||||
315 | |||||
316 | =pod | ||||
317 | |||||
318 | =head2 find $class | \&wanted | ||||
319 | |||||
320 | The C<find> method is used to search within a code tree for | ||||
321 | L<PPI::Element> objects that meet a particular condition. | ||||
322 | |||||
323 | To specify the condition, the method can be provided with either a simple | ||||
324 | class name (full or shortened), or a C<CODE>/function reference. | ||||
325 | |||||
326 | # Find all single quotes in a Document (which is a Node) | ||||
327 | $Document->find('PPI::Quote::Single'); | ||||
328 | |||||
329 | # The same thing with a shortened class name | ||||
330 | $Document->find('Quote::Single'); | ||||
331 | |||||
332 | # Anything more elaborate, we so with the sub | ||||
333 | $Document->find( sub { | ||||
334 | # At the top level of the file... | ||||
335 | $_[1]->parent == $_[0] | ||||
336 | and ( | ||||
337 | # ...find all comments and POD | ||||
338 | $_[1]->isa('PPI::Token::Pod') | ||||
339 | or | ||||
340 | $_[1]->isa('PPI::Token::Comment') | ||||
341 | ) | ||||
342 | } ); | ||||
343 | |||||
344 | The function will be passed two arguments, the top-level C<PPI::Node> | ||||
345 | you are searching in and the current L<PPI::Element> that the condition | ||||
346 | is testing. | ||||
347 | |||||
348 | The anonymous function should return one of three values. Returning true | ||||
349 | indicates a condition match, defined-false (C<0> or C<''>) indicates | ||||
350 | no-match, and C<undef> indicates no-match and no-descend. | ||||
351 | |||||
352 | In the last case, the tree walker will skip over anything below the | ||||
353 | C<undef>-returning element and move on to the next element at the same | ||||
354 | level. | ||||
355 | |||||
356 | To halt the entire search and return C<undef> immediately, a condition | ||||
357 | function should throw an exception (i.e. C<die>). | ||||
358 | |||||
359 | Note that this same wanted logic is used for all methods documented to | ||||
360 | have a C<\&wanted> parameter, as this one does. | ||||
361 | |||||
362 | The C<find> method returns a reference to an array of L<PPI::Element> | ||||
363 | objects that match the condition, false (but defined) if no Elements match | ||||
364 | the condition, or C<undef> if you provide a bad condition, or an error | ||||
365 | occurs during the search process. | ||||
366 | |||||
367 | In the case of a bad condition, a warning will be emitted as well. | ||||
368 | |||||
369 | =cut | ||||
370 | |||||
371 | # spent 6.01s (3.37+2.64) within PPI::Node::find which was called 3668 times, avg 1.64ms/call:
# 1293 times (62.8ms+103ms) by Perl::Critic::Policy::Variables::ProhibitConditionalDeclarations::violates at line 38 of Perl/Critic/Policy/Variables/ProhibitConditionalDeclarations.pm, avg 128µs/call
# 1016 times (780ms+575ms) by Perl::Critic::Utils::McCabe::_count_logic_keywords at line 110 of Perl/Critic/Utils/McCabe.pm, avg 1.33ms/call
# 1016 times (748ms+580ms) by Perl::Critic::Utils::McCabe::_count_logic_operators at line 129 of Perl/Critic/Utils/McCabe.pm, avg 1.31ms/call
# 144 times (965ms+691ms) by Perl::Critic::Document::find at line 179 of Perl/Critic/Document.pm, avg 11.5ms/call
# 144 times (807ms+679ms) by Perl::Critic::Document::find at line 160 of Perl/Critic/Document.pm, avg 10.3ms/call
# 55 times (7.60ms+9.02ms) by Perl::Critic::Policy::ControlStructures::ProhibitMutatingListFunctions::_has_topic_side_effect at line 119 of Perl/Critic/Policy/ControlStructures/ProhibitMutatingListFunctions.pm, avg 302µs/call | ||||
372 | 3668 | 730µs | my $self = shift; | ||
373 | 3668 | 4.65ms | 3668 | 155ms | my $wanted = $self->_wanted(shift) or return undef; # spent 155ms making 3668 calls to PPI::Node::_wanted, avg 42µs/call |
374 | |||||
375 | # Use a queue based search, rather than a recursive one | ||||
376 | 3668 | 1.30ms | my @found = (); | ||
377 | 3668 | 5.36ms | my @queue = @{$self->{children}}; | ||
378 | 3668 | 1.07ms | eval { | ||
379 | 3668 | 77.3ms | while ( @queue ) { | ||
380 | 406290 | 82.6ms | my $Element = shift @queue; | ||
381 | 406290 | 432ms | 406290 | 1.88s | my $rv = &$wanted( $self, $Element ); # spent 515ms making 110552 calls to Perl::Critic::Document::__ANON__[Perl/Critic/Document.pm:531], avg 5µs/call
# spent 513ms making 110552 calls to Perl::Critic::Document::_is_a_version_statement, avg 5µs/call
# spent 386ms making 86181 calls to PPI::Node::__ANON__[(eval 1000)[PPI/Node.pm:654]:4], avg 4µs/call
# spent 366ms making 86181 calls to PPI::Node::__ANON__[(eval 1001)[PPI/Node.pm:654]:4], avg 4µs/call
# spent 97.6ms making 12164 calls to Perl::Critic::Policy::Variables::ProhibitConditionalDeclarations::_is_conditional, avg 8µs/call
# spent 2.88ms making 660 calls to PPI::Node::__ANON__[(eval 1243)[PPI/Node.pm:654]:4], avg 4µs/call |
382 | 406290 | 13.6ms | push @found, $Element if $rv; | ||
383 | |||||
384 | # Support "don't descend on undef return" | ||||
385 | 406290 | 43.4ms | next unless defined $rv; | ||
386 | |||||
387 | # Skip if the Element doesn't have any children | ||||
388 | 394126 | 1.25s | 394126 | 384ms | next unless $Element->isa('PPI::Node'); # spent 340ms making 383503 calls to UNIVERSAL::isa, avg 887ns/call
# spent 43.8ms making 10611 calls to PPI::Structure::List::isa, avg 4µs/call
# spent 58µs making 12 calls to PPI::Structure::For::isa, avg 5µs/call |
389 | |||||
390 | # Depth-first keeps the queue size down and provides a | ||||
391 | # better logical order. | ||||
392 | 58424 | 179ms | 58424 | 87.8ms | if ( $Element->isa('PPI::Structure') ) { # spent 47.2ms making 10611 calls to PPI::Structure::List::isa, avg 4µs/call
# spent 40.6ms making 47801 calls to UNIVERSAL::isa, avg 850ns/call
# spent 46µs making 12 calls to PPI::Structure::For::isa, avg 4µs/call |
393 | 22718 | 118ms | 68154 | 67.4ms | unshift @queue, $Element->finish if $Element->finish; # spent 53.3ms making 45436 calls to PPI::Structure::finish, avg 1µs/call
# spent 14.1ms making 22718 calls to PPI::Util::TRUE, avg 619ns/call |
394 | 22718 | 19.1ms | unshift @queue, @{$Element->{children}}; | ||
395 | 22718 | 108ms | 68154 | 63.1ms | unshift @queue, $Element->start if $Element->start; # spent 50.8ms making 45436 calls to PPI::Structure::start, avg 1µs/call
# spent 12.3ms making 22718 calls to PPI::Util::TRUE, avg 539ns/call |
396 | } else { | ||||
397 | 35706 | 46.0ms | unshift @queue, @{$Element->{children}}; | ||
398 | } | ||||
399 | } | ||||
400 | }; | ||||
401 | 3668 | 291µs | if ( $@ ) { | ||
402 | # Caught exception thrown from the wanted function | ||||
403 | return undef; | ||||
404 | } | ||||
405 | |||||
406 | 3668 | 21.0ms | @found ? \@found : ''; | ||
407 | } | ||||
408 | |||||
409 | =pod | ||||
410 | |||||
411 | =head2 find_first $class | \&wanted | ||||
412 | |||||
413 | If the normal C<find> method is like a grep, then C<find_first> is | ||||
414 | equivalent to the L<Scalar::Util> C<first> function. | ||||
415 | |||||
416 | Given an element class or a wanted function, it will search depth-first | ||||
417 | through a tree until it finds something that matches the condition, | ||||
418 | returning the first Element that it encounters. | ||||
419 | |||||
420 | See the C<find> method for details on the format of the search condition. | ||||
421 | |||||
422 | Returns the first L<PPI::Element> object that matches the condition, false | ||||
423 | if nothing matches the condition, or C<undef> if given an invalid condition, | ||||
424 | or an error occurs. | ||||
425 | |||||
426 | =cut | ||||
427 | |||||
428 | # spent 1.40s (821ms+582ms) within PPI::Node::find_first which was called 1160 times, avg 1.21ms/call:
# 1016 times (796ms+527ms) by Perl::Critic::Policy::Subroutines::ProhibitNestedSubs::violates at line 47 of Perl/Critic/Policy/Subroutines/ProhibitNestedSubs.pm, avg 1.30ms/call
# 144 times (24.6ms+54.8ms) by Perl::Critic::Document::find_first at line 194 of Perl/Critic/Document.pm, avg 551µs/call | ||||
429 | 1160 | 305µs | my $self = shift; | ||
430 | 1160 | 1.59ms | 1160 | 5.13ms | my $wanted = $self->_wanted(shift) or return undef; # spent 5.13ms making 1160 calls to PPI::Node::_wanted, avg 4µs/call |
431 | |||||
432 | # Use the same queue-based search as for ->find | ||||
433 | 1160 | 2.40ms | my @queue = @{$self->{children}}; | ||
434 | 1160 | 461µs | my $rv = eval { | ||
435 | # The defined() here prevents a ton of calls to PPI::Util::TRUE | ||||
436 | 1160 | 16.4ms | while ( @queue ) { | ||
437 | 88192 | 18.5ms | my $Element = shift @queue; | ||
438 | 88192 | 103ms | 88192 | 450ms | my $rv = &$wanted( $self, $Element ); # spent 398ms making 86181 calls to Perl::Critic::Policy::Subroutines::ProhibitNestedSubs::__ANON__[Perl/Critic/Policy/Subroutines/ProhibitNestedSubs.pm:46], avg 5µs/call
# spent 51.9ms making 2011 calls to Perl::Critic::Policy::TestingAndDebugging::RequireUseStrict::__ANON__[Perl/Critic/Policy/TestingAndDebugging/RequireUseStrict.pm:116], avg 26µs/call |
439 | 88192 | 1.92ms | return $Element if $rv; | ||
440 | |||||
441 | # Support "don't descend on undef return" | ||||
442 | 88048 | 9.15ms | next unless defined $rv; | ||
443 | |||||
444 | # Skip if the Element doesn't have any children | ||||
445 | 88048 | 264ms | 88048 | 82.7ms | next unless $Element->isa('PPI::Node'); # spent 72.9ms making 85441 calls to UNIVERSAL::isa, avg 854ns/call
# spent 9.73ms making 2604 calls to PPI::Structure::List::isa, avg 4µs/call
# spent 11µs making 3 calls to PPI::Structure::For::isa, avg 4µs/call |
446 | |||||
447 | # Depth-first keeps the queue size down and provides a | ||||
448 | # better logical order. | ||||
449 | 13104 | 36.9ms | 13104 | 18.4ms | if ( $Element->isa('PPI::Structure') ) { # spent 9.32ms making 2604 calls to PPI::Structure::List::isa, avg 4µs/call
# spent 9.07ms making 10497 calls to UNIVERSAL::isa, avg 864ns/call
# spent 10µs making 3 calls to PPI::Structure::For::isa, avg 3µs/call |
450 | 5549 | 13.2ms | 11098 | 13.2ms | unshift @queue, $Element->finish if defined($Element->finish); # spent 13.2ms making 11098 calls to PPI::Structure::finish, avg 1µs/call |
451 | 5549 | 5.31ms | unshift @queue, @{$Element->{children}}; | ||
452 | 5549 | 12.2ms | 11098 | 12.6ms | unshift @queue, $Element->start if defined($Element->start); # spent 12.6ms making 11098 calls to PPI::Structure::start, avg 1µs/call |
453 | } else { | ||||
454 | 7555 | 10.8ms | unshift @queue, @{$Element->{children}}; | ||
455 | } | ||||
456 | } | ||||
457 | }; | ||||
458 | 1160 | 117µs | if ( $@ ) { | ||
459 | # Caught exception thrown from the wanted function | ||||
460 | return undef; | ||||
461 | } | ||||
462 | |||||
463 | 1160 | 5.81ms | 144 | 102µs | $rv or ''; # spent 102µs making 144 calls to PPI::Util::TRUE, avg 708ns/call |
464 | } | ||||
465 | |||||
466 | =pod | ||||
467 | |||||
468 | =head2 find_any $class | \&wanted | ||||
469 | |||||
470 | The C<find_any> method is a short-circuiting true/false method that behaves | ||||
471 | like the normal C<find> method, but returns true as soon as it finds any | ||||
472 | Elements that match the search condition. | ||||
473 | |||||
474 | See the C<find> method for details on the format of the search condition. | ||||
475 | |||||
476 | Returns true if any Elements that match the condition can be found, false if | ||||
477 | not, or C<undef> if given an invalid condition, or an error occurs. | ||||
478 | |||||
479 | =cut | ||||
480 | |||||
481 | sub find_any { | ||||
482 | my $self = shift; | ||||
483 | my $rv = $self->find_first(@_); | ||||
484 | $rv ? 1 : $rv; # false or undef | ||||
485 | } | ||||
486 | |||||
487 | =pod | ||||
488 | |||||
489 | =head2 remove_child $Element | ||||
490 | |||||
491 | If passed a L<PPI::Element> object that is a direct child of the Node, | ||||
492 | the C<remove_element> method will remove the C<Element> intact, along | ||||
493 | with any of its children. As such, this method acts essentially as a | ||||
494 | 'cut' function. | ||||
495 | |||||
496 | If successful, returns the removed element. Otherwise, returns C<undef>. | ||||
497 | |||||
498 | =cut | ||||
499 | |||||
500 | sub remove_child { | ||||
501 | my $self = shift; | ||||
502 | my $child = _INSTANCE(shift, 'PPI::Element') or return undef; | ||||
503 | |||||
504 | # Find the position of the child | ||||
505 | my $key = refaddr $child; | ||||
506 | my $p = List::MoreUtils::firstidx { | ||||
507 | refaddr $_ == $key | ||||
508 | } @{$self->{children}}; | ||||
509 | return undef unless defined $p; | ||||
510 | |||||
511 | # Splice it out, and remove the child's parent entry | ||||
512 | splice( @{$self->{children}}, $p, 1 ); | ||||
513 | delete $_PARENT{refaddr $child}; | ||||
514 | |||||
515 | $child; | ||||
516 | } | ||||
517 | |||||
518 | =pod | ||||
519 | |||||
520 | =head2 prune $class | \&wanted | ||||
521 | |||||
522 | The C<prune> method is used to strip L<PPI::Element> objects out of a code | ||||
523 | tree. The argument is the same as for the C<find> method, either a class | ||||
524 | name, or an anonymous subroutine which returns true/false. Any Element | ||||
525 | that matches the class|wanted will be deleted from the code tree, along | ||||
526 | with any of its children. | ||||
527 | |||||
528 | The C<prune> method returns the number of C<Element> objects that matched | ||||
529 | and were removed, B<non-recursively>. This might also be zero, so avoid a | ||||
530 | simple true/false test on the return false of the C<prune> method. It | ||||
531 | returns C<undef> on error, which you probably B<should> test for. | ||||
532 | |||||
533 | =begin testing prune 2 | ||||
534 | |||||
535 | # Avoids a bug in old Perls relating to the detection of scripts | ||||
536 | # Known to occur in ActivePerl 5.6.1 and at least one 5.6.2 install. | ||||
537 | my $hashbang = reverse 'lrep/nib/rsu/!#'; | ||||
538 | my $document = PPI::Document->new( \<<"END_PERL" ); | ||||
539 | $hashbang | ||||
540 | |||||
541 | use strict; | ||||
542 | |||||
543 | sub one { 1 } | ||||
544 | sub two { 2 } | ||||
545 | sub three { 3 } | ||||
546 | |||||
547 | print one; | ||||
548 | print "\n"; | ||||
549 | print three; | ||||
550 | print "\n"; | ||||
551 | |||||
552 | exit; | ||||
553 | END_PERL | ||||
554 | |||||
555 | isa_ok( $document, 'PPI::Document' ); | ||||
556 | ok( defined($document->prune ('PPI::Statement::Sub')), | ||||
557 | 'Pruned multiple subs ok' ); | ||||
558 | |||||
559 | =end testing | ||||
560 | |||||
561 | =cut | ||||
562 | |||||
563 | sub prune { | ||||
564 | my $self = shift; | ||||
565 | my $wanted = $self->_wanted(shift) or return undef; | ||||
566 | |||||
567 | # Use a depth-first queue search | ||||
568 | my $pruned = 0; | ||||
569 | my @queue = $self->children; | ||||
570 | eval { | ||||
571 | while ( my $element = shift @queue ) { | ||||
572 | my $rv = &$wanted( $self, $element ); | ||||
573 | if ( $rv ) { | ||||
574 | # Delete the child | ||||
575 | $element->delete or return undef; | ||||
576 | $pruned++; | ||||
577 | next; | ||||
578 | } | ||||
579 | |||||
580 | # Support the undef == "don't descend" | ||||
581 | next unless defined $rv; | ||||
582 | |||||
583 | if ( _INSTANCE($element, 'PPI::Node') ) { | ||||
584 | # Depth-first keeps the queue size down | ||||
585 | unshift @queue, $element->children; | ||||
586 | } | ||||
587 | } | ||||
588 | }; | ||||
589 | if ( $@ ) { | ||||
590 | # Caught exception thrown from the wanted function | ||||
591 | return undef; | ||||
592 | } | ||||
593 | |||||
594 | $pruned; | ||||
595 | } | ||||
596 | |||||
597 | # This method is likely to be very heavily used, to take | ||||
598 | # it slowly and carefuly. | ||||
599 | ### NOTE: Renaming this function or changing either to self will probably | ||||
600 | ### break File::Find::Rule::PPI | ||||
601 | sub _wanted { | ||||
602 | 4828 | 675µs | my $either = shift; | ||
603 | 4828 | 1.64ms | my $it = defined($_[0]) ? shift : do { | ||
604 | Carp::carp('Undefined value passed as search condition') if $^W; | ||||
605 | return undef; | ||||
606 | }; | ||||
607 | |||||
608 | # Has the caller provided a wanted function directly | ||||
609 | 4828 | 26.8ms | 4828 | 3.47ms | return $it if _CODELIKE($it); # spent 3.47ms making 4828 calls to Params::Util::_CODELIKE, avg 720ns/call |
610 | 2087 | 275µs | if ( ref $it ) { | ||
611 | # No other ref types are supported | ||||
612 | Carp::carp('Illegal non-CODE reference passed as search condition') if $^W; | ||||
613 | return undef; | ||||
614 | } | ||||
615 | |||||
616 | # The first argument should be an Element class, possibly in shorthand | ||||
617 | 2087 | 1.39ms | $it = "PPI::$it" unless substr($it, 0, 5) eq 'PPI::'; | ||
618 | 2087 | 10.2ms | 4174 | 17.0ms | unless ( _CLASS($it) and $it->isa('PPI::Element') ) { # spent 14.1ms making 2087 calls to Params::Util::_CLASS, avg 7µs/call
# spent 2.95ms making 2087 calls to UNIVERSAL::isa, avg 1µs/call |
619 | # We got something, but it isn't an element | ||||
620 | Carp::carp("Cannot create search condition for '$it': Not a PPI::Element") if $^W; | ||||
621 | return undef; | ||||
622 | } | ||||
623 | |||||
624 | # Create the class part of the wanted function | ||||
625 | 2087 | 1.39ms | my $wanted_class = "\n\treturn '' unless \$_[1]->isa('$it');"; | ||
626 | |||||
627 | # Have we been given a second argument to check the content | ||||
628 | 2087 | 287µs | my $wanted_content = ''; | ||
629 | 2087 | 372µs | if ( defined $_[0] ) { | ||
630 | my $content = shift; | ||||
631 | if ( ref $content eq 'Regexp' ) { | ||||
632 | $content = "$content"; | ||||
633 | } elsif ( ref $content ) { | ||||
634 | # No other ref types are supported | ||||
635 | Carp::carp("Cannot create search condition for '$it': Not a PPI::Element") if $^W; | ||||
636 | return undef; | ||||
637 | } else { | ||||
638 | $content = quotemeta $content; | ||||
639 | } | ||||
640 | |||||
641 | # Complete the content part of the wanted function | ||||
642 | $wanted_content .= "\n\treturn '' unless defined \$_[1]->{content};"; | ||||
643 | $wanted_content .= "\n\treturn '' unless \$_[1]->{content} =~ /$content/;"; | ||||
644 | } | ||||
645 | |||||
646 | # Create the complete wanted function | ||||
647 | 2087 | 1.48ms | my $code = "sub {" | ||
648 | . $wanted_class | ||||
649 | . $wanted_content | ||||
650 | . "\n\t1;" | ||||
651 | . "\n}"; | ||||
652 | |||||
653 | # Compile the wanted function | ||||
654 | 2087 | 88.9ms | $code = eval $code; # spent 582ms executing statements in 1016 string evals (merged) # includes 308ms spent executing 86181 calls to 1 sub defined therein. # spent 569ms executing statements in 1016 string evals (merged) # includes 290ms spent executing 86181 calls to 1 sub defined therein. # spent 5.69ms executing statements in 55 string evals (merged) # includes 2.28ms spent executing 660 calls to 1 sub defined therein. | ||
655 | 2087 | 10.2ms | (ref $code eq 'CODE') ? $code : undef; | ||
656 | } | ||||
657 | |||||
- - | |||||
662 | #################################################################### | ||||
663 | # PPI::Element overloaded methods | ||||
664 | |||||
665 | # spent 931ms (642+290) within PPI::Node::tokens which was called 32942 times, avg 28µs/call:
# 21076 times (424ms+-424ms) by PPI::Node::tokens at line 666, avg 0s/call
# 11578 times (170ms+-170ms) by PPI::Structure::tokens at line 278 of PPI/Structure.pm, avg 0s/call
# 144 times (24.9ms+475ms) by PPI::Document::index_locations at line 592 of PPI/Document.pm, avg 3.47ms/call
# 144 times (22.9ms+408ms) by PPI::Document::serialize at line 423 of PPI/Document.pm, avg 2.99ms/call | ||||
666 | 230890 | 343ms | 197948 | 868ms | map { $_->tokens } @{$_[0]->{children}}; # spent 1.40s making 11578 calls to PPI::Structure::tokens, avg 121µs/call, recursion: max depth 6, sum of overlapping time 664ms
# spent 133ms making 165294 calls to PPI::Element::tokens, avg 802ns/call
# spent 1.92s making 21076 calls to PPI::Node::tokens, avg 91µs/call, recursion: max depth 15, sum of overlapping time 1.92s |
667 | } | ||||
668 | |||||
669 | ### XS -> PPI/XS.xs:_PPI_Element__content 0.900+ | ||||
670 | # spent 82.0ms (56.3+25.7) within PPI::Node::content which was called 2076 times, avg 40µs/call:
# 1929 times (54.0ms+24.8ms) by PPI::Structure::content at line 293 of PPI/Structure.pm, avg 41µs/call
# 144 times (2.23ms+814µs) by Perl::Critic::Document::CORE:match at line 552 of Perl/Critic/Document.pm, avg 21µs/call
# 3 times (102µs+131µs) by Perl::Critic::Violation::_line_containing_violation at line 304 of Perl/Critic/Violation.pm, avg 78µs/call | ||||
671 | 10754 | 20.7ms | 8678 | 10.5ms | join '', map { $_->content } @{$_[0]->{children}}; # spent 10.4ms making 7954 calls to PPI::Token::content, avg 1µs/call
# spent 46.1ms making 724 calls to PPI::Structure::content, avg 64µs/call, recursion: max depth 5, sum of overlapping time 46.0ms |
672 | } | ||||
673 | |||||
674 | # Clone as normal, but then go down and relink all the _PARENT entries | ||||
675 | sub clone { | ||||
676 | my $self = shift; | ||||
677 | my $clone = $self->SUPER::clone; | ||||
678 | $clone->__link_children; | ||||
679 | $clone; | ||||
680 | } | ||||
681 | |||||
682 | # spent 127ms (61.5+65.6) within PPI::Node::location which was called 9610 times, avg 13µs/call:
# 9268 times (58.9ms+62.5ms) by Perl::Critic::Policy::TestingAndDebugging::RequireUseStrict::violates at line 73 of Perl/Critic/Policy/TestingAndDebugging/RequireUseStrict.pm, avg 13µs/call
# 144 times (1.17ms+1.47ms) by PPI::Element::logical_filename at line 974 of PPI/Element.pm, avg 18µs/call
# 144 times (1.07ms+1.37ms) by Perl::Critic::Policy::TestingAndDebugging::RequireUseStrict::violates at line 59 of Perl/Critic/Policy/TestingAndDebugging/RequireUseStrict.pm, avg 17µs/call
# 51 times (324µs+307µs) by PPI::Element::logical_line_number at line 932 of PPI/Element.pm, avg 12µs/call
# 3 times (17µs+16µs) by PPI::Element::line_number at line 814 of PPI/Element.pm, avg 11µs/call | ||||
683 | 9610 | 2.02ms | my $self = shift; | ||
684 | 9610 | 31.4ms | 9610 | 5.22ms | my $first = $self->{children}->[0] or return undef; # spent 5.22ms making 9610 calls to PPI::Util::TRUE, avg 543ns/call |
685 | 9610 | 23.9ms | 9610 | 60.4ms | $first->location; # spent 60.2ms making 9602 calls to PPI::Element::location, avg 6µs/call
# spent 180µs making 8 calls to PPI::Structure::location, avg 23µs/call |
686 | } | ||||
687 | |||||
- - | |||||
692 | ##################################################################### | ||||
693 | # Internal Methods | ||||
694 | |||||
695 | # spent 999ms (601+398) within PPI::Node::DESTROY which was called 16471 times, avg 61µs/call:
# 16327 times (72.3ms+-72.3ms) by PPI::Node::DESTROY at line 700, avg 0s/call
# 144 times (529ms+470ms) by Perl::Critic::critique at line 249 of Perl/Critic/Command.pm, avg 6.94ms/call | ||||
696 | 16471 | 1.18ms | local $_; | ||
697 | 16471 | 5.92ms | if ( $_[0]->{children} ) { | ||
698 | 144 | 149µs | my @queue = $_[0]; | ||
699 | 144 | 204µs | while ( defined($_ = shift @queue) ) { | ||
700 | 99118 | 107ms | 98830 | 338ms | unshift @queue, @{delete $_->{children}} if $_->{children}; # spent 338ms making 82503 calls to PPI::Element::DESTROY, avg 4µs/call
# spent 81.6ms making 16327 calls to PPI::Node::DESTROY, avg 5µs/call, recursion: max depth 1, sum of overlapping time 81.6ms |
701 | |||||
702 | # Remove all internal/private weird crosslinking so that | ||||
703 | # the cascading DESTROY calls will get called properly. | ||||
704 | 99118 | 254ms | 11578 | 49.3ms | %$_ = (); # spent 49.3ms making 11578 calls to PPI::Element::DESTROY, avg 4µs/call |
705 | } | ||||
706 | } | ||||
707 | |||||
708 | # Remove us from our parent node as normal | ||||
709 | 16471 | 87.8ms | 16615 | 10.0ms | delete $_PARENT{refaddr $_[0]}; # spent 9.49ms making 16471 calls to Scalar::Util::refaddr, avg 576ns/call
# spent 528µs making 144 calls to PPI::Element::DESTROY, avg 4µs/call |
710 | } | ||||
711 | |||||
712 | # Find the position of a child | ||||
713 | sub __position { | ||||
714 | my $key = refaddr $_[1]; | ||||
715 | List::MoreUtils::firstidx { refaddr $_ == $key } @{$_[0]->{children}}; | ||||
716 | } | ||||
717 | |||||
718 | # Insert one or more elements before a child | ||||
719 | sub __insert_before_child { | ||||
720 | my $self = shift; | ||||
721 | my $key = refaddr shift; | ||||
722 | my $p = List::MoreUtils::firstidx { | ||||
723 | refaddr $_ == $key | ||||
724 | } @{$self->{children}}; | ||||
725 | foreach ( @_ ) { | ||||
726 | Scalar::Util::weaken( | ||||
727 | $_PARENT{refaddr $_} = $self | ||||
728 | ); | ||||
729 | } | ||||
730 | splice( @{$self->{children}}, $p, 0, @_ ); | ||||
731 | 1; | ||||
732 | } | ||||
733 | |||||
734 | # Insert one or more elements after a child | ||||
735 | sub __insert_after_child { | ||||
736 | my $self = shift; | ||||
737 | my $key = refaddr shift; | ||||
738 | my $p = List::MoreUtils::firstidx { | ||||
739 | refaddr $_ == $key | ||||
740 | } @{$self->{children}}; | ||||
741 | foreach ( @_ ) { | ||||
742 | Scalar::Util::weaken( | ||||
743 | $_PARENT{refaddr $_} = $self | ||||
744 | ); | ||||
745 | } | ||||
746 | splice( @{$self->{children}}, $p + 1, 0, @_ ); | ||||
747 | 1; | ||||
748 | } | ||||
749 | |||||
750 | # Replace a child | ||||
751 | sub __replace_child { | ||||
752 | my $self = shift; | ||||
753 | my $key = refaddr shift; | ||||
754 | my $p = List::MoreUtils::firstidx { | ||||
755 | refaddr $_ == $key | ||||
756 | } @{$self->{children}}; | ||||
757 | foreach ( @_ ) { | ||||
758 | Scalar::Util::weaken( | ||||
759 | $_PARENT{refaddr $_} = $self | ||||
760 | ); | ||||
761 | } | ||||
762 | splice( @{$self->{children}}, $p, 1, @_ ); | ||||
763 | 1; | ||||
764 | } | ||||
765 | |||||
766 | # Create PARENT links for an entire tree. | ||||
767 | # Used when cloning or thawing. | ||||
768 | sub __link_children { | ||||
769 | my $self = shift; | ||||
770 | |||||
771 | # Relink all our children ( depth first ) | ||||
772 | my @queue = ( $self ); | ||||
773 | while ( my $Node = shift @queue ) { | ||||
774 | # Link our immediate children | ||||
775 | foreach my $Element ( @{$Node->{children}} ) { | ||||
776 | Scalar::Util::weaken( | ||||
777 | $_PARENT{refaddr($Element)} = $Node | ||||
778 | ); | ||||
779 | unshift @queue, $Element if $Element->isa('PPI::Node'); | ||||
780 | } | ||||
781 | |||||
782 | # If it's a structure, relink the open/close braces | ||||
783 | next unless $Node->isa('PPI::Structure'); | ||||
784 | Scalar::Util::weaken( | ||||
785 | $_PARENT{refaddr($Node->start)} = $Node | ||||
786 | ) if $Node->start; | ||||
787 | Scalar::Util::weaken( | ||||
788 | $_PARENT{refaddr($Node->finish)} = $Node | ||||
789 | ) if $Node->finish; | ||||
790 | } | ||||
791 | |||||
792 | 1; | ||||
793 | } | ||||
794 | |||||
795 | 1 | 2µs | 1; | ||
796 | |||||
797 | =pod | ||||
798 | |||||
799 | =head1 TO DO | ||||
800 | |||||
801 | - Move as much as possible to L<PPI::XS> | ||||
802 | |||||
803 | =head1 SUPPORT | ||||
804 | |||||
805 | See the L<support section|PPI/SUPPORT> in the main module. | ||||
806 | |||||
807 | =head1 AUTHOR | ||||
808 | |||||
809 | Adam Kennedy E<lt>adamk@cpan.orgE<gt> | ||||
810 | |||||
811 | =head1 COPYRIGHT | ||||
812 | |||||
813 | Copyright 2001 - 2011 Adam Kennedy. | ||||
814 | |||||
815 | This program is free software; you can redistribute | ||||
816 | it and/or modify it under the same terms as Perl itself. | ||||
817 | |||||
818 | The full text of the license can be found in the | ||||
819 | LICENSE file included with this module. | ||||
820 | |||||
821 | =cut |