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   70138 use strict;
  133         208  
  133         3071  
3 133     133   34241 use warnings;
  133         295  
  133         3217  
4 133     133   862 use Perl::Lint::Constants::Type;
  133         153  
  133         59414  
5 133     133   905 use parent "Perl::Lint::Policy";
  133         138  
  133         563  
6              
7             use constant {
8 133         62390 DESC => 'Unreachable code',
9             EXPL => 'Consider removing it',
10 133     133   6565 };
  133         155  
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 15 my ($class, $file, $tokens, $src, $args) = @_;
35              
36 9         8 my $depth = 0;
37 9         5 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         26 for (my $i = 0, my $token_type, my $token_data; my $token = $tokens->[$i]; $i++) {
43 328         235 $token_type = $token->{type};
44 328         220 $token_data = $token->{data};
45              
46 328 100       353 if ($token_type == LEFT_BRACE) {
47 38         26 $depth++;
48 38         52 next;
49             }
50              
51 290 100       308 if ($token_type == RIGHT_BRACE) {
52 37 100       47 if (my $unreachable_token = $unreachable_token_by_depth{$depth}) {
53             push @violations, {
54             filename => $file,
55             line => $unreachable_token->{line},
56 17         42 description => DESC,
57             explanation => EXPL,
58             policy => __PACKAGE__,
59             };
60              
61 17         19 undef $unreachable_token_by_depth{$depth};
62             }
63              
64 37         25 $is_exited_by_depth{$depth} = 0;
65 37         25 $is_in_ignore_context_by_depth{$depth} = 0;
66 37         24 $depth--;
67 37         56 next;
68             }
69              
70 253 100 100     897 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       56 if ($is_exited_by_depth{$depth}) {
75 1   33     6 $unreachable_token_by_depth{$depth} //= $token;
76 1         1 next;
77             }
78              
79 38         36 my $before_token = $tokens->[$i-1];
80 38 100 66     113 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         8 next;
85             }
86              
87 33         23 $is_exited_by_depth{$depth} = 1;
88              
89 33         55 for ($i++; $token = $tokens->[$i]; $i++) {
90 40         60 $token_type = $token->{type};
91 40 100       46 if ($token_type == SEMI_COLON) {
92 27         22 last;
93             }
94              
95 13 100 100     36 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         7 last;
99             }
100             }
101              
102 33         49 next;
103             }
104              
105 214 100       240 if ($token_type == KEY) {
106 23         17 $token = $tokens->[++$i];
107 23 100       31 if ($token->{type} == COLON) {
108             # Label (e.g. FOO:)
109 5         4 $is_in_ignore_context_by_depth{$depth} = 1;
110             }
111              
112 23         30 next;
113             }
114              
115 191 100       202 if ($token_type == PACKAGE) {
116             # in other package
117 1         2 $is_in_ignore_context_by_depth{$depth} = 1;
118 1         2 next;
119             }
120              
121 190 100 100     601 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         9 for ($i++; $token = $tokens->[$i]; $i++) {
127 6         5 $token_type = $token->{type};
128 6 100       12 if ($token_type == SEMI_COLON) {
129 3         3 last;
130             }
131             }
132 3         5 next;
133             }
134              
135 187 100 66     376 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         19 $token_type = $token->{type};
142 21 100       31 if ($token_type == LEFT_BRACE) {
143 11         6 last;
144             }
145             }
146              
147 11         8 $i--; # rewind
148              
149 11         16 next;
150             }
151              
152 176 100 100     416 if ($is_exited_by_depth{$depth} && !$is_in_ignore_context_by_depth{$depth}) {
153 44   66     111 $unreachable_token_by_depth{$depth} //= $token;
154             }
155             }
156              
157             # for depth of top, finally
158 9 100       14 if (my $unreachable_token = $unreachable_token_by_depth{$depth}) {
159             push @violations, {
160             filename => $file,
161             line => $unreachable_token->{line},
162 1         4 description => DESC,
163             explanation => EXPL,
164             policy => __PACKAGE__,
165             };
166             }
167              
168 9         41 return \@violations;
169             }
170              
171             1;
172