File Coverage

blib/lib/Perl/Lint/Policy/ControlStructures/ProhibitUnreachableCode.pm
Criterion Covered Total %
statement 74 76 97.3
branch 34 34 100.0
condition 32 42 76.1
subroutine 6 6 100.0
pod 0 1 0.0
total 146 159 91.8


line stmt bran cond sub pod time code
1             package Perl::Lint::Policy::ControlStructures::ProhibitUnreachableCode;
2 133     133   69764 use strict;
  133         201  
  133         3160  
3 133     133   34971 use warnings;
  133         301  
  133         3294  
4 133     133   892 use Perl::Lint::Constants::Type;
  133         158  
  133         59915  
5 133     133   827 use parent "Perl::Lint::Policy";
  133         148  
  133         576  
6              
7             use constant {
8 133         62586 DESC => 'Unreachable code',
9             EXPL => 'Consider removing it',
10 133     133   6654 };
  133         188  
11              
12             my %control_statement_token_types_to_exit = (
13             &RETURN => 1,
14             &NEXT => 1,
15             &LAST => 1,
16             &REDO => 1,
17             );
18              
19             my %control_statement_to_exit = (
20             die => 1,
21             exit => 1,
22             croak => 1,
23             confess => 1,
24             );
25              
26             my %conditional_token_types = (
27             &AND => 1,
28             &OR => 1,
29             &ALPHABET_AND => 1,
30             &ALPHABET_OR => 1,
31             );
32              
33             sub evaluate {
34 9     9 0 13 my ($class, $file, $tokens, $src, $args) = @_;
35              
36 9         7 my $depth = 0;
37 9         9 my %is_exited_by_depth;
38             my %unreachable_token_by_depth;
39 0         0 my %is_in_ignore_context_by_depth;
40              
41 0         0 my @violations;
42 9         23 for (my $i = 0, my $token_type, my $token_data; my $token = $tokens->[$i]; $i++) {
43 328         218 $token_type = $token->{type};
44 328         234 $token_data = $token->{data};
45              
46 328 100       340 if ($token_type == LEFT_BRACE) {
47 38         24 $depth++;
48 38         50 next;
49             }
50              
51 290 100       291 if ($token_type == RIGHT_BRACE) {
52 37 100       55 if (my $unreachable_token = $unreachable_token_by_depth{$depth}) {
53             push @violations, {
54             filename => $file,
55             line => $unreachable_token->{line},
56 17         43 description => DESC,
57             explanation => EXPL,
58             policy => __PACKAGE__,
59             };
60              
61 17         14 undef $unreachable_token_by_depth{$depth};
62             }
63              
64 37         30 $is_exited_by_depth{$depth} = 0;
65 37         28 $is_in_ignore_context_by_depth{$depth} = 0;
66 37         18 $depth--;
67 37         56 next;
68             }
69              
70 253 100 100     873 if (
      66        
      66        
71             (($token_type == KEY || $token_type == BUILTIN_FUNC) && $control_statement_to_exit{$token_data}) ||
72             $control_statement_token_types_to_exit{$token_type}
73             ) {
74 39 100       59 if ($is_exited_by_depth{$depth}) {
75 1   33     6 $unreachable_token_by_depth{$depth} //= $token;
76 1         2 next;
77             }
78              
79 38         26 my $before_token = $tokens->[$i-1];
80 38 100 66     108 if ($conditional_token_types{$before_token->{type}} ||
      66        
81             ($before_token->{type} == DEFAULT_OP && $before_token->{data} eq '//')
82             ) {
83             # if before token is conditional operator, ignore
84 5         11 next;
85             }
86              
87 33         26 $is_exited_by_depth{$depth} = 1;
88              
89 33         50 for ($i++; $token = $tokens->[$i]; $i++) {
90 40         29 $token_type = $token->{type};
91 40 100       47 if ($token_type == SEMI_COLON) {
92 27         18 last;
93             }
94              
95 13 100 100     35 if ($token_type == IF_STATEMENT || $token_type == UNLESS_STATEMENT) {
96             # if postfix conditional statement exists, ignore
97 6         4 $is_exited_by_depth{$depth} = 0;
98 6         6 last;
99             }
100             }
101              
102 33         47 next;
103             }
104              
105 214 100       224 if ($token_type == KEY) {
106 23         22 $token = $tokens->[++$i];
107 23 100       26 if ($token->{type} == COLON) {
108             # Label (e.g. FOO:)
109 5         6 $is_in_ignore_context_by_depth{$depth} = 1;
110             }
111              
112 23         32 next;
113             }
114              
115 191 100       191 if ($token_type == PACKAGE) {
116             # in other package
117 1         1 $is_in_ignore_context_by_depth{$depth} = 1;
118 1         3 next;
119             }
120              
121 190 100 100     593 if (
      100        
      66        
122             $token_type == USE_DECL || $token_type == OUR_DECL ||
123             ($token_type == BUILTIN_FUNC && $token_data eq 'no')
124             ) {
125             # for compiler phase. Ignore them.
126 3         5 for ($i++; $token = $tokens->[$i]; $i++) {
127 6         5 $token_type = $token->{type};
128 6 100       11 if ($token_type == SEMI_COLON) {
129 3         3 last;
130             }
131             }
132 3         6 next;
133             }
134              
135 187 100 66     349 if (
      66        
136             $token_type == FUNCTION_DECL ||
137             ($token_type == MOD_WORD && $token_data eq 'BEGIN')
138             ) {
139             # for function declare and BEGIN block
140 11         16 for ($i++; $token = $tokens->[$i]; $i++) {
141 21         20 $token_type = $token->{type};
142 21 100       30 if ($token_type == LEFT_BRACE) {
143 11         11 last;
144             }
145             }
146              
147 11         6 $i--; # rewind
148              
149 11         18 next;
150             }
151              
152 176 100 100     398 if ($is_exited_by_depth{$depth} && !$is_in_ignore_context_by_depth{$depth}) {
153 44   66     110 $unreachable_token_by_depth{$depth} //= $token;
154             }
155             }
156              
157             # for depth of top, finally
158 9 100       20 if (my $unreachable_token = $unreachable_token_by_depth{$depth}) {
159             push @violations, {
160             filename => $file,
161             line => $unreachable_token->{line},
162 1         3 description => DESC,
163             explanation => EXPL,
164             policy => __PACKAGE__,
165             };
166             }
167              
168 9         36 return \@violations;
169             }
170              
171             1;
172