Hide Show 41 lines of Pod
$Perl::MinimumVersion::VERSION
=
'1.40'
;
use
5.006;
:classification
:traversal
}
;
our
(
@ISA
,
@EXPORT_OK
,
%CHECKS
,
@CHECKS_RV
,
%MATCHES
);
BEGIN {
@ISA
=
'Exporter'
;
@EXPORT_OK
=
'PMV'
;
%CHECKS
= (
_yada_yada_yada
=> version->new(
'5.012'
),
_pkg_name_version
=> version->new(
'5.012'
),
_postfix_when
=> version->new(
'5.012'
),
_perl_5012_pragmas
=> version->new(
'5.012'
),
_while_readdir
=> version->new(
'5.012'
),
_perl_5010_pragmas
=> version->new(
'5.010'
),
_perl_5010_operators
=> version->new(
'5.010'
),
_perl_5010_magic
=> version->new(
'5.010'
),
_state_declaration
=> version->new(
'5.010'
),
_bugfix_magic_errno
=> version->new(
'5.008.003'
),
_is_utf8
=> version->new(
'5.008.001'
),
_unquoted_versions
=> version->new(
'5.008.001'
),
_perl_5008_pragmas
=> version->new(
'5.008'
),
_constant_hash
=> version->new(
'5.008'
),
_local_soft_reference
=> version->new(
'5.008'
),
_use_carp_version
=> version->new(
'5.008'
),
_open_temp
=> version->new(
'5.008'
),
_open_scalar
=> version->new(
'5.008'
),
_internals_svreadonly
=> version->new(
'5.008'
),
_pragma_utf8
=> version->new(
'5.008'
),
_perl_5006_pragmas
=> version->new(
'5.006'
),
_any_our_variables
=> version->new(
'5.006'
),
_any_binary_literals
=> version->new(
'5.006'
),
_any_version_literals
=> version->new(
'5.006'
),
_magic_version
=> version->new(
'5.006'
),
_any_attributes
=> version->new(
'5.006'
),
_any_CHECK_blocks
=> version->new(
'5.006'
),
_three_argument_open
=> version->new(
'5.006'
),
_weaken
=> version->new(
'5.006'
),
_mkdir_1_arg
=> version->new(
'5.006'
),
_exists_subr
=> version->new(
'5.006'
),
_sort_subref
=> version->new(
'5.006'
),
_any_qr_tokens
=> version->new(
'5.005.03'
),
_perl_5005_pragmas
=> version->new(
'5.005'
),
_perl_5005_modules
=> version->new(
'5.005'
),
_any_tied_arrays
=> version->new(
'5.005'
),
_any_quotelike_regexp
=> version->new(
'5.005'
),
_any_INIT_blocks
=> version->new(
'5.005'
),
_substr_4_arg
=> version->new(
'5.005'
),
_splice_negative_length
=> version->new(
'5.005'
),
_5005_variables
=> version->new(
'5.005'
),
_bareword_double_colon
=> version->new(
'5.005'
),
_postfix_foreach
=> version->new(
'5.004.05'
),
);
@CHECKS_RV
= (
'_feature_bundle'
,
'_regex'
,
'_each_argument'
,
'_binmode_2_arg'
,
'_scheduled_blocks'
,
'_experimental_bundle'
);
%MATCHES
= (
_perl_5012_pragmas
=> {
deprecate
=> 1,
},
_perl_5010_pragmas
=> {
mro
=> 1,
feature
=> 1,
},
_perl_5010_operators
=> {
'//'
=> 1,
'//='
=> 1,
'~~'
=> 1,
},
_perl_5010_magic
=> {
'%+'
=> 1,
'%-'
=> 1,
},
_perl_5008_pragmas
=> {
threads
=> 1,
'threads::shared'
=> 1,
sort
=> 1,
encoding
=> 1,
},
_perl_5006_pragmas
=> {
warnings
=> 1,
'warnings::register'
=> 1,
attributes
=> 1,
open
=> 1,
filetest
=> 1,
charnames
=> 1,
bytes
=> 1,
},
_perl_5005_pragmas
=> {
re
=> 1,
fields
=> 1,
attr
=> 1,
},
);
}
sub
PMV () {
'Perl::MinimumVersion'
}
Hide Show 17 lines of Pod
sub
new {
my
$class
=
ref
$_
[0] ?
ref
shift
:
shift
;
my
$Document
= _Document(
shift
) or
return
undef
;
my
$default
= _INSTANCE(
shift
,
'version'
) || version->new(
'5.004'
);
my
$self
=
bless
{
Document
=>
$Document
,
default
=>
$default
,
explicit
=>
undef
,
syntax
=>
undef
,
external
=>
undef
,
},
$class
;
$self
;
}
Hide Show 9 lines of Pod
sub
Document {
$_
[0]->{Document}
}
Hide Show 14 lines of Pod
sub
minimum_version {
my
$self
= _SELF(\
@_
) or
return
undef
;
my
$minimum
=
$self
->{
default
};
my
$explicit
=
$self
->minimum_explicit_version;
return
undef
unless
defined
$explicit
;
if
(
$explicit
and
$explicit
>
$minimum
) {
$minimum
=
$explicit
;
}
my
$syntax
=
$self
->minimum_syntax_version;
return
undef
unless
defined
$syntax
;
if
(
$syntax
and
$syntax
>
$minimum
) {
$minimum
=
$syntax
;
}
$minimum
;
}
sub
minimum_reason {
my
$self
= _SELF(\
@_
) or
return
undef
;
my
$minimum
=
$self
->default_reason;
my
$explicit
=
$self
->minimum_explicit_version;
return
undef
unless
defined
$explicit
;
if
(
$explicit
and
$explicit
>
$minimum
) {
$minimum
=
$explicit
;
}
}
sub
default_reason {
Perl::MinimumVersion::Reason->new(
rule
=>
'default'
,
version
=>
$_
[0]->{
default
},
element
=>
undef
,
);
}
Hide Show 18 lines of Pod
sub
minimum_explicit_version {
my
$self
= _SELF(\
@_
) or
return
undef
;
my
$reason
=
$self
->minimum_explicit_reason(
@_
);
return
$reason
?
$reason
->version :
$reason
;
}
sub
minimum_explicit_reason {
my
$self
= _SELF(\
@_
) or
return
undef
;
unless
(
defined
$self
->{explicit} ) {
$self
->{explicit} =
$self
->_minimum_explicit_version;
}
return
$self
->{explicit};
}
sub
_minimum_explicit_version {
my
$self
=
shift
or
return
undef
;
my
$explicit
=
$self
->Document->find(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
) or
return
''
;
$_
[1]->version or
return
''
;
1;
} );
return
$explicit
unless
$explicit
;
my
$max
=
undef
;
my
$element
=
undef
;
foreach
my
$include
(
@$explicit
) {
my
$version
= version->new(
$include
->version);
if
( not
$element
or
$version
>
$max
) {
$max
=
$version
;
$element
=
$include
;
}
}
return
Perl::MinimumVersion::Reason->new(
rule
=>
'explicit'
,
version
=>
$max
,
element
=>
$element
,
);
}
Hide Show 28 lines of Pod
sub
minimum_syntax_version {
my
$self
= _SELF(\
@_
) or
return
undef
;
my
$reason
=
$self
->minimum_syntax_reason(
@_
);
return
$reason
?
$reason
->version :
$reason
;
}
sub
minimum_syntax_reason {
my
$self
= _SELF(\
@_
) or
return
undef
;
my
$limit
=
shift
;
if
(
defined
$limit
and not _INSTANCE(
$limit
,
'version'
) ) {
$limit
= version->new(
"$limit"
);
}
if
(
defined
$self
->{syntax} ) {
if
( !
defined
(
$limit
) or
$self
->{syntax}->version >=
$limit
) {
return
$self
->{syntax};
}
return
''
;
}
my
$syntax
=
$self
->_minimum_syntax_version(
$limit
);
if
(
$syntax
) {
$self
->{syntax} =
$syntax
;
return
$self
->{syntax};
}
return
''
;
}
sub
_set_checks2skip {
my
$self
=
shift
;
my
$list
=
shift
;
$self
->{_checks2skip} =
$list
;
}
sub
_set_collect_all_reasons {
my
$self
=
shift
;
my
$value
=
shift
;
$value
= 1
unless
defined
$value
;
$self
->{_collect_all_reasons} =
$value
;
}
sub
_minimum_syntax_version {
my
$self
=
shift
;
my
$filter
=
shift
||
$self
->{
default
};
my
%checks2skip
;
@checks2skip
{ @{
$self
->{_checks2skip} || [] } } = ();
my
%rv_result
;
my
$current_reason
;
foreach
my
$rule
(
@CHECKS_RV
) {
next
if
exists
$checks2skip
{
$rule
};
my
(
$v
,
$obj
) =
$self
->
$rule
();
$v
= version->new(
$v
);
if
(
$v
>
$filter
) {
$current_reason
= Perl::MinimumVersion::Reason->new(
rule
=>
$rule
,
version
=>
$v
,
element
=> _INSTANCE(
$obj
,
'PPI::Element'
),
);
if
(
$self
->{_collect_all_reasons}) {
push
@{
$self
->{_all_reasons} },
$current_reason
;
}
else
{
$filter
=
$v
;
}
}
}
my
@rules
=
sort
{
$CHECKS
{
$b
} <=>
$CHECKS
{
$a
}
}
grep
{
not(
exists
$checks2skip
{
$_
}) and
$CHECKS
{
$_
} >
$filter
}
keys
%CHECKS
;
foreach
my
$rule
(
@rules
) {
my
$result
=
$self
->
$rule
() or
next
;
my
$reason
= Perl::MinimumVersion::Reason->new(
rule
=>
$rule
,
version
=>
$CHECKS
{
$rule
},
element
=> _INSTANCE(
$result
,
'PPI::Element'
),
);
if
(
$self
->{_collect_all_reasons}) {
push
@{
$self
->{_all_reasons} },
$current_reason
;
}
else
{
return
$reason
;
}
}
return
$current_reason
||
''
;
}
Hide Show 16 lines of Pod
sub
minimum_external_version {
my
$self
= _SELF(\
@_
) or
return
undef
;
my
$reason
=
$self
->minimum_explicit_reason(
@_
);
return
$reason
?
$reason
->version :
$reason
;
}
sub
minimum_external_reason {
my
$self
= _SELF(\
@_
) or
return
undef
;
unless
(
defined
$self
->{external} ) {
$self
->{external} =
$self
->_minimum_external_version;
}
$self
->{external};
}
sub
_minimum_external_version {
Carp::croak(
"Perl::MinimumVersion::minimum_external_version is not implemented"
);
}
Hide Show 16 lines of Pod
sub
version_markers {
my
$self
= _SELF(\
@_
) or
return
undef
;
my
%markers
;
if
(
my
$explicit
=
$self
->minimum_explicit_version ) {
$markers
{
$explicit
} = [
'explicit'
];
}
foreach
my
$check
(
keys
%CHECKS
) {
next
unless
$self
->
$check
();
my
$markers
=
$markers
{
$CHECKS
{
$check
} } ||= [];
push
@$markers
,
$check
;
}
my
@rv
;
my
%marker_ver
=
map
{
$_
=> version->new(
$_
) }
keys
%markers
;
foreach
my
$ver
(
sort
{
$marker_ver
{
$b
} <=>
$marker_ver
{
$a
} }
keys
%markers
) {
push
@rv
,
$marker_ver
{
$ver
} =>
$markers
{
$ver
};
}
return
@rv
;
}
my
%feature
=
(
'say'
=>
'5.10'
,
'smartmatch'
=>
'5.10'
,
'state'
=>
'5.10'
,
'switch'
=>
'5.10'
,
'unicode_strings'
=>
'5.14'
,
'unicode_eval'
=>
'5.16'
,
'evalbytes'
=>
'5.16'
,
'current_sub'
=>
'5.16'
,
'array_base'
=>
'5.16'
,
'fc'
=>
'5.16'
,
'lexical_subs'
=>
'5.18'
,
'postderef'
=>
'5.20'
,
'postderef_qq'
=>
'5.20'
,
'signatures'
=>
'5.20'
,
'refaliasing'
=>
'5.22'
,
'bitwise'
=>
'5.22'
,
'declared_refs'
=>
'5.26'
,
'isa'
=>
'5.32'
,
'indirect'
=>
'5.32'
,
);
my
$feature_regexp
=
join
(
'|'
,
keys
%feature
);
sub
_feature_bundle {
my
@versions
;
my
(
$version
,
$obj
);
shift
->Document->find(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
) or
return
''
;
$_
[1]->pragma eq
'feature'
or
return
''
;
my
@child
=
$_
[1]->schildren;
my
@args
=
@child
[1..
$#child
]; # skip
'use'
,
'feature'
and
';'
foreach
my
$arg
(
@args
) {
my
$v
= 0;
$v
= $1
if
(
$arg
->content =~ /:(5\.\d+)(?:\.\d+)?/);
$v
= max(
$v
,
$feature
{$1})
if
(
$arg
->content =~ /\b(
$feature_regexp
)\b/);
if
(
$v
and
$v
> (
$version
|| 0) ) {
$version
=
$v
;
$obj
=
$_
[1];
}
}
return
''
;
} );
return
(
defined
(
$version
)?
"$version.0"
:
undef
,
$obj
);
}
my
%experimental
=
(
array_base
=>
'5'
,
autoderef
=>
'5.14'
,
bitwise
=>
'5.22'
,
const_attr
=>
'5.22'
,
current_sub
=>
'5.16'
,
declared_refs
=>
'5.26'
,
evalbytes
=>
'5.16'
,
fc
=>
'5.16'
,
isa
=>
'5.32'
,
lexical_topic
=>
'5.10'
,
lexical_subs
=>
'5.18'
,
postderef
=>
'5.20'
,
postderef_qq
=>
'5.20'
,
refaliasing
=>
'5.22'
,
regex_sets
=>
'5.18'
,
say
=>
'5.10'
,
smartmatch
=>
'5.10'
,
signatures
=>
'5.20'
,
state
=>
'5.10'
,
switch
=>
'5.10'
,
unicode_eval
=>
'5.16'
,
unicode_strings
=>
'5.12'
,
);
my
$experimental_regexp
=
join
(
'|'
,
keys
%experimental
);
sub
_experimental_bundle {
my
(
$version
,
$obj
);
shift
->Document->find(
sub
{
return
''
unless
$_
[1]->isa(
'PPI::Statement::Include'
)
and
$_
[1]->pragma eq
'experimental'
;
my
@child
=
$_
[1]->schildren;
my
@args
=
@child
[1..
$#child
]; # skip
'use'
,
'experimental'
and
';'
foreach
my
$arg
(
@args
) {
my
$v
= 0;
$v
= $1
if
(
$arg
->content =~ /:(5\.\d+)(?:\.\d+)?/);
$v
= max(
$v
,
$experimental
{$1})
if
(
$arg
->content =~ /\b(
$experimental_regexp
)\b/);
if
(
$v
and
$v
> (
$version
|| 0) ) {
$version
=
$v
;
$obj
=
$_
[1];
}
}
return
''
;
} );
return
(
defined
(
$version
)?
"$version.0"
:
undef
,
$obj
);
}
my
%SCHEDULED_BLOCK
=
(
'INIT'
=>
'5.006'
,
'CHECK'
=>
'5.006002'
,
'UNITCHECK'
=>
'5.010'
,
);
sub
_scheduled_blocks
{
my
@versions
;
my
(
$version
,
$obj
);
shift
->Document->find(
sub
{
$_
[1]->isa(
'PPI::Statement::Scheduled'
) or
return
''
;
(
$_
[1]->children)[0]->isa(
'PPI::Token::Word'
) or
return
''
;
my
$function
= ((
$_
[1]->children)[0])->content;
exists
(
$SCHEDULED_BLOCK
{
$function
}) or
return
''
;
my
$v
=
$SCHEDULED_BLOCK
{ (
$_
[1]->children)[0]->content };
if
(
$v
and
$v
> (
$version
|| 0) ) {
$version
=
$v
;
$obj
=
$_
[1];
}
return
''
;
} );
return
(
defined
(
$version
) ?
$version
:
undef
,
$obj
);
}
sub
_regex {
my
@versions
;
my
(
$version
,
$obj
);
shift
->Document->find(
sub
{
return
''
unless
grep
{
$_
[1]->isa(
$_
) }
qw/PPI::Token::QuoteLike::Regexp PPI::Token::Regexp::Match PPI::Token::Regexp::Substitute/
;
my
$re
= PPIx::Regexp->new(
$_
[1] );
my
$v
=
$re
->perl_version_introduced;
if
(
$v
and
$v
> (
$version
|| 0) ) {
$version
=
$v
;
$obj
=
$_
[1];
}
return
''
;
} );
$version
=
undef
if
(
$version
and
$version
eq
'5.000'
);
return
(
$version
,
$obj
);
}
sub
_each_argument {
my
(
$version
,
$obj
);
shift
->Document->find(
sub
{
$_
[1]->isa(
'PPI::Token::Word'
) or
return
''
;
$_
[1]->content =~
'^(each|keys|values)$'
or
return
''
;
return
''
if
is_method_call(
$_
[1]);
my
$next
=
$_
[1]->snext_sibling;
$next
=
$next
->schild(0)->schild(0)
if
$next
->isa(
'PPI::Structure::List'
);
if
(
$next
->isa(
'PPI::Token::Cast'
)) {
if
(
$next
->content eq
'@'
&& 5.012 > (
$version
|| 0)) {
$version
= 5.012;
$obj
=
$_
[1]->parent;
}
elsif
(
$next
->content eq
'$'
&& 5.014 > (
$version
|| 0)) {
$version
= 5.014;
$obj
=
$_
[1]->parent;
}
}
elsif
(
$next
->isa(
'PPI::Token::Symbol'
)) {
if
(
$next
->raw_type eq
'@'
&& 5.012 > (
$version
|| 0)) {
$version
= 5.012;
$obj
=
$_
[1]->parent;
}
elsif
(
$next
->raw_type eq
'$'
&& 5.014 > (
$version
|| 0)) {
$version
= 5.014;
$obj
=
$_
[1]->parent;
}
}
elsif
(
$next
->isa(
'PPI::Token::Operator'
)) {
return
''
;
}
elsif
(
$_
[1]->parent->isa(
'PPI::Statement::Sub'
)) {
return
''
;
}
else
{
if
(5.014 > (
$version
|| 0)) {
$version
= 5.014;
$obj
=
$_
[1]->parent;
}
}
return
1
if
(
$version
and
$version
== 5.014);
return
''
;
} );
return
(
defined
(
$version
)?
"$version"
:
undef
,
$obj
);
}
sub
_str_in_list {
my
$str
=
shift
;
foreach
my
$s
(
@_
) {
return
1
if
$s
eq
$str
;
}
return
0;
}
sub
_binmode_2_arg {
my
(
$version
,
$obj
);
shift
->Document->find_first(
sub
{
my
$main_element
=
$_
[1];
$main_element
->isa(
'PPI::Token::Word'
) or
return
''
;
$main_element
->content eq
'binmode'
or
return
''
;
return
''
if
is_hash_key(
$main_element
);
return
''
if
is_method_call(
$main_element
);
return
''
if
is_subroutine_name(
$main_element
);
return
''
if
is_included_module_name(
$main_element
);
return
''
if
is_package_declaration(
$main_element
);
my
@arguments
= parse_arg_list(
$main_element
);
if
(
scalar
@arguments
== 2 ) {
my
$arg2
=
$arguments
[1][0];
if
(
$arg2
->isa(
'PPI::Token::Quote'
)) {
my
$str
=
$arg2
->string;
$str
=~ s/^\s+//s;
$str
=~ s/\s+$//s;
$str
=~ s/:\s+/:/g;
if
( !_str_in_list(
$str
=>
qw/:raw :crlf/
) and
$str
!~ /[\$\@\%]/) {
$version
= 5.008;
$obj
=
$main_element
;
return
1;
}
}
if
(!
$version
) {
$version
= 5.006;
$obj
=
$main_element
;
}
}
return
''
;
} );
return
(
$version
,
$obj
);
}
sub
_while_readdir {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Word'
) or
return
''
;
$_
[1]->content eq
'while'
or
return
''
;
return
''
if
is_hash_key(
$_
[1]);
return
''
if
is_method_call(
$_
[1]);
my
$e1
=
$_
[1]->next_sibling or
return
''
;
if
(
$e1
->isa(
'PPI::Structure::Condition'
)) {
my
@children
=
$e1
->children;
$e1
=
$children
[0];
}
$e1
->isa(
'PPI::Statement::Expression'
) or
return
''
;
my
@children
=
$e1
->schildren;
$e1
=
$children
[0];
$e1
->isa(
'PPI::Token::Word'
) or
return
''
;
$e1
->content eq
'readdir'
or
return
''
;
return
1
if
@children
== 1;
return
''
if
@children
> 2;
$e1
=
$children
[1];
$e1
->isa(
'PPI::Structure::List'
) or
$e1
->isa(
'PPI::Token::Symbol'
) or
return
''
;
return
1;
} );
}
sub
_perl_5012_pragmas {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
)
and
$MATCHES
{_perl_5012_pragmas}->{
$_
[1]->pragma}
} );
}
sub
_sort_subref {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Word'
) or
return
''
;
$_
[1]->content eq
'sort'
or
return
''
;
is_function_call(
$_
[1]) or
return
''
;
my
$e1
=
$_
[1]->next_sibling;
$e1
->isa(
'PPI::Token::Whitespace'
) or
return
''
;
$e1
=
$e1
->next_sibling;
_get_resulting_sigil(
$e1
) ||
''
eq
'$'
or
return
''
;
$e1
=
$e1
->next_sibling;
$e1
->isa(
'PPI::Token::Whitespace'
) or
return
''
;
$e1
=
$e1
->next_sibling;
$e1
->isa(
'PPI::Token::Word'
) or
$e1
->isa(
'PPI::Token::Symbol'
)
or
$e1
->isa(
'PPI::Token::Cast'
) or
$e1
->isa(
'PPI::Structure::List'
) or
return
''
;
return
1;
} );
}
sub
_open_temp {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement'
) or
return
''
;
my
@children
=
$_
[1]->children;
my
$main_element
=
$children
[0];
$main_element
->isa(
'PPI::Token::Word'
) or
return
''
;
$main_element
->content eq
'open'
or
return
''
;
my
@arguments
= parse_arg_list(
$main_element
);
if
(
scalar
@arguments
== 3 and
scalar
(@{
$arguments
[2]}) == 1) {
my
$arg3
=
$arguments
[2][0];
if
(
$arg3
->isa(
'PPI::Token::Word'
) and
$arg3
->content eq
'undef'
) {
return
1;
}
}
return
''
;
} );
}
sub
_open_scalar {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement'
) or
return
''
;
my
@children
=
$_
[1]->children;
my
$main_element
=
$children
[0];
$main_element
->isa(
'PPI::Token::Word'
) or
return
''
;
$main_element
->content eq
'open'
or
return
''
;
my
@arguments
= parse_arg_list(
$main_element
);
if
(
scalar
@arguments
== 3) {
my
$arg3
=
$arguments
[2][0];
if
(
$arg3
->isa(
'PPI::Token::Cast'
) and
$arg3
->content eq
'\\'
) {
return
1;
}
}
return
''
;
} );
}
sub
_exists_subr {
my
(
$pmv
) =
@_
;
$pmv
->Document->find_first(
sub
{
my
(
$document
,
$elem
) =
@_
;
if
(
$elem
->isa(
'PPI::Token::Word'
)
&&
$elem
eq
'exists'
&& is_function_call(
$elem
)
&& (
$elem
= first_arg(
$elem
))
&& (_get_resulting_sigil(
$elem
) ||
''
) eq
'&'
) {
return
1;
}
else
{
return
0;
}
});
}
sub
_get_resulting_sigil {
my
$elem
=
shift
;
if
(
$elem
->isa(
'PPI::Token::Cast'
)) {
return
$elem
->content;
}
elsif
(
$elem
->isa(
'PPI::Token::Symbol'
)) {
return
$elem
->symbol_type;
}
else
{
return
undef
;
}
}
sub
_postfix_when {
shift
->Document->find_first(
sub
{
my
$main_element
=
$_
[1];
$main_element
->isa(
'PPI::Token::Word'
) or
return
''
;
$main_element
->content eq
'when'
or
return
''
;
return
''
if
is_hash_key(
$main_element
);
return
''
if
is_method_call(
$main_element
);
return
''
if
is_subroutine_name(
$main_element
);
return
''
if
is_included_module_name(
$main_element
);
return
''
if
is_package_declaration(
$main_element
);
my
$stmnt
=
$main_element
->statement();
return
''
if
!
$stmnt
;
return
''
if
$stmnt
->isa(
'PPI::Statement::When'
);
return
1;
} );
}
sub
_yada_yada_yada {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Operator'
)
and
$_
[1]->content eq
'...'
or
return
''
;
my
@child
=
$_
[1]->parent->schildren;
@child
== 1 and
return
1;
if
(
@child
== 2) {
$child
[1]->isa(
'PPI::Token::Structure'
)
}
} );
}
sub
_state_declaration {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Variable'
)
and (
$_
[1]->children)[0]->isa(
'PPI::Token::Word'
)
and (
$_
[1]->children)[0]->content eq
'state'
} );
}
sub
_stacked_labels {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Compound'
) ||
return
''
;
$_
[1]->schild(0)->isa(
'PPI::Token::Label'
) ||
return
''
;
my
$next
=
$_
[1]->snext_sibling ||
return
''
;
if
(
$next
->isa(
'PPI::Statement::Compound'
)
&&
$next
->schild(0)->isa(
'PPI::Token::Label'
)) {
return
1;
}
0;
} );
}
sub
_internals_svreadonly {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement'
)
and (
$_
[1]->children)[0]->isa(
'PPI::Token::Word'
)
and (
$_
[1]->children)[0]->content eq
'Internals::SvREADONLY'
} );
}
sub
_pkg_name_version {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Package'
) or
return
''
;
my
@child
=
$_
[1]->schildren();
$child
[0]->isa(
'PPI::Token::Word'
) or
return
''
;
$child
[0]->content eq
'package'
or
return
''
;
$child
[1]->isa(
'PPI::Token::Word'
) or
return
''
;
$child
[2]->isa(
'PPI::Token::Number'
) or
return
''
;
return
1;
} );
}
sub
_perl_5010_pragmas {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
)
and
$MATCHES
{_perl_5010_pragmas}->{
$_
[1]->pragma}
} );
}
sub
_perl_5010_operators {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Operator'
)
and
$MATCHES
{_perl_5010_operators}->{
$_
[1]->content}
} );
}
sub
_perl_5010_magic {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Magic'
)
and
$MATCHES
{_perl_5010_magic}->{
$_
[1]->symbol}
} );
}
sub
_perl_5008_pragmas {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
)
and
$MATCHES
{_perl_5008_pragmas}->{
$_
[1]->pragma}
} );
}
sub
_bugfix_magic_errno {
my
$Document
=
shift
->Document;
my
$element
=
$Document
->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Magic'
)
and
$_
[1]->symbol eq
'$^E'
} ) ||
return
undef
;
$Document
->find_any(
sub
{
$_
[1]->isa(
'PPI::Token::Magic'
)
and
$_
[1]->symbol eq
'$!'
} ) ||
return
''
;
return
$element
;
}
sub
_is_utf8 {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Word'
) or
return
''
;
$_
[1] eq
'utf8::is_utf'
or
return
''
;
return
1;
} );
}
sub
_unquoted_versions {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Number'
) or
return
''
;
$_
[1]->{_subtype} or
return
''
;
$_
[1]->{_subtype} eq
'base256'
or
return
''
;
my
$stmt
=
$_
[1]->parent or
return
''
;
my
$braces
=
$stmt
->parent or
return
''
;
$braces
->isa(
'PPI::Structure'
) or
return
''
;
$braces
->braces eq
'()'
or
return
''
;
my
$new
=
$braces
->previous_sibling or
return
''
;
$new
->isa(
'PPI::Token::Word'
) or
return
''
;
$new
->content eq
'new'
or
return
''
;
my
$method
=
$new
->previous_sibling or
return
''
;
$method
->isa(
'PPI::Token::Operator'
) or
return
''
;
$method
->content eq
'->'
or
return
''
;
my
$_class
=
$method
->previous_sibling or
return
''
;
$_class
->isa(
'PPI::Token::Word'
) or
return
''
;
$_class
->content eq
'version'
or
return
''
;
1;
} );
}
sub
_pragma_utf8 {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
)
and
(
(
$_
[1]->module and
$_
[1]->module eq
'utf8'
)
or
(
$_
[1]->pragma and
$_
[1]->pragma eq
'utf8'
)
)
} );
}
sub
_constant_hash {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
)
and
$_
[1]->type
and
$_
[1]->type eq
'use'
and
$_
[1]->module eq
'constant'
and
$_
[1]->schild(2)->isa(
'PPI::Structure'
)
} );
}
sub
_perl_5006_pragmas {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
)
and
$MATCHES
{_perl_5006_pragmas}->{
$_
[1]->pragma}
} );
}
sub
_any_our_variables {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Variable'
)
and
$_
[1]->type eq
'our'
} );
}
sub
_any_binary_literals {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Number::Binary'
)
} );
}
sub
_any_version_literals {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Number::Version'
)
} );
}
sub
_magic_version {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Magic'
)
and
$_
[1]->symbol eq
'$^V'
} );
}
sub
_any_attributes {
shift
->Document->find_first(
'Token::Attribute'
);
}
sub
_any_CHECK_blocks {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Scheduled'
)
and
$_
[1]->type eq
'CHECK'
} );
}
sub
_any_qr_tokens {
shift
->Document->find_first(
'Token::QuoteLike::Regexp'
);
}
sub
_perl_5005_pragmas {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
)
and
$MATCHES
{_perl_5005_pragmas}->{
$_
[1]->pragma}
} );
}
sub
_perl_5005_modules {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
)
and
$_
[1]->module
and (
$_
[1]->module eq
'Tie::Array'
or
(
$_
[1]->module =~ /\bException\b/ and
$_
[1]->module !~ /^(?:CPAN)::/)
or
$_
[1]->module =~ /\bThread\b/
or
$_
[1]->module =~ /^Error\b/
or
$_
[1]->module eq
'base'
or
$_
[1]->module eq
'Errno'
)
} );
}
sub
_any_tied_arrays {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Sub'
)
and
$_
[1]->name eq
'TIEARRAY'
} )
}
sub
_any_quotelike_regexp {
shift
->Document->find_first(
'Token::QuoteLike::Regexp'
);
}
sub
_any_INIT_blocks {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Scheduled'
)
and
$_
[1]->type eq
'INIT'
} );
}
sub
_local_soft_reference {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Variable'
) or
return
''
;
$_
[1]->type eq
'local'
or
return
''
;
my
@child
=
$_
[1]->schildren;
scalar
(
@child
) >= 2 or
return
''
;
$child
[1]->isa(
'PPI::Token::Cast'
) or
return
''
;
$child
[1]->content eq
'$'
or
return
''
;
$child
[2]->isa(
'PPI::Structure::Block'
) or
return
''
;
my
$statement
=
$child
[2]->schild(0) or
return
''
;
$statement
->isa(
'PPI::Statement'
) or
return
''
;
my
$inside
=
$statement
->schild(0) or
return
''
;
$inside
->isa(
'PPI::Token::Quote'
) or
return
''
;
return
1;
} );
}
sub
_use_carp_version {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement::Include'
) or
return
''
;
$_
[1]->module eq
'Carp'
or
return
''
;
my
$version
=
$_
[1]->module_version;
return
!! (
defined
$version
and
length
"$version"
);
} );
}
sub
_three_argument_open {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Statement'
) or
return
''
;
my
@children
=
$_
[1]->children;
my
$main_element
=
$children
[0];
$main_element
->isa(
'PPI::Token::Word'
) or
return
''
;
$main_element
->content eq
'open'
or
return
''
;
my
@arguments
= parse_arg_list(
$main_element
);
if
(
scalar
@arguments
> 2 ) {
return
1;
}
return
''
;
} );
}
sub
_substr_4_arg {
shift
->Document->find_first(
sub
{
my
$main_element
=
$_
[1];
$main_element
->isa(
'PPI::Token::Word'
) or
return
''
;
$main_element
->content eq
'substr'
or
return
''
;
return
''
if
is_hash_key(
$main_element
);
return
''
if
is_method_call(
$main_element
);
return
''
if
is_subroutine_name(
$main_element
);
return
''
if
is_included_module_name(
$main_element
);
return
''
if
is_package_declaration(
$main_element
);
my
@arguments
= parse_arg_list(
$main_element
);
if
(
scalar
@arguments
> 3 ) {
return
1;
}
return
''
;
} );
}
sub
_mkdir_1_arg {
shift
->Document->find_first(
sub
{
my
$main_element
=
$_
[1];
$main_element
->isa(
'PPI::Token::Word'
) or
return
''
;
$main_element
->content eq
'mkdir'
or
return
''
;
return
''
if
is_hash_key(
$main_element
);
return
''
if
is_method_call(
$main_element
);
return
''
if
is_subroutine_name(
$main_element
);
return
''
if
is_included_module_name(
$main_element
);
return
''
if
is_package_declaration(
$main_element
);
my
@arguments
= parse_arg_list(
$main_element
);
if
(
scalar
@arguments
!= 2 ) {
return
1;
}
return
''
;
} );
}
sub
_splice_negative_length {
shift
->Document->find_first(
sub
{
my
$main_element
=
$_
[1];
$main_element
->isa(
'PPI::Token::Word'
) or
return
''
;
$main_element
->content eq
'splice'
or
return
''
;
return
''
if
is_hash_key(
$main_element
);
return
''
if
is_method_call(
$main_element
);
return
''
if
is_subroutine_name(
$main_element
);
return
''
if
is_included_module_name(
$main_element
);
return
''
if
is_package_declaration(
$main_element
);
my
@arguments
= parse_arg_list(
$main_element
);
if
(
scalar
@arguments
< 3 ) {
return
''
;
}
my
$arg
=
$arguments
[2];
if
(
ref
(
$arg
) eq
'ARRAY'
) {
$arg
=
$arg
->[0];
}
if
(
$arg
->isa(
'PPI::Token::Number'
)) {
if
(
$arg
->literal<0) {
return
1;
}
else
{
return
''
;
}
}
return
''
;
} );
}
sub
_postfix_foreach {
shift
->Document->find_first(
sub
{
my
$main_element
=
$_
[1];
$main_element
->isa(
'PPI::Token::Word'
) or
return
''
;
$main_element
->content eq
'foreach'
or
return
''
;
return
''
if
is_hash_key(
$main_element
);
return
''
if
is_method_call(
$main_element
);
return
''
if
is_subroutine_name(
$main_element
);
return
''
if
is_included_module_name(
$main_element
);
return
''
if
is_package_declaration(
$main_element
);
my
$stmnt
=
$main_element
->statement();
return
''
if
!
$stmnt
;
return
''
if
$stmnt
->isa(
'PPI::Statement::Compound'
);
return
1;
} );
}
sub
_weaken {
shift
->Document->find_first(
sub
{
(
$_
[1]->isa(
'PPI::Statement::Include'
)
and
$_
[1]->module eq
'Scalar::Util'
and
$_
[1]->content =~ /[^:]\b(?:weaken|isweak)\b[^:]/
)
or
(
$_
[1]->isa(
'PPI::Token::Word'
)
and
(
$_
[1]->content eq
'Scalar::Util::isweak'
or
$_
[1]->content eq
'Scalar::Util::weaken'
)
)
} );
}
sub
_5005_variables {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Magic'
)
and
(
$_
[1]->symbol eq
'$!'
or
$_
[1]->symbol eq
'$^R'
)
} );
}
sub
_bareword_double_colon {
shift
->Document->find_first(
sub
{
$_
[1]->isa(
'PPI::Token::Word'
)
and
$_
[1]->content =~ /::$/
} );
}
sub
_SELF {
my
$param
=
shift
;
if
( _INSTANCE(
$param
->[0],
'Perl::MinimumVersion'
) ) {
return
shift
@$param
;
}
if
(
_CLASS(
$param
->[0])
and
$param
->[0]->isa(
'Perl::MinimumVersion'
)
) {
my
$class
=
shift
@$param
;
my
$options
=
shift
@$param
;
return
$class
->new(
$options
);
}
Perl::MinimumVersion->new(
shift
@$param
);
}
sub
_max {
defined
$_
[0] and
"$_[0]"
eq PMV and
shift
;
my
@valid
=
map
{
[
$_
,
$_
->isa(
'Perl::MinimumVersion::Reason'
) ?
$_
->version :
$_
]
}
grep
{
_INSTANCE(
$_
,
'Perl::MinimumVersion::Reason'
)
or
_INSTANCE(
$_
,
'version'
)
}
@_
or
return
''
;
my
$max
=
shift
@valid
;
foreach
my
$it
(
@valid
) {
$max
=
$it
if
$it
->[1] >
$max
->[1];
}
return
$max
->[0];
}
1;
Hide Show 69 lines of Pod