File Coverage

blib/lib/Perl/Critic/Utils/PPI.pm
Criterion Covered Total %
statement 65 84 77.3
branch 39 68 57.3
condition 6 21 28.5
subroutine 15 17 88.2
pod 10 10 100.0
total 135 200 67.5


line stmt bran cond sub pod time code
1             package Perl::Critic::Utils::PPI;
2              
3 40     40   124277 use 5.010001;
  40         227  
4 40     40   238 use strict;
  40         114  
  40         794  
5 40     40   209 use warnings;
  40         88  
  40         919  
6              
7 40     40   737 use Readonly;
  40         4192  
  40         1815  
8              
9 40     40   256 use Scalar::Util qw< blessed >;
  40         97  
  40         1685  
10              
11 40     40   282 use Exporter 'import';
  40         99  
  40         44796  
12              
13             our $VERSION = '1.150';
14              
15             #-----------------------------------------------------------------------------
16              
17             our @EXPORT_OK = qw(
18             is_ppi_expression_or_generic_statement
19             is_ppi_generic_statement
20             is_ppi_statement_subclass
21             is_ppi_simple_statement
22             is_ppi_constant_element
23             is_subroutine_declaration
24             is_in_subroutine
25             get_constant_name_element_from_declaring_statement
26             get_next_element_in_same_simple_statement
27             get_previous_module_used_on_same_line
28             );
29              
30             our %EXPORT_TAGS = (
31             all => \@EXPORT_OK,
32             );
33              
34             #-----------------------------------------------------------------------------
35              
36             sub is_ppi_expression_or_generic_statement {
37 300     300 1 2685 my $element = shift;
38              
39 300 100       1550 return if not $element;
40 299 100       758 return if not $element->isa('PPI::Statement');
41 298 100       825 return 1 if $element->isa('PPI::Statement::Expression');
42              
43 208         476 my $element_class = blessed($element);
44              
45 208 50       372 return if not $element_class;
46 208         634 return $element_class eq 'PPI::Statement';
47             }
48              
49             #-----------------------------------------------------------------------------
50              
51             sub is_ppi_generic_statement {
52 65     65 1 393 my $element = shift;
53              
54 65         164 my $element_class = blessed($element);
55              
56 65 100       151 return if not $element_class;
57 64 100       193 return if not $element->isa('PPI::Statement');
58              
59 41         149 return $element_class eq 'PPI::Statement';
60             }
61              
62             #-----------------------------------------------------------------------------
63              
64             sub is_ppi_statement_subclass {
65 310     310 1 673 my $element = shift;
66              
67 310         640 my $element_class = blessed($element);
68              
69 310 100       579 return if not $element_class;
70 309 100       693 return if not $element->isa('PPI::Statement');
71              
72 308         937 return $element_class ne 'PPI::Statement';
73             }
74              
75             #-----------------------------------------------------------------------------
76              
77             # Can not use hashify() here because Perl::Critic::Utils already depends on
78             # this module.
79             Readonly::Hash my %SIMPLE_STATEMENT_CLASS => map { $_ => 1 } qw<
80             PPI::Statement
81             PPI::Statement::Break
82             PPI::Statement::Include
83             PPI::Statement::Null
84             PPI::Statement::Package
85             PPI::Statement::Variable
86             >;
87              
88             sub is_ppi_simple_statement {
89 189 50   189 1 536 my $element = shift or return;
90              
91 189 50       475 my $element_class = blessed( $element ) or return;
92              
93 189         667 return $SIMPLE_STATEMENT_CLASS{ $element_class };
94             }
95              
96             #-----------------------------------------------------------------------------
97              
98             sub is_ppi_constant_element {
99 27 50   27 1 98 my $element = shift or return;
100              
101 27 50       120 blessed( $element ) or return;
102              
103             # TODO implement here documents once PPI::Token::HereDoc grows the
104             # necessary PPI::Token::Quote interface.
105             return
106 27   0     170 $element->isa( 'PPI::Token::Number' )
107             || $element->isa( 'PPI::Token::Quote::Literal' )
108             || $element->isa( 'PPI::Token::Quote::Single' )
109             || $element->isa( 'PPI::Token::QuoteLike::Words' )
110             || (
111             $element->isa( 'PPI::Token::Quote::Double' )
112             || $element->isa( 'PPI::Token::Quote::Interpolate' ) )
113             && $element->string() !~ m< (?: \A | [^\\] ) (?: \\\\)* [\$\@] >smx
114             ;
115             }
116              
117             #-----------------------------------------------------------------------------
118              
119             sub is_subroutine_declaration {
120 54     54 1 7050 my $element = shift;
121              
122 54 100       114 return if not $element;
123              
124 53 100       193 return 1 if $element->isa('PPI::Statement::Sub');
125              
126 49 100       76 if ( is_ppi_generic_statement($element) ) {
127 4         15 my $first_element = $element->first_element();
128              
129 4 100 66     43 return 1 if
      66        
130             $first_element
131             and $first_element->isa('PPI::Token::Word')
132             and $first_element->content() eq 'sub';
133             }
134              
135 46         121 return;
136             }
137              
138             #-----------------------------------------------------------------------------
139              
140             sub is_in_subroutine {
141 15     15 1 8470 my ($element) = @_;
142              
143 15 100       54 return if not $element;
144 13 50       33 return 1 if is_subroutine_declaration($element);
145              
146 13         39 while ( $element = $element->parent() ) {
147 35 100       154 return 1 if is_subroutine_declaration($element);
148             }
149              
150 9         51 return;
151             }
152              
153             #-----------------------------------------------------------------------------
154              
155             sub get_constant_name_element_from_declaring_statement {
156 0     0 1 0 my ($element) = @_;
157              
158 0         0 warnings::warnif(
159             'deprecated',
160             'Perl::Critic::Utils::PPI::get_constant_name_element_from_declaring_statement() is deprecated. Use PPIx::Utils::Traversal::get_constant_name_elements_from_declaring_statement() instead.',
161             );
162              
163 0 0       0 return if not $element;
164 0 0       0 return if not $element->isa('PPI::Statement');
165              
166 0 0 0     0 if ( $element->isa('PPI::Statement::Include') ) {
    0          
167 0         0 my $pragma;
168 0 0 0     0 if ( $pragma = $element->pragma() and $pragma eq 'constant' ) {
169 0         0 return _constant_name_from_constant_pragma($element);
170             }
171             }
172             elsif (
173             is_ppi_generic_statement($element)
174             and $element->schild(0)->content() =~ m< \A Readonly \b >xms
175             ) {
176 0         0 return $element->schild(2);
177             }
178              
179 0         0 return;
180             }
181              
182             sub _constant_name_from_constant_pragma {
183 0     0   0 my ($include) = @_;
184              
185 0 0       0 my @arguments = $include->arguments() or return;
186              
187 0         0 my $follower = $arguments[0];
188 0 0       0 return if not defined $follower;
189              
190 0         0 return $follower;
191             }
192              
193             #-----------------------------------------------------------------------------
194              
195             sub get_next_element_in_same_simple_statement {
196 81 50   81 1 241 my $element = shift or return;
197              
198 81   33     330 while ( $element and (
      33        
199             not is_ppi_simple_statement( $element )
200             or $element->parent()
201             and $element->parent()->isa( 'PPI::Structure::List' ) ) ) {
202 81         700 my $next;
203 81 50       263 $next = $element->snext_sibling() and return $next;
204 0         0 $element = $element->parent();
205             }
206 0         0 return;
207              
208             }
209              
210             #-----------------------------------------------------------------------------
211              
212             sub get_previous_module_used_on_same_line {
213 27 50   27 1 117 my $element = shift or return;
214              
215 27 50       47 my ( $line ) = @{ $element->location() || []};
  27         106  
216              
217 27         382 while (not is_ppi_simple_statement( $element )) {
218 27 50       247 $element = $element->parent() or return;
219             }
220              
221 27         220 while ( $element = $element->sprevious_sibling() ) {
222 27 50       809 ( @{ $element->location() || []} )[0] == $line or return;
  27 50       67  
223 0 0         $element->isa( 'PPI::Statement::Include' )
224             and return $element->schild( 1 );
225             }
226              
227 0           return;
228             }
229              
230             #-----------------------------------------------------------------------------
231              
232             1;
233              
234             __END__
235              
236             =pod
237              
238             =for stopwords
239              
240             =head1 NAME
241              
242             Perl::Critic::Utils::PPI - Utility functions for dealing with PPI objects.
243              
244              
245             =head1 DESCRIPTION
246              
247             Provides classification of L<PPI::Elements|PPI::Elements>.
248              
249              
250             =head1 INTERFACE SUPPORT
251              
252             This is considered to be a public module. Any changes to its
253             interface will go through a deprecation cycle.
254              
255              
256             =head1 IMPORTABLE SUBS
257              
258             =over
259              
260             =item C<is_ppi_expression_or_generic_statement( $element )>
261              
262             Answers whether the parameter is an expression or an undifferentiated
263             statement. I.e. the parameter either is a
264             L<PPI::Statement::Expression|PPI::Statement::Expression> or the class
265             of the parameter is L<PPI::Statement|PPI::Statement> and not one of
266             its subclasses other than C<Expression>.
267              
268              
269             =item C<is_ppi_generic_statement( $element )>
270              
271             Answers whether the parameter is an undifferentiated statement, i.e.
272             the parameter is a L<PPI::Statement|PPI::Statement> but not one of its
273             subclasses.
274              
275              
276             =item C<is_ppi_statement_subclass( $element )>
277              
278             Answers whether the parameter is a specialized statement, i.e. the
279             parameter is a L<PPI::Statement|PPI::Statement> but the class of the
280             parameter is not L<PPI::Statement|PPI::Statement>.
281              
282              
283             =item C<is_ppi_simple_statement( $element )>
284              
285             Answers whether the parameter represents a simple statement, i.e. whether the
286             parameter is a L<PPI::Statement|PPI::Statement>,
287             L<PPI::Statement::Break|PPI::Statement::Break>,
288             L<PPI::Statement::Include|PPI::Statement::Include>,
289             L<PPI::Statement::Null|PPI::Statement::Null>,
290             L<PPI::Statement::Package|PPI::Statement::Package>, or
291             L<PPI::Statement::Variable|PPI::Statement::Variable>.
292              
293              
294             =item C<is_ppi_constant_element( $element )>
295              
296             Answers whether the parameter represents a constant value, i.e. whether the
297             parameter is a L<PPI::Token::Number|PPI::Token::Number>,
298             L<PPI::Token::Quote::Literal|PPI::Token::Quote::Literal>,
299             L<PPI::Token::Quote::Single|PPI::Token::Quote::Single>, or
300             L<PPI::Token::QuoteLike::Words|PPI::Token::QuoteLike::Words>, or is a
301             L<PPI::Token::Quote::Double|PPI::Token::Quote::Double> or
302             L<PPI::Token::Quote::Interpolate|PPI::Token::Quote::Interpolate> which does
303             not in fact contain any interpolated variables.
304              
305             This subroutine does B<not> interpret any form of here document as a constant
306             value, and may not until L<PPI::Token::HereDoc|PPI::Token::HereDoc> acquires
307             the relevant portions of the L<PPI::Token::Quote|PPI::Token::Quote> interface.
308              
309             This subroutine also does B<not> interpret entities created by the
310             L<Readonly|Readonly> module or the L<constant|constant> pragma as constants,
311             because the infrastructure to detect these appears not to be present, and the
312             author of this subroutine (B<not> Mr. Shank or Mr. Thalhammer) lacks the
313             knowledge/expertise/gumption to put it in place.
314              
315              
316             =item C<is_subroutine_declaration( $element )>
317              
318             Is the parameter a subroutine declaration, named or not?
319              
320              
321             =item C<is_in_subroutine( $element )>
322              
323             Is the parameter a subroutine or inside one?
324              
325              
326             =item C<get_constant_name_element_from_declaring_statement($statement)>
327              
328             B<This subroutine is deprecated.> You should use
329             L<PPIx::Utils::Traversal/get_constant_name_elements_from_declaring_statement()>
330             instead.
331              
332             Given a L<PPI::Statement|PPI::Statement>, if the statement is a C<use
333             constant> or L<Readonly|Readonly> declaration statement, return the name of
334             the thing being defined.
335              
336             Given
337              
338             use constant 1.16 FOO => 'bar';
339              
340             this will return "FOO". Similarly, given
341              
342             Readonly::Hash my %FOO => ( bar => 'baz' );
343              
344             this will return "%FOO".
345              
346             B<Caveat:> in the case where multiple constants are declared using the same
347             C<use constant> statement (e.g. C<< use constant { FOO => 1, BAR => 2 }; >>),
348             this subroutine will return the declaring
349             L<PPI::Structure::Constructor|PPI::Structure::Constructor>. In the case of
350             C<< use constant 1.16 { FOO => 1, BAR => 2 }; >> it may return a
351             L<PPI::Structure::Block|PPI::Structure::Block> instead of a
352             L<PPI::Structure::Constructor|PPI::Structure::Constructor>, due to a parse
353             error in L<PPI|PPI>.
354              
355              
356             =item C<get_next_element_in_same_simple_statement( $element )>
357              
358             Given a L<PPI::Element|PPI::Element>, this subroutine returns the next element
359             in the same simple statement as defined by is_ppi_simple_statement(). If no
360             next element can be found, this subroutine simply returns.
361              
362             If the $element is undefined or unblessed, we simply return.
363              
364             If the $element satisfies C<is_ppi_simple_statement()>, we return, B<unless>
365             it has a parent which is a L<PPI::Structure::List|PPI::Structure::List>.
366              
367             If the $element is the last significant element in its L<PPI::Node|PPI::Node>,
368             we replace it with its parent and iterate again.
369              
370             Otherwise, we return C<< $element->snext_sibling() >>.
371              
372              
373             =item C<get_previous_module_used_on_same_line( $element )>
374              
375             Given a L<PPI::Element|PPI::Element>, returns the L<PPI::Element|PPI::Element>
376             representing the name of the module included by the previous C<use> or
377             C<require> on the same line as the $element. If none is found, simply returns.
378              
379             For example, with the line
380              
381             use version; our $VERSION = ...;
382              
383             given the L<PPI::Token::Symbol|PPI::Token::Symbol> instance for C<$VERSION>, this will return
384             "version".
385              
386             If the given element is in a C<use> or <require>, the return is from the
387             previous C<use> or C<require> on the line, if any.
388              
389              
390             =back
391              
392              
393             =head1 AUTHOR
394              
395             Elliot Shank <perl@galumph.com>
396              
397              
398             =head1 COPYRIGHT
399              
400             Copyright (c) 2007-2011 Elliot Shank.
401              
402             This program is free software; you can redistribute it and/or modify
403             it under the same terms as Perl itself. The full text of this license
404             can be found in the LICENSE file included with this module.
405              
406             =cut
407              
408             # Local Variables:
409             # mode: cperl
410             # cperl-indent-level: 4
411             # fill-column: 78
412             # indent-tabs-mode: nil
413             # c-indentation-style: bsd
414             # End:
415             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :