File Coverage

blib/lib/Perl/Lint/Policy/ErrorHandling/RequireCheckingReturnValueOfEval.pm
Criterion Covered Total %
statement 111 111 100.0
branch 74 74 100.0
condition 76 87 87.3
subroutine 6 6 100.0
pod 0 1 0.0
total 267 279 95.7


line stmt bran cond sub pod time code
1             package Perl::Lint::Policy::ErrorHandling::RequireCheckingReturnValueOfEval;
2 133     133   73207 use strict;
  133         174  
  133         3016  
3 133     133   420 use warnings;
  133         156  
  133         2406  
4 133     133   800 use Perl::Lint::Constants::Type;
  133         136  
  133         60794  
5 133     133   645 use parent "Perl::Lint::Policy";
  133         165  
  133         554  
6              
7             use constant {
8 133         91442 DESC => 'Return value of eval not tested.',
9             EXPL => q{You can't depend upon the value of $@/$EVAL_ERROR to tell whether an eval failed.},
10 133     133   6843 };
  133         160  
11              
12             sub evaluate {
13 17     17 0 26 my ($class, $file, $tokens, $args) = @_;
14              
15 17         11 my @violations;
16 17         18 my $token_num = scalar @$tokens;
17 17         16 my $assigned = 0;
18 17         13 my $is_in_grep = 0;
19 17         11 my $left_paren_num = 0;
20 17         15 my $left_brace_num = 0;
21 17         15 my $left_bracket_num = 0;
22 17         34 for (my $i = 0; $i < $token_num; $i++) {
23 719         524 my $token = $tokens->[$i];
24 719         467 my $token_type = $token->{type};
25 719         519 my $token_data = $token->{data};
26              
27 719 100 100     5265 if ($token_type == ASSIGN) {
    100 100        
    100 100        
    100 100        
    100 100        
    100 66        
    100          
    100          
    100          
    100          
    100          
    100          
    100          
    100          
28 29         71 $assigned = 1;
29             }
30             elsif ($token_type == COMMA) {
31 23 100 66     96 if (
      100        
32             $left_paren_num <= 0 &&
33             $left_brace_num <= 0 &&
34             $left_bracket_num <= 0
35             ) {
36 17         24 $assigned = 0;
37             }
38             }
39             elsif ($token_type == LEFT_PAREN) {
40 14         19 $left_paren_num++;
41             }
42             elsif ($token_type == LEFT_BRACE) {
43 97         133 $left_brace_num++;
44             }
45             elsif ($token_type == LEFT_BRACKET) {
46 11         19 $left_bracket_num++;
47             }
48             elsif ($token_type == RIGHT_PAREN) {
49 14         19 $left_paren_num--;
50             }
51             elsif ($token_type == RIGHT_BRACE) {
52 96         152 $left_brace_num--;
53             }
54             elsif ($token_type == RIGHT_BRACKET) {
55 11         17 $left_bracket_num--;
56             }
57             elsif ($token_type == BUILTIN_FUNC && $token_data eq 'grep') {
58 1         3 $is_in_grep = 1;
59             }
60             elsif (
61             !$assigned &&
62             !$is_in_grep &&
63             $token_type == BUILTIN_FUNC &&
64             $token_data eq 'eval'
65             ) {
66 36         32 my $is_ternary = 0;
67 36         21 my $is_proper = 0;
68 36         27 my $left_brace_num = 0;
69              
70             # XXX not good cuz run twice
71 36         57 for (my $j = $i + 1; $j < $token_num; $j++) {
72 266         180 my $token = $tokens->[$j];
73 266         170 my $token_type = $token->{type};
74              
75 266 100 100     1398 if ($token_type == LEFT_BRACE) {
    100 66        
    100 100        
    100 100        
    100          
76 37         53 $left_brace_num++;
77             }
78             elsif ($token_type == RIGHT_BRACE) {
79 43         54 $left_brace_num--;
80             }
81             elsif ($token_type == THREE_TERM_OP) {
82 2         4 $is_ternary = 1;
83             }
84             elsif (
85             $left_brace_num <= 0 &&
86             (
87             $token_type == AND ||
88             $token_type == OR ||
89             $token_type == ALPHABET_AND ||
90             $token_type == ALPHABET_OR
91             )
92             ) {
93 8         11 $is_proper = 1;
94             }
95             elsif (
96             $left_brace_num <= 0 &&
97             $token_type == SEMI_COLON ||
98             !$tokens->[$j+1]
99             ) {
100 36         32 last;
101             }
102             }
103              
104 36 100 66     75 if (!$is_ternary && !$is_proper) {
105             push @violations, {
106             filename => $file,
107             line => $token->{line},
108 26         103 description => DESC,
109             explanation => EXPL,
110             policy => __PACKAGE__,
111             };
112             }
113             }
114             elsif ($token_type == IF_STATEMENT) {
115 28         25 my $left_paren_num = 0;
116 28         14 my $left_paren_found = 0;
117 28         17 my $exists_eval = 0;
118 28         19 my $exists_eval_global = 0;
119 28         16 my $exists_comma = 0;
120 28         43 my $last_token = {type => -1, data => ''};
121 28         44 for ($i++; $i < $token_num; $i++) {
122 254         163 my $token = $tokens->[$i];
123 254         173 my $token_type = $token->{type};
124              
125 254 100 100     607 if ($token_type == BUILTIN_FUNC && $token->{data} eq 'eval') {
    100          
    100          
    100          
126 30         20 $exists_eval = 1;
127 30         23 $exists_eval_global = 1;
128             }
129             elsif ($token_type == COMMA) {
130 22         15 $exists_comma = 1;
131              
132 22         20 my $next_token = $tokens->[$i + 1];
133 22         16 my $next_token_type = $next_token->{type};
134 22 100 100     59 if (
135             $next_token_type != COMMA &&
136             $next_token_type != RIGHT_PAREN
137             ) {
138 16         13 $last_token = $next_token;
139             }
140             }
141             elsif ($token_type == LEFT_PAREN) {
142 41         26 $left_paren_num++;
143 41         23 $left_paren_found++;
144 41         25 $exists_eval = 0;
145 41         28 $exists_comma = 0;
146             }
147             elsif ($token_type == RIGHT_PAREN) {
148 41 100 66     177 if (
      66        
      66        
      100        
149             $last_token->{type} != BUILTIN_FUNC &&
150             $last_token->{data} ne 'eval' &&
151             ($exists_eval_global || $exists_eval) && $exists_comma
152             ) {
153             push @violations, {
154             filename => $file,
155             line => $token->{line},
156 8         26 description => DESC,
157             explanation => EXPL,
158             policy => __PACKAGE__,
159             };
160             }
161 41         24 $left_paren_num--;
162 41         31 $exists_eval = 0;
163 41         24 $exists_comma = 0;
164             }
165              
166 254 100 100     1250 if (
      66        
      100        
167             ($left_paren_num <= 0 && $left_paren_found) ||
168             $token == SEMI_COLON ||
169             !$tokens->[$i+1]
170             ) {
171 28         52 last;
172             }
173             }
174             }
175             elsif (
176             $token_type == FOREACH_STATEMENT ||
177             $token_type == WHILE_STATEMENT
178             ) {
179 21         12 my $left_paren_num = 0;
180 21         19 my $left_paren_found = 0;
181 21         29 for ($i++; $i < $token_num; $i++) {
182 187         136 my $token = $tokens->[$i];
183 187         112 my $token_type = $token->{type};
184              
185 187 100       254 if ($token_type == LEFT_PAREN) {
    100          
186 26         20 $left_paren_num++;
187 26         16 $left_paren_found++;
188             }
189             elsif ($token_type == RIGHT_PAREN) {
190 26         15 $left_paren_num--;
191             }
192              
193 187 100 100     883 if (
      66        
      100        
194             ($left_paren_num <= 0 && $left_paren_found) ||
195             $token == SEMI_COLON ||
196             !$tokens->[$i+1]
197             ) {
198 21         31 last;
199             }
200             }
201             }
202             elsif ($token_type == FOR_STATEMENT) {
203 12         6 my $left_paren_num = 0;
204 12         12 my $left_paren_found = 0;
205 12         7 my $assigned = 0;
206 12         9 my $block = 1;
207 12         20 for ($i++; $i < $token_num; $i++) {
208 145         126 my $token = $tokens->[$i];
209 145         106 my $token_type = $token->{type};
210              
211 145 100 100     552 if ($token_type == ASSIGN) {
    100 100        
    100 66        
    100          
    100          
212 4         4 $assigned = 1;
213             }
214             elsif ($token_type == LEFT_PAREN) {
215 16         10 $left_paren_num++;
216 16         14 $left_paren_found++;
217             }
218             elsif ($token_type == RIGHT_PAREN) {
219 16         11 $left_paren_num--;
220             }
221             elsif ($token_type == SEMI_COLON) {
222 31         19 $block++;
223 31         24 $assigned = 0;
224             }
225             elsif (
226             !$assigned &&
227             $block & 1 &&
228             $token_type == BUILTIN_FUNC &&
229             $token->{data} eq 'eval'
230             ) {
231             push @violations, {
232             filename => $file,
233             line => $token->{line},
234 4         12 description => DESC,
235             explanation => EXPL,
236             policy => __PACKAGE__,
237             };
238             }
239              
240 145 100 66     355 if ($left_paren_num <= 0 && $left_paren_found) {
241 12         26 last;
242             }
243             }
244             }
245             elsif ($token_type == SEMI_COLON || !$tokens->[$i+1]) {
246 75         54 $assigned = 0;
247 75         126 $is_in_grep = 0;
248             }
249             }
250 17         63 return \@violations;
251             }
252              
253             1;
254