use
5.006001;
our
$VERSION
=
'1.110_001'
;
Readonly::Scalar
my
$DESC
=>
q<Mismatched operator>
;
Readonly::Scalar
my
$EXPL
=>
q<Numeric/string operators and operands should match>
;
Readonly::Hash
my
%TOKEN_COMPATIBILITY
=> (
'PPI::Token::Number'
=> [
$TRUE
,
$FALSE
],
'PPI::Token::Symbol'
=> [
$TRUE
,
$TRUE
],
'PPI::Token::Quote'
=> [
$FALSE
,
$TRUE
],
);
Readonly::Hash
my
%FILE_OPERATOR_COMPATIBILITY
=>
map
{;
"-$_"
=> [
$TRUE
,
$FALSE
] }
qw< r w x o R W X O e z s f d l p S b c t u g k T B M A >
;
Readonly::Scalar
my
$TOKEN_COMPATIBILITY_INDEX_NUMERIC
=> 0;
Readonly::Scalar
my
$TOKEN_COMPATIBILITY_INDEX_STRING
=> 1;
Readonly::Hash
my
%OPERATOR_TYPES
=> (
(
map
{
$_
=>
$TOKEN_COMPATIBILITY_INDEX_NUMERIC
}
qw[ == != > >= < <= + - * / += -= *= /= ]
),
map
{
$_
=>
$TOKEN_COMPATIBILITY_INDEX_STRING
}
qw< eq ne lt gt le ge . .= >
,
);
sub
supported_parameters {
return
() }
sub
default_severity {
return
$SEVERITY_MEDIUM
}
sub
default_themes {
return
qw< core bugs >
}
sub
applies_to {
return
'PPI::Token::Operator'
}
sub
violates {
my
(
$self
,
$elem
) =
@_
;
my
$elem_text
=
$elem
->content();
return
if
not
exists
$OPERATOR_TYPES
{
$elem_text
};
my
$leading_operator
=
$self
->_get_potential_leading_operator(
$elem
)
or
return
;
my
$next_elem
=
$elem
->snext_sibling() or
return
;
if
(
$next_elem
->isa(
'PPI::Token::Operator'
) ) {
$elem_text
.=
$next_elem
->content();
$next_elem
=
$next_elem
->snext_sibling();
}
return
if
not
exists
$OPERATOR_TYPES
{
$elem_text
};
my
$operator_type
=
$OPERATOR_TYPES
{
$elem_text
};
my
$leading_operator_compatibility
=
$self
->_get_token_compatibility(
$leading_operator
);
my
$next_compatibility
=
$self
->_get_token_compatibility(
$next_elem
);
return
if
(
!
defined
$leading_operator_compatibility
||
$leading_operator_compatibility
->[
$operator_type
]
)
&& (
!
defined
$next_compatibility
||
$next_compatibility
->[
$operator_type
]
);
return
if
$operator_type
&&
defined
$leading_operator_compatibility
&& !
$leading_operator_compatibility
->[
$operator_type
]
&&
$self
->_have_stringy_x(
$leading_operator
);
return
$self
->violation(
$DESC
,
$EXPL
,
$elem
);
}
sub
_get_token_compatibility {
my
(
$self
,
$elem
) =
@_
;
return
$FILE_OPERATOR_COMPATIBILITY
{
$elem
->content() }
if
$self
->_is_file_operator(
$elem
);
for
my
$class
(
keys
%TOKEN_COMPATIBILITY
) {
return
$TOKEN_COMPATIBILITY
{
$class
}
if
$elem
->isa(
$class
);
}
return
;
}
sub
_have_stringy_x {
my
(
$self
,
$elem
) =
@_
;
return
if
not
$elem
;
my
$prev_oper
=
$elem
->sprevious_sibling() or
return
;
return
if
not
$prev_oper
->isa(
'PPI::Token::Operator'
);
return
if
'x'
ne
$prev_oper
->content();
return
!!
$prev_oper
->sprevious_sibling();
}
sub
_get_potential_leading_operator {
my
(
$self
,
$elem
) =
@_
;
my
$previous_element
=
$elem
->sprevious_sibling() or
return
;
if
(
$self
->_get_token_compatibility(
$previous_element
) ) {
my
$previous_sibling
=
$previous_element
->sprevious_sibling();
if
(
$previous_sibling
and
$self
->_is_file_operator(
$previous_sibling
)
) {
$previous_element
=
$previous_sibling
;
}
}
return
$previous_element
;
}
sub
_is_file_operator {
my
(
$self
,
$elem
) =
@_
;
return
if
not
$elem
;
return
if
not
$elem
->isa(
'PPI::Token::Operator'
);
return
!!
$FILE_OPERATOR_COMPATIBILITY
{
$elem
->content() }
}
1;