| 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 | PPI::Node::find |
| 1160 | 2 | 2 | 821ms | 1.40s | PPI::Node::find_first |
| 32942 | 4 | 3 | 642ms | 931ms | PPI::Node::tokens (recurses: max depth 15, inclusive time 3.16s) |
| 16471 | 2 | 2 | 601ms | 999ms | PPI::Node::DESTROY (recurses: max depth 1, inclusive time 81.6ms) |
| 29896 | 21 | 8 | 265ms | 311ms | PPI::Node::schild |
| 9627 | 2 | 1 | 150ms | 178ms | PPI::Node::schildren |
| 4828 | 2 | 1 | 140ms | 160ms | PPI::Node::_wanted |
| 9610 | 5 | 2 | 61.5ms | 127ms | PPI::Node::location |
| 2076 | 3 | 3 | 56.3ms | 82.0ms | PPI::Node::content (recurses: max depth 5, inclusive time 30.8ms) |
| 2404 | 3 | 3 | 4.84ms | 4.84ms | PPI::Node::children |
| 144 | 1 | 1 | 842µs | 842µs | PPI::Node::new |
| 144 | 1 | 1 | 361µs | 361µs | PPI::Node::first_element |
| 1 | 1 | 1 | 12µs | 12µs | PPI::Node::BEGIN@59 |
| 1 | 1 | 1 | 11µs | 24µs | PPI::Node::BEGIN@51 |
| 1 | 1 | 1 | 7µs | 48µs | PPI::Node::BEGIN@58 |
| 1 | 1 | 1 | 7µs | 28µs | PPI::Node::BEGIN@53 |
| 1 | 1 | 1 | 7µs | 42µs | PPI::Node::BEGIN@55 |
| 2 | 1 | 1 | 5µs | 5µs | PPI::Node::child |
| 1 | 1 | 1 | 3µs | 3µs | PPI::Node::BEGIN@56 |
| 1 | 1 | 1 | 3µs | 3µs | PPI::Node::BEGIN@52 |
| 1 | 1 | 1 | 3µs | 3µs | PPI::Node::BEGIN@54 |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__ANON__[:508] |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__ANON__[:715] |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__ANON__[:724] |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__ANON__[:740] |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__ANON__[:756] |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__add_element |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__insert_after_child |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__insert_before_child |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__link_children |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__position |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::__replace_child |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::add_element |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::clone |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::contains |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::elements |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::find_any |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::last_element |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::prune |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::remove_child |
| 0 | 0 | 0 | 0s | 0s | PPI::Node::scope |
| 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 |