DESC
=>
'Unreachable code'
,
EXPL
=>
'Consider removing it'
,
};
my
%control_statement_token_types_to_exit
= (
&RETURN
=> 1,
&NEXT
=> 1,
&LAST
=> 1,
&REDO
=> 1,
);
my
%control_statement_to_exit
= (
die
=> 1,
exit
=> 1,
croak
=> 1,
confess
=> 1,
);
my
%conditional_token_types
= (
&AND
=> 1,
&OR
=> 1,
&ALPHABET_AND
=> 1,
&ALPHABET_OR
=> 1,
);
sub
evaluate {
my
(
$class
,
$file
,
$tokens
,
$src
,
$args
) =
@_
;
my
$depth
= 0;
my
%is_exited_by_depth
;
my
%unreachable_token_by_depth
;
my
%is_in_ignore_context_by_depth
;
my
@violations
;
for
(
my
$i
= 0,
my
$token_type
,
my
$token_data
;
my
$token
=
$tokens
->[
$i
];
$i
++) {
$token_type
=
$token
->{type};
$token_data
=
$token
->{data};
if
(
$token_type
== LEFT_BRACE) {
$depth
++;
next
;
}
if
(
$token_type
== RIGHT_BRACE) {
if
(
my
$unreachable_token
=
$unreachable_token_by_depth
{
$depth
}) {
push
@violations
, {
filename
=>
$file
,
line
=>
$unreachable_token
->{line},
description
=> DESC,
explanation
=> EXPL,
policy
=> __PACKAGE__,
};
undef
$unreachable_token_by_depth
{
$depth
};
}
$is_exited_by_depth
{
$depth
} = 0;
$is_in_ignore_context_by_depth
{
$depth
} = 0;
$depth
--;
next
;
}
if
(
((
$token_type
== KEY ||
$token_type
== BUILTIN_FUNC) &&
$control_statement_to_exit
{
$token_data
}) ||
$control_statement_token_types_to_exit
{
$token_type
}
) {
if
(
$is_exited_by_depth
{
$depth
}) {
$unreachable_token_by_depth
{
$depth
} //=
$token
;
next
;
}
my
$before_token
=
$tokens
->[
$i
-1];
if
(
$conditional_token_types
{
$before_token
->{type}} ||
(
$before_token
->{type} == DEFAULT_OP &&
$before_token
->{data} eq
'//'
)
) {
next
;
}
$is_exited_by_depth
{
$depth
} = 1;
for
(
$i
++;
$token
=
$tokens
->[
$i
];
$i
++) {
$token_type
=
$token
->{type};
if
(
$token_type
== SEMI_COLON) {
last
;
}
if
(
$token_type
== IF_STATEMENT ||
$token_type
== UNLESS_STATEMENT) {
$is_exited_by_depth
{
$depth
} = 0;
last
;
}
}
next
;
}
if
(
$token_type
== KEY) {
$token
=
$tokens
->[++
$i
];
if
(
$token
->{type} == COLON) {
$is_in_ignore_context_by_depth
{
$depth
} = 1;
}
next
;
}
if
(
$token_type
== PACKAGE) {
$is_in_ignore_context_by_depth
{
$depth
} = 1;
next
;
}
if
(
$token_type
== USE_DECL ||
$token_type
== OUR_DECL ||
(
$token_type
== BUILTIN_FUNC &&
$token_data
eq
'no'
)
) {
for
(
$i
++;
$token
=
$tokens
->[
$i
];
$i
++) {
$token_type
=
$token
->{type};
if
(
$token_type
== SEMI_COLON) {
last
;
}
}
next
;
}
if
(
$token_type
== FUNCTION_DECL ||
(
$token_type
== MOD_WORD &&
$token_data
eq
'BEGIN'
)
) {
for
(
$i
++;
$token
=
$tokens
->[
$i
];
$i
++) {
$token_type
=
$token
->{type};
if
(
$token_type
== LEFT_BRACE) {
last
;
}
}
$i
--;
next
;
}
if
(
$is_exited_by_depth
{
$depth
} && !
$is_in_ignore_context_by_depth
{
$depth
}) {
$unreachable_token_by_depth
{
$depth
} //=
$token
;
}
}
if
(
my
$unreachable_token
=
$unreachable_token_by_depth
{
$depth
}) {
push
@violations
, {
filename
=>
$file
,
line
=>
$unreachable_token
->{line},
description
=> DESC,
explanation
=> EXPL,
policy
=> __PACKAGE__,
};
}
return
\
@violations
;
}
1;