File Coverage

blib/lib/Perl/MinimumVersion.pm
Criterion Covered Total %
statement 308 344 89.5
branch 185 252 73.4
condition 67 104 64.4
subroutine 60 69 86.9
pod 7 12 58.3
total 627 781 80.2


line stmt bran cond sub pod time code
1             package Perl::MinimumVersion;
2             $Perl::MinimumVersion::VERSION = '1.41'; # TRIAL
3             =pod
4              
5             =head1 NAME
6              
7             Perl::MinimumVersion - Find a minimum required version of perl for Perl code
8              
9             =head1 SYNOPSIS
10              
11             # Create the version checking object
12             $object = Perl::MinimumVersion->new( $filename );
13             $object = Perl::MinimumVersion->new( \$source );
14             $object = Perl::MinimumVersion->new( $ppi_document );
15              
16             # Find the minimum version
17             $version = $object->minimum_version;
18              
19             =head1 DESCRIPTION
20              
21             C takes Perl source code and calculates the minimum
22             version of perl required to be able to run it. Because it is based on
23             L, it can do this without having to actually load the code.
24              
25             Currently it tests both the syntax of your code, and the use of explicit
26             version dependencies such as C.
27              
28             Future plans are to also add support for tracing module dependencies.
29              
30             Using C is dead simple, the synopsis pretty much
31             covers it.
32              
33             The distribution comes with a script called L,
34             which is the easiest way to run C on your code:
35              
36             % perlver lib/Foo/Bar.pm
37              
38             See the L for more details.
39              
40             =head1 METHODS
41              
42             =cut
43              
44 14     14   1082468 use 5.006;
  14         188  
45 14     14   77 use strict;
  14         34  
  14         336  
46 14     14   66 use warnings;
  14         29  
  14         600  
47 14     14   5946 use version 0.76 ();
  14         25831  
  14         395  
48 14     14   92 use Carp ();
  14         28  
  14         190  
49 14     14   64 use Exporter ();
  14         27  
  14         373  
50 14     14   80 use List::Util 1.20 qw(max first);
  14         296  
  14         1764  
51 14     14   6550 use Params::Util 0.25 ('_INSTANCE', '_CLASS');
  14         85452  
  14         1007  
52 14     14   5867 use PPI::Util ('_Document');
  14         10459  
  14         808  
53 14     14   7005 use PPI 1.215 ();
  14         1442452  
  14         570  
54 14         3413 use PPIx::Utils qw{
55             :classification
56             :traversal
57 14     14   5911 };
  14         210675  
58 14     14   8412 use PPIx::Regexp 0.033;
  14         1720739  
  14         553  
59 14     14   6775 use Perl::MinimumVersion::Reason ();
  14         40  
  14         2869  
60              
61             our (@ISA, @EXPORT_OK, %CHECKS, @CHECKS_RV ,%MATCHES);
62             BEGIN {
63             # Export the PMV convenience constant
64 14     14   354 @ISA = 'Exporter';
65 14         60 @EXPORT_OK = 'PMV';
66              
67             # The primary list of version checks
68 14         522 %CHECKS = (
69             _heredoc_indent => version->new('5.025.007'),
70              
71             # _stacked_labels => version->new('5.014'),
72              
73             _yada_yada_yada => version->new('5.012'),
74             _pkg_name_version => version->new('5.012'),
75             _postfix_when => version->new('5.012'),
76             _perl_5012_pragmas => version->new('5.012'),
77             _while_readdir => version->new('5.012'),
78              
79             _perl_5010_pragmas => version->new('5.010'),
80             _perl_5010_operators => version->new('5.010'),
81             _perl_5010_magic => version->new('5.010'),
82             _state_declaration => version->new('5.010'),
83             );
84 14         55 @CHECKS_RV = ( #subs that return version
85             '_feature_bundle','_regex','_each_argument',,
86             '_scheduled_blocks', '_experimental_bundle'
87             );
88              
89             # Predefine some indexes needed by various check methods
90 14         66945 %MATCHES = (
91             _perl_5012_pragmas => {
92             deprecate => 1,
93             },
94             _perl_5010_pragmas => {
95             mro => 1,
96             feature => 1,
97             },
98             _perl_5010_operators => {
99             '//' => 1,
100             '//=' => 1,
101             '~~' => 1,
102             },
103             _perl_5010_magic => {
104             '%+' => 1,
105             '%-' => 1,
106             },
107             );
108             }
109              
110             sub PMV () { 'Perl::MinimumVersion' }
111              
112              
113              
114              
115              
116             #####################################################################
117             # Constructor
118              
119             =pod
120              
121             =head2 new
122              
123             # Create the version checking object
124             $object = Perl::MinimumVersion->new( $filename );
125             $object = Perl::MinimumVersion->new( \$source );
126             $object = Perl::MinimumVersion->new( $ppi_document );
127              
128             The C constructor creates a new version checking object for a
129             L. You can also provide the document to be read as a
130             file name, or as a C reference containing the code.
131              
132             Returns a new C object, or C on error.
133              
134             =cut
135              
136             sub new {
137 152 50   152 1 152378 my $class = ref $_[0] ? ref shift : shift;
138 152 100       495 my $Document = _Document(shift) or return undef;
139 149   33     445960 my $default = _INSTANCE(shift, 'version') || version->new('5.008');
140              
141             # Create the object
142 149         908 my $self = bless {
143             Document => $Document,
144              
145             # Checking limit and default minimum version.
146             # Explicitly don't check below this version.
147             default => $default,
148              
149             # Caches for resolved versions
150             explicit => undef,
151             syntax => undef,
152             external => undef,
153             }, $class;
154              
155 149         469 $self;
156             }
157              
158             =pod
159              
160             =head2 Document
161              
162             The C accessor can be used to get the L object
163             back out of the version checker.
164              
165             =cut
166              
167             sub Document {
168             $_[0]->{Document}
169 696     696 1 4249 }
170              
171              
172              
173              
174              
175             #####################################################################
176             # Main Methods
177              
178             =pod
179              
180             =head2 minimum_version
181              
182             The C method is the primary method for finding the
183             minimum perl version required based on C factors in the document.
184              
185             At the present time, this is just syntax and explicit version checks,
186             as L is not yet completed.
187              
188             Returns a L object, or C on error.
189              
190             =cut
191              
192             sub minimum_version {
193 35 50   35 1 5341 my $self = _SELF(\@_) or return undef;
194 35         87 my $minimum = $self->{default}; # Sensible default
195              
196             # Is the explicit version greater?
197 35         88 my $explicit = $self->minimum_explicit_version;
198 35 50       95 return undef unless defined $explicit;
199 35 100 100     122 if ( $explicit and $explicit > $minimum ) {
200 1         2 $minimum = $explicit;
201             }
202              
203             # Is the syntax version greater?
204             # Since this is the most expensive operation (for this file),
205             # we need to be careful we don't run things we don't need to.
206 35         107 my $syntax = $self->minimum_syntax_version;
207 35 50       85 return undef unless defined $syntax;
208 35 100 66     302 if ( $syntax and $syntax > $minimum ) {
209 17         56 $minimum = $syntax;
210             }
211              
212             ### FIXME - Disabled until minimum_external_version completed
213             # Is the external version greater?
214             #my $external = $self->minimum_external_version;
215             #return undef unless defined $external;
216             #if ( $external and $external > $minimum ) {
217             # $minimum = $external;
218             #}
219              
220 35         139 $minimum;
221             }
222              
223             sub minimum_reason {
224 0 0   0 0 0 my $self = _SELF(\@_) or return undef;
225 0         0 my $minimum = $self->default_reason; # Sensible default
226              
227             # Is the explicit version greater?
228 0         0 my $explicit = $self->minimum_explicit_version;
229 0 0       0 return undef unless defined $explicit;
230 0 0 0     0 if ( $explicit and $explicit > $minimum ) {
231 0         0 $minimum = $explicit;
232             }
233              
234             }
235              
236             sub default_reason {
237             Perl::MinimumVersion::Reason->new(
238             rule => 'default',
239             version => $_[0]->{default},
240 0     0 0 0 element => undef,
241             );
242             }
243              
244             =pod
245              
246             =head2 minimum_explicit_version
247              
248             The C method checks through Perl code for the
249             use of explicit version dependencies such as.
250              
251             use 5.008;
252             require 5.010;
253              
254             Although there is almost always only one of these in a file, if more than
255             one are found, the highest version dependency will be returned.
256              
257             Returns a L object, false if no dependencies could be found,
258             or C on error.
259              
260             =cut
261              
262             sub minimum_explicit_version {
263 36 50   36 1 80 my $self = _SELF(\@_) or return undef;
264 36         104 my $reason = $self->minimum_explicit_reason(@_);
265 36 100       117 return $reason ? $reason->version : $reason;
266             }
267              
268             sub minimum_explicit_reason {
269 36 50   36 0 87 my $self = _SELF(\@_) or return undef;
270 36 50       140 unless ( defined $self->{explicit} ) {
271 36         93 $self->{explicit} = $self->_minimum_explicit_version;
272             }
273 36         118 return $self->{explicit};
274             }
275              
276             sub _minimum_explicit_version {
277 36 50   36   93 my $self = shift or return undef;
278             my $explicit = $self->Document->find( sub {
279 422 100   422   5776 $_[1]->isa('PPI::Statement::Include') or return '';
280 16 100       59 $_[1]->version or return '';
281 4         117 1;
282 36         88 } );
283 36 100       614 return $explicit unless $explicit;
284              
285             # Find the highest version
286 3         5 my $max = undef;
287 3         7 my $element = undef;
288 3         29 foreach my $include ( @$explicit ) {
289 4         14 my $version = version->new($include->version);
290 4 50 66     138 if ( not $element or $version > $max ) {
291 4         19 $max = $version;
292 4         14 $element = $include;
293             }
294             }
295              
296 3         20 return Perl::MinimumVersion::Reason->new(
297             rule => 'explicit',
298             version => $max,
299             element => $element,
300             );
301             }
302              
303             =pod
304              
305             =head2 minimum_syntax_version $limit
306              
307             The C method will explicitly test only the
308             Document's syntax to determine it's minimum version, to the extent
309             that this is possible.
310              
311             It takes an optional parameter of a L object defining
312             the lowest known current value. For example, if it is already known
313             that it must be 5.010 or higher, then you can provide a param of
314             qv(5.010) and the method will not run any of the tests below this
315             version. This should provide dramatic speed improvements for
316             large and/or complex documents.
317              
318             The limitations of parsing Perl mean that this method may provide
319             artificially low results, but should not artificially high results.
320              
321             For example, if C returned 5.008, you can be
322             confident it will not run on anything lower, although there is a chance
323             that during actual execution it may use some untestable feature that
324             creates a dependency on a higher version.
325              
326             Returns a L object, false if no dependencies could be found,
327             or C on error.
328              
329             =cut
330              
331             sub minimum_syntax_version {
332 41 50   41 1 125 my $self = _SELF(\@_) or return undef;
333 41         135 my $reason = $self->minimum_syntax_reason(@_);
334 41 100       175 return $reason ? $reason->version : $reason;
335             }
336              
337             sub minimum_syntax_reason {
338 44 50   44 0 118 my $self = _SELF(\@_) or return undef;
339 44         82 my $limit = shift;
340 44 100 100     158 if ( defined $limit and not _INSTANCE($limit, 'version') ) {
341 1         27 $limit = version->new("$limit");
342             }
343 44 100       120 if ( defined $self->{syntax} ) {
344 5 100 100     26 if ( !defined($limit) or $self->{syntax}->version >= $limit ) {
345             # Previously discovered minimum is what they want
346 4         12 return $self->{syntax};
347             }
348              
349             # Rather than return a value BELOW their filter,
350             # which they would not be expecting, return false.
351 1         4 return '';
352             }
353              
354             # Look for the value
355 39         102 my $syntax = $self->_minimum_syntax_version( $limit );
356              
357             # If we found a value, it will be stable, cache it.
358             # If we did NOT, don't cache as subsequent runs without
359             # the filter may find a version.
360 39 100       129 if ( $syntax ) {
361 19         62 $self->{syntax} = $syntax;
362 19         51 return $self->{syntax};
363             }
364              
365 20         79 return '';
366             }
367              
368             #for Perl::Critic::Policy::Compatibility::PerlMinimumVersionAndWhy
369             sub _set_checks2skip {
370 1     1   7 my $self = shift;
371 1         2 my $list = shift;
372 1         3 $self->{_checks2skip} = $list;
373             }
374             sub _set_collect_all_reasons {
375 1     1   7 my $self = shift;
376 1         2 my $value = shift;
377 1 50       5 $value = 1 unless defined $value;
378 1         3 $self->{_collect_all_reasons} = $value;
379             }
380              
381             sub _minimum_syntax_version {
382 39     39   63 my $self = shift;
383 39   66     338 my $filter = shift || $self->{default};
384              
385 39         116 my %checks2skip;
386 39 100       76 @checks2skip{ @{ $self->{_checks2skip} || [] } } = ();
  39         163  
387              
388 39         88 my %rv_result;
389             my $current_reason;
390 39         94 foreach my $rule ( @CHECKS_RV ) {
391 195 100       448 next if exists $checks2skip{$rule};
392 194         563 my ($v, $obj) = $self->$rule();
393 194         1020 $v = version->new($v);
394 194 100       1108 if ( $v > $filter ) {
395 10         102 $current_reason = Perl::MinimumVersion::Reason->new(
396             rule => $rule,
397             version => $v,
398             element => _INSTANCE($obj, 'PPI::Element'),
399             );
400 10 100       48 if ($self->{_collect_all_reasons}) {
401 1         3 push @{ $self->{_all_reasons} }, $current_reason;
  1         4  
402             } else {
403 9         23 $filter = $v;
404             }
405             }
406             }
407              
408              
409             # Always check in descending version order.
410             # By doing it this way, the version of the first check that matches
411             # is also the version of the document as a whole.
412             my @rules = sort {
413 712         1675 $CHECKS{$b} <=> $CHECKS{$a}
414             } grep {
415 39 50       171 not(exists $checks2skip{$_}) and $CHECKS{$_} > $filter
  390         1776  
416             } keys %CHECKS;
417              
418 39         143 foreach my $rule ( @rules ) {
419 301 100       4199 my $result = $self->$rule() or next;
420              
421             # Create the result object
422             my $reason = Perl::MinimumVersion::Reason->new(
423             rule => $rule,
424 11         568 version => $CHECKS{$rule},
425             element => _INSTANCE($result, 'PPI::Element'),
426             );
427 11 50       45 if ($self->{_collect_all_reasons}) {
428 0         0 push @{ $self->{_all_reasons} }, $current_reason;
  0         0  
429             } else {
430 11         52 return $reason;
431             }
432              
433             }
434              
435             # Found nothing of interest
436 28   100     900 return $current_reason || '';
437             }
438              
439             =pod
440              
441             =head2 minimum_external_version
442              
443             B
444             an exception>
445              
446             The C examines code for dependencies on other
447             external files, and recursively traverses the dependency tree applying the
448             same tests to those files as it does to the original.
449              
450             Returns a C object, false if no dependencies could be found, or
451             C on error.
452              
453             =cut
454              
455             sub minimum_external_version {
456 0 0   0 1 0 my $self = _SELF(\@_) or return undef;
457 0         0 my $reason = $self->minimum_explicit_reason(@_);
458 0 0       0 return $reason ? $reason->version : $reason;
459             }
460              
461             sub minimum_external_reason {
462 0 0   0 0 0 my $self = _SELF(\@_) or return undef;
463 0 0       0 unless ( defined $self->{external} ) {
464 0         0 $self->{external} = $self->_minimum_external_version;
465             }
466 0         0 $self->{external};
467             }
468              
469             sub _minimum_external_version {
470 0     0   0 Carp::croak("Perl::MinimumVersion::minimum_external_version is not implemented");
471             }
472              
473             =pod
474              
475             =head2 version_markers
476              
477             This method returns a list of pairs in the form:
478              
479             ($version, \@markers)
480              
481             Each pair represents all the markers that could be found indicating that the
482             version was the minimum needed version. C<@markers> is an array of strings.
483             Currently, these strings are not as clear as they might be, but this may be
484             changed in the future. In other words: don't rely on them as specific
485             identifiers.
486              
487             =cut
488              
489             sub version_markers {
490 1 50   1 1 671 my $self = _SELF(\@_) or return undef;
491              
492 1         3 my %markers;
493              
494 1 50       5 if ( my $explicit = $self->minimum_explicit_version ) {
495 1         14 $markers{ $explicit } = [ 'explicit' ];
496             }
497              
498 1         8 foreach my $check ( keys %CHECKS ) {
499 10 100       120 next unless $self->$check();
500 1   50     49 my $markers = $markers{ $CHECKS{$check} } ||= [];
501 1         4 push @$markers, $check;
502             }
503              
504 1         15 my @rv;
505 1         4 my %marker_ver = map { $_ => version->new($_) } keys %markers;
  2         13  
506              
507 1         5 foreach my $ver ( sort { $marker_ver{$b} <=> $marker_ver{$a} } keys %markers ) {
  1         7  
508 2         7 push @rv, $marker_ver{$ver} => $markers{$ver};
509             }
510              
511 1         7 return @rv;
512             }
513              
514              
515              
516              
517             #####################################################################
518             # Version Check Methods
519              
520             my %feature =
521             (
522             'say' => '5.10',
523             'smartmatch' => '5.10',
524             'state' => '5.10',
525             'switch' => '5.10',
526             'unicode_strings' => '5.14',
527             'unicode_eval' => '5.16',
528             'evalbytes' => '5.16',
529             'current_sub' => '5.16',
530             'array_base' => '5.16', #defined only in 5.16
531             'fc' => '5.16',
532             'lexical_subs' => '5.18',
533             'postderef' => '5.20',
534             'postderef_qq' => '5.20',
535             'signatures' => '5.20',
536             'refaliasing' => '5.22',
537             'bitwise' => '5.22',
538             'declared_refs' => '5.26',
539             'isa' => '5.32',
540             'indirect' => '5.32', #defined only in 5.32
541             );
542             my $feature_regexp = join('|', keys %feature);
543              
544             #:5.14 means same as :5.12, but :5.14 is not defined in feature.pm in perl 5.12.
545             sub _feature_bundle {
546 63     63   155 my @versions;
547 63         105 my ($version, $obj);
548             shift->Document->find( sub {
549 603 100   603   7820 $_[1]->isa('PPI::Statement::Include') or return '';
550 40 100       126 $_[1]->pragma eq 'feature' or return '';
551 31         1088 my @child = $_[1]->schildren;
552 31         491 my @args = @child[1..$#child]; # skip 'use', 'feature' and ';'
553 31         68 foreach my $arg (@args) {
554 92         132 my $v = 0;
555 92 100       181 $v = $1 if ($arg->content =~ /:(5\.\d+)(?:\.\d+)?/);
556 92 100       486 $v = max($v, $feature{$1}) if ($arg->content =~ /\b($feature_regexp)\b/);
557             #
558 92 100 100     1246 if ($v and $v > ($version || 0) ) {
      100        
559 29         57 $version = $v;
560 29         63 $obj = $_[1];
561             }
562             }
563 31         88 return '';
564 63         134 } );
565 63 100       1255 return (defined($version)?"$version.0":undef, $obj);
566             }
567              
568             # list copied from experimental.pm v0.021 itself
569             my %experimental =
570             (
571             array_base => '5',
572             autoderef => '5.14',
573             bitwise => '5.22',
574             const_attr => '5.22',
575             current_sub => '5.16',
576             declared_refs => '5.26',
577             evalbytes => '5.16',
578             fc => '5.16',
579             isa => '5.32',
580             lexical_topic => '5.10',
581             lexical_subs => '5.18',
582             postderef => '5.20',
583             postderef_qq => '5.20',
584             refaliasing => '5.22',
585             regex_sets => '5.18',
586             say => '5.10',
587             smartmatch => '5.10',
588             signatures => '5.20',
589             state => '5.10',
590             switch => '5.10',
591             unicode_eval => '5.16',
592             unicode_strings => '5.12',
593             );
594             my $experimental_regexp = join('|', keys %experimental);
595             sub _experimental_bundle {
596 39     39   82 my ($version, $obj);
597              
598             shift->Document->find( sub {
599 422 100 100 422   5441 return '' unless $_[1]->isa('PPI::Statement::Include')
600             and $_[1]->pragma eq 'experimental';
601              
602 2         110 my @child = $_[1]->schildren;
603 2         41 my @args = @child[1..$#child]; # skip 'use', 'experimental' and ';'
604 2         5 foreach my $arg (@args) {
605 5         8 my $v = 0;
606 5 50       13 $v = $1 if ($arg->content =~ /:(5\.\d+)(?:\.\d+)?/);
607 5 100       28 $v = max($v, $experimental{$1}) if ($arg->content =~ /\b($experimental_regexp)\b/);
608              
609 5 100 50     212 if ($v and $v > ($version || 0) ) {
      66        
610 1         4 $version = $v;
611 1         3 $obj = $_[1];
612             }
613             }
614 2         6 return '';
615 39         107 } );
616              
617 39 100       674 return (defined($version)?"$version.0":undef, $obj);
618             }
619              
620             my %SCHEDULED_BLOCK =
621             (
622             'UNITCHECK' => '5.010',
623             );
624              
625             sub _scheduled_blocks
626             {
627 39     39   95 my @versions;
628 39         79 my ($version, $obj);
629              
630             shift->Document->find( sub {
631 422 100   422   4984 $_[1]->isa('PPI::Statement::Scheduled') or return '';
632 4 50       15 ($_[1]->children)[0]->isa('PPI::Token::Word') or return '';
633 4         50 my $function = (($_[1]->children)[0])->content;
634 4 100       35 exists( $SCHEDULED_BLOCK{ $function }) or return '';
635              
636 1         13 my $v = $SCHEDULED_BLOCK{ ($_[1]->children)[0]->content };
637 1 50 50     27 if ($v and $v > ($version || 0) ) {
      33        
638 1         2 $version = $v;
639 1         2 $obj = $_[1];
640             }
641              
642 1         4 return '';
643 39         106 } );
644 39 100       653 return (defined($version) ? $version : undef, $obj);
645             }
646              
647             sub _regex {
648 47     47   113 my $self = shift;
649 47         78 my @versions;
650 47         94 my ($version, $obj);
651             $self->Document->find( sub {
652             return '' unless
653 437 100   437   5371 grep { $_[1]->isa($_) }
  1311         4009  
654             qw/PPI::Token::QuoteLike::Regexp PPI::Token::Regexp::Match PPI::Token::Regexp::Substitute/;
655 13         72 my $re = PPIx::Regexp->new( $_[1] );
656 13         53683 my $v = $re->perl_version_introduced;
657 13 50 50     3874 if ($v and $v > ($version || 0) ) {
      33        
658 13         28 $version = $v;
659 13         26 $obj = $_[1];
660             }
661 13         64 return '';
662 47         108 } );
663 47         1727 my $tr_r_version = version->new('5.013.007');
664             $self->Document->find( sub {
665 437 100   437   5526 return '' unless
666             $_[1]->isa(q/PPI::Token::Regexp::Transliterate/);
667 2 50 50     12 if( exists $_[1]->get_modifiers->{r}
      33        
668             && $tr_r_version > ( $version || 0 )
669             ) {
670 2         52 $version = $tr_r_version;
671 2         4 $obj = $_[1];
672             }
673 2         6 return '';
674 47         125 } );
675 47 100 100     730 $version = undef if ($version and $version eq '5.000');
676 47         191 return ($version, $obj);
677             }
678              
679             sub _each_argument {
680 81     81   263 my ($version, $obj);
681             shift->Document->find( sub {
682 730 100   730   10652 $_[1]->isa('PPI::Token::Word') or return '';
683 109 100       323 $_[1]->content =~ '^(each|keys|values)$' or return '';
684 44 100       424 return '' if is_method_call($_[1]);
685 42         1488 my $next = $_[1]->snext_sibling;
686 42 100       927 $next = $next->schild(0)->schild(0) if $next->isa('PPI::Structure::List');
687 41 100       690 if($next->isa('PPI::Token::Cast')) {
    100          
    100          
    100          
688 4 100 50     11 if($next->content eq '@' && 5.012 > ($version || 0)) {
    50 66        
      0        
      33        
689 3         41 $version = 5.012;
690 3         10 $obj = $_[1]->parent;
691             } elsif($next->content eq '$' && 5.014 > ($version || 0)) {
692 0         0 $version = 5.014;
693 0         0 $obj = $_[1]->parent;
694             }
695             } elsif($next->isa('PPI::Token::Symbol')) {
696 28 100 100     90 if($next->raw_type eq '@' && 5.012 > ($version || 0)) {
    100 100        
      100        
      66        
697 7         70 $version = 5.012;
698 7         19 $obj = $_[1]->parent;
699             } elsif($next->raw_type eq '$' && 5.014 > ($version || 0)) {
700 14         210 $version = 5.014;
701 14         38 $obj = $_[1]->parent;
702             }
703             } elsif($next->isa('PPI::Token::Operator')) { # % $a
704 1         6 return '';
705             } elsif($_[1]->parent->isa('PPI::Statement::Sub')) { # sub each|keys|values
706 2         18 return '';
707             } else { # function call or other should be reference
708 6 50 50     60 if(5.014 > ($version || 0)) {
709 6         9 $version = 5.014;
710 6         13 $obj = $_[1]->parent;
711             }
712             }
713 38 100 100     340 return 1 if ($version and $version == 5.014);
714 17         40 return '';
715 81         198 } );
716 81 100       1790 return (defined($version)?"$version":undef, $obj);
717             }
718              
719             #Is string (first argument) in list (other arguments)
720             sub _str_in_list {
721 0     0   0 my $str = shift;
722 0         0 foreach my $s (@_) {
723 0 0       0 return 1 if $s eq $str;
724             }
725 0         0 return 0;
726             }
727              
728              
729              
730             #http://perldoc.perl.org/functions/readdir.html
731             #while(readdir $dh) requires perl 5.12
732             sub _while_readdir {
733             shift->Document->find_first( sub {
734 458 100   458   5802 $_[1]->isa('PPI::Token::Word') or return '';
735 58 100       155 $_[1]->content eq 'while' or return '';
736 8 50       63 return '' if is_hash_key($_[1]);
737 8 50       606 return '' if is_method_call($_[1]);
738 8 100       228 my $e1 = $_[1]->next_sibling or return '';
739 7 50       138 if ($e1->isa('PPI::Structure::Condition')) { #while ()
740 7         21 my @children = $e1->children;
741 7         49 $e1 = $children[0];
742             }
743 7 50       23 $e1->isa('PPI::Statement::Expression') or return '';
744 7         21 my @children = $e1->schildren;
745 7         90 $e1 = $children[0];
746              
747 7 100       36 $e1->isa('PPI::Token::Word') or return '';
748 6 100       21 $e1->content eq 'readdir' or return '';
749 5 50       24 return 1 if @children == 1; #incorrect call
750 5 100       15 return '' if @children > 2; #not only readdir
751 3         7 $e1 = $children[1];
752 3 50 66     20 $e1->isa('PPI::Structure::List') or $e1->isa('PPI::Token::Symbol') or return '';
753             #readdir($dh) or readdir $dh
754              
755 3         13 return 1;
756 41     41   131 } );
757             }
758              
759             sub _perl_5012_pragmas {
760             shift->Document->find_first( sub {
761             $_[1]->isa('PPI::Statement::Include')
762             and
763 300 100   300   4059 $MATCHES{_perl_5012_pragmas}->{$_[1]->pragma}
764 33     33   97 } );
765             }
766              
767             sub _get_resulting_sigil {
768 0     0   0 my $elem = shift;
769 0 0       0 if ($elem->isa('PPI::Token::Cast')) {
    0          
770 0         0 return $elem->content;
771             } elsif ($elem->isa('PPI::Token::Symbol')) {
772 0         0 return $elem->symbol_type;
773             } else {
774 0         0 return undef;
775             }
776             }
777              
778             sub _heredoc_indent {
779             shift->Document->find_first( sub {
780 433     433   4451 my $main_element = $_[1];
781 433 100       1402 $main_element->isa('PPI::Token::HereDoc') or return '';
782 2 100       12 $main_element->content =~ /^\Q<<~\E/ or return '';
783 1         8 return 1;
784 40     40   115 });
785             }
786              
787             sub _postfix_when {
788             shift->Document->find_first( sub {
789 403     403   4279 my $main_element=$_[1];
790 403 100       1258 $main_element->isa('PPI::Token::Word') or return '';
791 48 100       159 $main_element->content eq 'when' or return '';
792 5 50       35 return '' if is_hash_key($main_element);
793 5 50       414 return '' if is_method_call($main_element);
794 5 50       197 return '' if is_subroutine_name($main_element);
795 5 50       201 return '' if is_included_module_name($main_element);
796 5 50       132 return '' if is_package_declaration($main_element);
797 5         143 my $stmnt = $main_element->statement();
798 5 50       68 return '' if !$stmnt;
799 5 100       24 return '' if $stmnt->isa('PPI::Statement::When');
800 3         8 return 1;
801 37     37   113 } );
802             }
803              
804             sub _yada_yada_yada {
805             shift->Document->find_first( sub {
806 430 100 100 430   5522 $_[1]->isa('PPI::Token::Operator')
807             and $_[1]->content eq '...' or return '';
808 8         69 my @child = $_[1]->parent->schildren;
809 8 100       492 @child == 1 and return 1;
810 3 100       12 if (@child == 2) {
811 1         7 $child[1]->isa('PPI::Token::Structure')
812             }
813 42     42   136 } );
814             }
815              
816             sub _state_declaration {
817             shift->Document->find_first( sub {
818 271 100 66 271   3334 $_[1]->isa('PPI::Statement::Variable')
819             and ($_[1]->children)[0]->isa('PPI::Token::Word')
820             and ($_[1]->children)[0]->content eq 'state'
821 28     28   116 } );
822             }
823              
824             sub _stacked_labels {
825             shift->Document->find_first( sub {
826 0 0   0   0 $_[1]->isa('PPI::Statement::Compound') || return '';
827 0 0       0 $_[1]->schild(0)->isa('PPI::Token::Label') || return '';
828              
829 0   0     0 my $next = $_[1]->snext_sibling || return '';
830              
831 0 0 0     0 if ( $next->isa('PPI::Statement::Compound')
832             && $next->schild(0)->isa('PPI::Token::Label')) {
833 0         0 return 1;
834             }
835              
836 0         0 0;
837 0     0   0 } );
838             }
839              
840             sub _pkg_name_version {
841             shift->Document->find_first( sub {
842 404 100   404   4766 $_[1]->isa('PPI::Statement::Package') or return '';
843 9         25 my @child = $_[1]->schildren();
844 9 50       136 $child[0]->isa('PPI::Token::Word') or return '';
845 9 50       36 $child[0]->content eq 'package' or return '';
846 9 50       61 $child[1]->isa('PPI::Token::Word') or return '';
847 9 100       38 $child[2]->isa('PPI::Token::Number') or return '';
848 6         13 return 1;
849 43     43   140 } );
850             }
851              
852             sub _perl_5010_pragmas {
853             shift->Document->find_first( sub {
854             $_[1]->isa('PPI::Statement::Include')
855             and
856 225 100   225   2977 $MATCHES{_perl_5010_pragmas}->{$_[1]->pragma}
857 27     27   623 } );
858             }
859              
860             sub _perl_5010_operators {
861             shift->Document->find_first( sub {
862             $_[1]->isa('PPI::Token::Operator')
863             and
864 284 100   284   3526 $MATCHES{_perl_5010_operators}->{$_[1]->content}
865 26     26   96 } );
866             }
867              
868             sub _perl_5010_magic {
869             shift->Document->find_first( sub {
870             $_[1]->isa('PPI::Token::Magic')
871             and
872 290 100   290   3519 $MATCHES{_perl_5010_magic}->{$_[1]->symbol}
873 27     27   100 } );
874             }
875              
876             #####################################################################
877             # Support Functions
878              
879             # Let sub be a function, object method, and static method
880             sub _SELF {
881 193     193   287 my $param = shift;
882 193 100       939 if ( _INSTANCE($param->[0], 'Perl::MinimumVersion') ) {
883 191         634 return shift @$param;
884             }
885 2 50 33     17 if (
886             _CLASS($param->[0])
887             and
888             $param->[0]->isa('Perl::MinimumVersion')
889             ) {
890 2         39 my $class = shift @$param;
891 2         7 my $options = shift @$param;
892 2         7 return $class->new($options);
893             }
894 0         0 Perl::MinimumVersion->new(shift @$param);
895             }
896              
897             # Find the maximum version, ignoring problems
898             sub _max {
899 18 100 100 18   1026 defined $_[0] and "$_[0]" eq PMV and shift;
900              
901             # Filter and prepare for a Schwartian maximum
902             my @valid = map {
903 26 50       113 [ $_, $_->isa('Perl::MinimumVersion::Reason') ? $_->version : $_ ]
904             } grep {
905 18 50       54 _INSTANCE($_, 'Perl::MinimumVersion::Reason')
  36 100       547  
906             or
907             _INSTANCE($_, 'version')
908             } @_ or return '';
909              
910             # Find the maximum
911 12         25 my $max = shift @valid;
912 12         26 foreach my $it ( @valid ) {
913 14 100       66 $max = $it if $it->[1] > $max->[1];
914             }
915              
916 12         151 return $max->[0];
917             }
918              
919             1;
920              
921             =pod
922              
923             =head1 BUGS
924              
925             B does a reasonable job of catching the best-known
926             explicit version dependencies.
927              
928             B it is exceedingly easy to add a new syntax check, so if you
929             find something this is missing, copy and paste one of the existing
930             5 line checking functions, modify it to find what you want, and report it
931             to rt.cpan.org, along with the version needed.
932              
933             I don't even need an entire diff... just the function and version.
934              
935             =head1 TO DO
936              
937             B
938              
939             - Perl 5.10 operators and language structures
940              
941             - Three-argument open
942              
943             B
944              
945             B
946              
947             _while_readdir for postfix while without brackets
948              
949             B
950             C, C<...>, and C)>
951              
952             =head1 SUPPORT
953              
954             All bugs should be filed via the CPAN bug tracker at
955              
956             L
957              
958             For other issues, or commercial enhancement or support, contact the author.
959              
960             =head1 AUTHORS
961              
962             Adam Kennedy Eadamk@cpan.orgE
963              
964             =head1 SEE ALSO
965              
966             L - the command-line script for running C
967             on your code.
968              
969             L - another module which does the same thing.
970             It's a lot faster, but only supports Perl 5.8.1+.
971              
972             L, L, L
973              
974             =head1 REPOSITORY
975              
976             L
977              
978             =head1 COPYRIGHT
979              
980             Copyright 2005 - 2014 Adam Kennedy.
981              
982             This program is free software; you can redistribute
983             it and/or modify it under the same terms as Perl itself.
984              
985             The full text of the license can be found in the
986             LICENSE file included with this module.
987              
988             =cut