File Coverage

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


line stmt bran cond sub pod time code
1             package Perl::Lint::Policy::ControlStructures::ProhibitUnreachableCode;
2 133     133   92105 use strict;
  133         266  
  133         4755  
3 133     133   47301 use warnings;
  133         378  
  133         4654  
4 133     133   1353 use Perl::Lint::Constants::Type;
  133         177  
  133         80797  
5 133     133   1219 use parent "Perl::Lint::Policy";
  133         204  
  133         756  
6              
7             use constant {
8 133         81322 DESC => 'Unreachable code',
9             EXPL => 'Consider removing it',
10 133     133   9610 };
  133         243  
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 23 my ($class, $file, $tokens, $src, $args) = @_;
35              
36 9         12 my $depth = 0;
37 9         10 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         62 for (my $i = 0, my $token_type, my $token_data; my $token = $tokens->[$i]; $i++) {
43 328         389 $token_type = $token->{type};
44 328         395 $token_data = $token->{data};
45              
46 328 100       475 if ($token_type == LEFT_BRACE) {
47 38         35 $depth++;
48 38         78 next;
49             }
50              
51 290 100       563 if ($token_type == RIGHT_BRACE) {
52 37 100       67 if (my $unreachable_token = $unreachable_token_by_depth{$depth}) {
53 17         76 push @violations, {
54             filename => $file,
55             line => $unreachable_token->{line},
56             description => DESC,
57             explanation => EXPL,
58             policy => __PACKAGE__,
59             };
60              
61 17         25 undef $unreachable_token_by_depth{$depth};
62             }
63              
64 37         40 $is_exited_by_depth{$depth} = 0;
65 37         37 $is_in_ignore_context_by_depth{$depth} = 0;
66 37         39 $depth--;
67 37         82 next;
68             }
69              
70 253 100 100     1513 if (
      100        
      100        
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       79 if ($is_exited_by_depth{$depth}) {
75 1   33     7 $unreachable_token_by_depth{$depth} //= $token;
76 1         2 next;
77             }
78              
79 38         55 my $before_token = $tokens->[$i-1];
80 38 100 66     173 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         14 next;
85             }
86              
87 33         48 $is_exited_by_depth{$depth} = 1;
88              
89 33         74 for ($i++; $token = $tokens->[$i]; $i++) {
90 40         55 $token_type = $token->{type};
91 40 100       70 if ($token_type == SEMI_COLON) {
92 27         27 last;
93             }
94              
95 13 100 100     58 if ($token_type == IF_STATEMENT || $token_type == UNLESS_STATEMENT) {
96             # if postfix conditional statement exists, ignore
97 6         8 $is_exited_by_depth{$depth} = 0;
98 6         9 last;
99             }
100             }
101              
102 33         78 next;
103             }
104              
105 214 100       327 if ($token_type == KEY) {
106 23         28 $token = $tokens->[++$i];
107 23 100       47 if ($token->{type} == COLON) {
108             # Label (e.g. FOO:)
109 5         7 $is_in_ignore_context_by_depth{$depth} = 1;
110             }
111              
112 23         48 next;
113             }
114              
115 191 100       276 if ($token_type == PACKAGE) {
116             # in other package
117 1         3 $is_in_ignore_context_by_depth{$depth} = 1;
118 1         5 next;
119             }
120              
121 190 100 100     868 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         8 for ($i++; $token = $tokens->[$i]; $i++) {
127 6         5 $token_type = $token->{type};
128 6 100       13 if ($token_type == SEMI_COLON) {
129 3         3 last;
130             }
131             }
132 3         5 next;
133             }
134              
135 187 100 66     508 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         31 for ($i++; $token = $tokens->[$i]; $i++) {
141 21         27 $token_type = $token->{type};
142 21 100       53 if ($token_type == LEFT_BRACE) {
143 11         14 last;
144             }
145             }
146              
147 11         12 $i--; # rewind
148              
149 11         30 next;
150             }
151              
152 176 100 100     622 if ($is_exited_by_depth{$depth} && !$is_in_ignore_context_by_depth{$depth}) {
153 44   66     155 $unreachable_token_by_depth{$depth} //= $token;
154             }
155             }
156              
157             # for depth of top, finally
158 9 100       24 if (my $unreachable_token = $unreachable_token_by_depth{$depth}) {
159 1         6 push @violations, {
160             filename => $file,
161             line => $unreachable_token->{line},
162             description => DESC,
163             explanation => EXPL,
164             policy => __PACKAGE__,
165             };
166             }
167              
168 9         84 return \@violations;
169             }
170              
171             1;
172