Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/Perl/Critic/Policy/Subroutines/ProhibitUnusedPrivateSubroutines.pm |
Statements | Executed 29 statements in 1.17ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 27µs | 50µs | _parse_private_name_regex | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 26µs | 408µs | BEGIN@18 | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 16µs | 16µs | BEGIN@10 | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 16µs | 18µs | supported_parameters | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 8µs | 8µs | CORE:regcomp (opcode) | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 8µs | 11µs | BEGIN@13 | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 8µs | 26µs | BEGIN@16 | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 7µs | 57µs | BEGIN@22 | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 7µs | 18µs | BEGIN@12 | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 7µs | 187µs | BEGIN@15 | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 6µs | 7µs | default_severity | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
1 | 1 | 1 | 2µs | 2µs | CORE:qr (opcode) | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | _compare_token_locations | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | _expand_element | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | _find_regular_expressions | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | _find_sub_call_in_document | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | _find_sub_overload_in_document | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | _find_sub_reference_in_document | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | _find_sub_usage_in_regexp | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | _get_include_arguments | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | applies_to | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | default_themes | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
0 | 0 | 0 | 0s | 0s | violates | Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | ############################################################################## | ||||
2 | # $URL$ | ||||
3 | # $Date$ | ||||
4 | # $Author$ | ||||
5 | # $Revision$ | ||||
6 | ############################################################################## | ||||
7 | |||||
8 | package Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines; | ||||
9 | |||||
10 | 2 | 39µs | 1 | 16µs | # spent 16µs within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@10 which was called:
# once (16µs+0s) by Module::Pluggable::Object::_require at line 10 # spent 16µs making 1 call to Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@10 |
11 | |||||
12 | 2 | 22µs | 2 | 29µs | # spent 18µs (7+11) within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@12 which was called:
# once (7µs+11µs) by Module::Pluggable::Object::_require at line 12 # spent 18µs making 1 call to Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@12
# spent 11µs making 1 call to strict::import |
13 | 2 | 21µs | 2 | 15µs | # spent 11µs (8+4) within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@13 which was called:
# once (8µs+4µs) by Module::Pluggable::Object::_require at line 13 # spent 11µs making 1 call to Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@13
# spent 4µs making 1 call to warnings::import |
14 | |||||
15 | 2 | 22µs | 2 | 367µs | # spent 187µs (7+180) within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@15 which was called:
# once (7µs+180µs) by Module::Pluggable::Object::_require at line 15 # spent 187µs making 1 call to Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@15
# spent 180µs making 1 call to English::import |
16 | 2 | 25µs | 2 | 45µs | # spent 26µs (8+19) within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@16 which was called:
# once (8µs+19µs) by Module::Pluggable::Object::_require at line 16 # spent 26µs making 1 call to Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@16
# spent 19µs making 1 call to Exporter::import |
17 | |||||
18 | 1 | 300ns | # spent 408µs (26+382) within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@18 which was called:
# once (26µs+382µs) by Module::Pluggable::Object::_require at line 21 | ||
19 | :characters hashify is_function_call is_method_call :severities | ||||
20 | $EMPTY $TRUE | ||||
21 | 1 | 25µs | 2 | 790µs | }; # spent 408µs making 1 call to Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@18
# spent 382µs making 1 call to Exporter::import |
22 | 2 | 959µs | 2 | 106µs | # spent 57µs (7+50) within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@22 which was called:
# once (7µs+50µs) by Module::Pluggable::Object::_require at line 22 # spent 57µs making 1 call to Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::BEGIN@22
# spent 50µs making 1 call to base::import |
23 | |||||
24 | 1 | 600ns | our $VERSION = '1.121'; | ||
25 | |||||
26 | #----------------------------------------------------------------------------- | ||||
27 | |||||
28 | 1 | 2µs | 1 | 30µs | Readonly::Scalar my $DESC => # spent 30µs making 1 call to Readonly::Scalar |
29 | q{Private subroutine/method '%s' declared but not used}; | ||||
30 | 1 | 900ns | 1 | 21µs | Readonly::Scalar my $EXPL => q{Eliminate dead code}; # spent 21µs making 1 call to Readonly::Scalar |
31 | |||||
32 | 1 | 3µs | 2 | 37µs | Readonly::Hash my %IS_COMMA => hashify( $COMMA, $FATCOMMA ); # spent 24µs making 1 call to Readonly::Hash
# spent 13µs making 1 call to Perl::Critic::Utils::hashify |
33 | |||||
34 | #----------------------------------------------------------------------------- | ||||
35 | |||||
36 | # spent 18µs (16+2) within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::supported_parameters which was called:
# once (16µs+2µs) by Perl::Critic::Policy::new at line 88 of Perl/Critic/Policy.pm | ||||
37 | return ( | ||||
38 | { | ||||
39 | 1 | 14µs | 2 | 2µs | name => 'private_name_regex', # spent 2µs making 2 calls to Readonly::Scalar::FETCH, avg 1µs/call |
40 | description => 'Pattern that determines what a private subroutine is.', | ||||
41 | default_string => '\b_\w+\b', ## no critic (RequireInterpolationOfMetachars) | ||||
42 | behavior => 'string', | ||||
43 | parser => \&_parse_private_name_regex, | ||||
44 | }, | ||||
45 | { | ||||
46 | name => 'allow', | ||||
47 | description => | ||||
48 | q<Subroutines matching the private name regex to allow under this policy.>, | ||||
49 | default_string => $EMPTY, | ||||
50 | behavior => 'string list', | ||||
51 | }, | ||||
52 | ); | ||||
53 | } | ||||
54 | |||||
55 | 1 | 2µs | # spent 7µs (6+1) within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::default_severity which was called:
# once (6µs+1µs) by Perl::Critic::Policy::get_severity at line 331 of Perl/Critic/Policy.pm | ||
56 | sub default_themes { return qw( core maintenance certrec ) } | ||||
57 | sub applies_to { return 'PPI::Statement::Sub' } | ||||
58 | |||||
59 | #----------------------------------------------------------------------------- | ||||
60 | |||||
61 | # spent 50µs (27+23) within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::_parse_private_name_regex which was called:
# once (27µs+23µs) by Perl::Critic::PolicyParameter::parse_and_validate_config_value at line 231 of Perl/Critic/PolicyParameter.pm | ||||
62 | 1 | 500ns | my ($self, $parameter, $config_string) = @_; | ||
63 | 1 | 2µs | 1 | 1µs | defined $config_string # spent 1µs making 1 call to Perl::Critic::PolicyParameter::get_default_string |
64 | or $config_string = $parameter->get_default_string(); | ||||
65 | |||||
66 | 1 | 500ns | my $regex; | ||
67 | 3 | 22µs | 2 | 10µs | eval { $regex = qr/$config_string/; 1 } ## no critic (RegularExpressions) # spent 8µs making 1 call to Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::CORE:regcomp
# spent 2µs making 1 call to Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::CORE:qr |
68 | or $self->throw_parameter_value_exception( | ||||
69 | 'private_name_regex', | ||||
70 | $config_string, | ||||
71 | undef, | ||||
72 | "is not a valid regular expression: $EVAL_ERROR", | ||||
73 | ); | ||||
74 | |||||
75 | 1 | 4µs | 1 | 11µs | $self->__set_parameter_value($parameter, $regex); # spent 11µs making 1 call to Perl::Critic::Policy::__set_parameter_value |
76 | |||||
77 | 1 | 3µs | return; | ||
78 | } | ||||
79 | |||||
80 | #----------------------------------------------------------------------------- | ||||
81 | |||||
82 | sub violates { | ||||
83 | my ( $self, $elem, $document ) = @_; | ||||
84 | |||||
85 | # Not interested in forward declarations, only the real thing. | ||||
86 | $elem->forward() and return; | ||||
87 | |||||
88 | # Not interested in subs without names. | ||||
89 | my $name = $elem->name() or return; | ||||
90 | |||||
91 | # If the sub is shoved into someone else's name space, we wimp out. | ||||
92 | $name =~ m/ :: /smx and return; | ||||
93 | |||||
94 | # If the name is explicitly allowed, we just return (OK). | ||||
95 | $self->{_allow}{$name} and return; | ||||
96 | |||||
97 | # If the name is not an anonymous subroutine according to our definition, | ||||
98 | # we just return (OK). | ||||
99 | $name =~ m/ \A $self->{_private_name_regex} \z /smx or return; | ||||
100 | |||||
101 | # If the subroutine is called in the document, just return (OK). | ||||
102 | $self->_find_sub_call_in_document( $elem, $document ) and return; | ||||
103 | |||||
104 | # If the subroutine is referred to in the document, just return (OK). | ||||
105 | $self->_find_sub_reference_in_document( $elem, $document ) and return; | ||||
106 | |||||
107 | # If the subroutine is used in an overload, just return (OK). | ||||
108 | $self->_find_sub_overload_in_document( $elem, $document ) and return; | ||||
109 | |||||
110 | # No uses of subroutine found. Return a violation. | ||||
111 | return $self->violation( sprintf( $DESC, $name ), $EXPL, $elem ); | ||||
112 | } | ||||
113 | |||||
114 | |||||
115 | # Basically the spaceship operator for token locations. The arguments are the | ||||
116 | # two tokens to compare. If either location is unavailable we return undef. | ||||
117 | sub _compare_token_locations { | ||||
118 | my ( $left_token, $right_token ) = @_; | ||||
119 | my $left_loc = $left_token->location() or return; | ||||
120 | my $right_loc = $right_token->location() or return; | ||||
121 | return $left_loc->[0] <=> $right_loc->[0] || | ||||
122 | $left_loc->[1] <=> $right_loc->[1]; | ||||
123 | } | ||||
124 | |||||
125 | # Find out if the subroutine defined in $elem is called in $document. Calls | ||||
126 | # inside the subroutine itself do not count. | ||||
127 | sub _find_sub_call_in_document { | ||||
128 | my ( $self, $elem, $document ) = @_; | ||||
129 | |||||
130 | my $start_token = $elem->first_token(); | ||||
131 | my $finish_token = $elem->last_token(); | ||||
132 | my $name = $elem->name(); | ||||
133 | |||||
134 | if ( my $found = $document->find( 'PPI::Token::Word' ) ) { | ||||
135 | foreach my $usage ( @{ $found } ) { | ||||
136 | $name eq $usage->content() or next; | ||||
137 | is_function_call( $usage ) | ||||
138 | or is_method_call( $usage ) | ||||
139 | or next; | ||||
140 | _compare_token_locations( $usage, $start_token ) < 0 | ||||
141 | and return $TRUE; | ||||
142 | _compare_token_locations( $finish_token, $usage ) < 0 | ||||
143 | and return $TRUE; | ||||
144 | } | ||||
145 | } | ||||
146 | |||||
147 | foreach my $regexp ( _find_regular_expressions( $document ) ) { | ||||
148 | |||||
149 | _compare_token_locations( $regexp, $start_token ) >= 0 | ||||
150 | and _compare_token_locations( $finish_token, $regexp ) >= 0 | ||||
151 | and next; | ||||
152 | _find_sub_usage_in_regexp( $name, $regexp, $document ) | ||||
153 | and return $TRUE; | ||||
154 | |||||
155 | } | ||||
156 | |||||
157 | return; | ||||
158 | } | ||||
159 | |||||
160 | # Find analyzable regular expressions in the given document. This means | ||||
161 | # matches, substitutions, and the qr{} operator. | ||||
162 | sub _find_regular_expressions { | ||||
163 | my ( $document ) = @_; | ||||
164 | |||||
165 | return ( map { @{ $document->find( $_ ) || [] } } qw{ | ||||
166 | PPI::Token::Regexp::Match | ||||
167 | PPI::Token::Regexp::Substitute | ||||
168 | PPI::Token::QuoteLike::Regexp | ||||
169 | } ); | ||||
170 | } | ||||
171 | |||||
172 | # Find out if the subroutine named in $name is called in the given $regexp. | ||||
173 | # This could happen either by an explicit s/.../.../e, or by interpolation | ||||
174 | # (i.e. @{[...]} ). | ||||
175 | sub _find_sub_usage_in_regexp { | ||||
176 | my ( $name, $regexp, $document ) = @_; | ||||
177 | |||||
178 | my $ppix = $document->ppix_regexp_from_element( $regexp ) or return; | ||||
179 | $ppix->failures() and return; | ||||
180 | |||||
181 | foreach my $code ( @{ $ppix->find( 'PPIx::Regexp::Token::Code' ) || [] } ) { | ||||
182 | my $doc = $code->ppi() or next; | ||||
183 | |||||
184 | foreach my $word ( @{ $doc->find( 'PPI::Token::Word' ) || [] } ) { | ||||
185 | $name eq $word->content() or next; | ||||
186 | is_function_call( $word ) | ||||
187 | or is_method_call( $word ) | ||||
188 | or next; | ||||
189 | return $TRUE; | ||||
190 | } | ||||
191 | |||||
192 | } | ||||
193 | |||||
194 | return; | ||||
195 | } | ||||
196 | |||||
197 | # Find out if the subroutine defined in $elem handles an overloaded operator. | ||||
198 | # We recognize both string literals (the usual form) and words (in case | ||||
199 | # someone perversely followed the subroutine name by a fat comma). We ignore | ||||
200 | # the '\&_foo' construction, since _find_sub_reference_in_document() should | ||||
201 | # find this. | ||||
202 | sub _find_sub_overload_in_document { | ||||
203 | my ( $self, $elem, $document ) = @_; | ||||
204 | |||||
205 | my $name = $elem->name(); | ||||
206 | |||||
207 | if ( my $found = $document->find( 'PPI::Statement::Include' ) ) { | ||||
208 | foreach my $usage ( @{ $found } ) { | ||||
209 | 'overload' eq $usage->module() or next; | ||||
210 | my $inx; | ||||
211 | foreach my $arg ( _get_include_arguments( $usage ) ) { | ||||
212 | $inx++ % 2 or next; | ||||
213 | @{ $arg } == 1 or next; | ||||
214 | my $element = $arg->[0]; | ||||
215 | |||||
216 | if ( $element->isa( 'PPI::Token::Quote' ) ) { | ||||
217 | $element->string() eq $name and return $TRUE; | ||||
218 | } elsif ( $element->isa( 'PPI::Token::Word' ) ) { | ||||
219 | $element->content() eq $name and return $TRUE; | ||||
220 | } | ||||
221 | } | ||||
222 | } | ||||
223 | } | ||||
224 | |||||
225 | return; | ||||
226 | } | ||||
227 | |||||
228 | # Find things of the form '&_foo'. This includes both references proper (i.e. | ||||
229 | # '\&foo'), calls using the sigil, and gotos. The latter two do not count if | ||||
230 | # inside the subroutine itself. | ||||
231 | sub _find_sub_reference_in_document { | ||||
232 | my ( $self, $elem, $document ) = @_; | ||||
233 | |||||
234 | my $start_token = $elem->first_token(); | ||||
235 | my $finish_token = $elem->last_token(); | ||||
236 | my $symbol = q<&> . $elem->name(); | ||||
237 | |||||
238 | if ( my $found = $document->find( 'PPI::Token::Symbol' ) ) { | ||||
239 | foreach my $usage ( @{ $found } ) { | ||||
240 | $symbol eq $usage->content() or next; | ||||
241 | |||||
242 | my $prior = $usage->sprevious_sibling(); | ||||
243 | $prior | ||||
244 | and $prior->isa( 'PPI::Token::Cast' ) | ||||
245 | and q<\\> eq $prior->content() | ||||
246 | and return $TRUE; | ||||
247 | |||||
248 | is_function_call( $usage ) | ||||
249 | or $prior | ||||
250 | and $prior->isa( 'PPI::Token::Word' ) | ||||
251 | and 'goto' eq $prior->content() | ||||
252 | or next; | ||||
253 | |||||
254 | _compare_token_locations( $usage, $start_token ) < 0 | ||||
255 | and return $TRUE; | ||||
256 | _compare_token_locations( $finish_token, $usage ) < 0 | ||||
257 | and return $TRUE; | ||||
258 | } | ||||
259 | } | ||||
260 | |||||
261 | return; | ||||
262 | } | ||||
263 | |||||
264 | # Expand the given element, losing any brackets along the way. This is | ||||
265 | # intended to be used to flatten the argument list of 'use overload'. | ||||
266 | sub _expand_element { | ||||
267 | my ( $element ) = @_; | ||||
268 | $element->isa( 'PPI::Node' ) | ||||
269 | and return ( map { _expand_element( $_ ) } $_->children() ); | ||||
270 | $element->significant() and return $element; | ||||
271 | return; | ||||
272 | } | ||||
273 | |||||
274 | # Given an include statement, return its arguments. The return is a flattened | ||||
275 | # list of lists of tokens, each list of tokens representing an argument. | ||||
276 | sub _get_include_arguments { | ||||
277 | my ($include) = @_; | ||||
278 | |||||
279 | # If there are no arguments, just return. We flatten the list because | ||||
280 | # someone might use parens to define it. | ||||
281 | my @arguments = map { _expand_element( $_ ) } $include->arguments() | ||||
282 | or return; | ||||
283 | |||||
284 | my @elements; | ||||
285 | my $inx = 0; | ||||
286 | foreach my $element ( @arguments ) { | ||||
287 | if ( $element->isa( 'PPI::Token::Operator' ) && | ||||
288 | $IS_COMMA{$element->content()} ) { | ||||
289 | $inx++; | ||||
290 | } else { | ||||
291 | push @{ $elements[$inx] ||= [] }, $element; | ||||
292 | } | ||||
293 | } | ||||
294 | |||||
295 | return @elements; | ||||
296 | } | ||||
297 | |||||
298 | 1 | 4µs | 1; | ||
299 | |||||
300 | __END__ | ||||
# spent 2µs within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::CORE:qr which was called:
# once (2µs+0s) by Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::_parse_private_name_regex at line 67 | |||||
# spent 8µs within Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::CORE:regcomp which was called:
# once (8µs+0s) by Perl::Critic::Policy::Subroutines::ProhibitUnusedPrivateSubroutines::_parse_private_name_regex at line 67 |