File Coverage

blib/lib/Perl/Lint/Policy/InputOutput/RequireCheckedClose.pm
Criterion Covered Total %
statement 95 109 87.1
branch 57 78 73.0
condition 24 48 50.0
subroutine 7 7 100.0
pod 0 1 0.0
total 183 243 75.3


line stmt bran cond sub pod time code
1             package Perl::Lint::Policy::InputOutput::RequireCheckedClose;
2 134     134   71164 use strict;
  134         190  
  134         3327  
3 134     134   445 use warnings;
  134         170  
  134         2548  
4 134     134   820 use Perl::Lint::Constants::Type;
  134         170  
  134         60380  
5 134     134   911 use Perl::Lint::Constants::Kind;
  134         192  
  134         6469  
6 134     134   488 use parent "Perl::Lint::Policy";
  134         176  
  134         572  
7              
8             use constant {
9 134         90376 DESC => 'Return value of "close" ignored',
10             EXPL => 'Check the return value of "close" for success',
11 134     134   6751 };
  134         193  
12              
13             sub evaluate {
14 22     22 0 28 my ($class, $file, $tokens, $src, $args) = @_;
15              
16 22         19 my $is_in_assign_context = 0;
17 22         19 my $is_in_statement_context = 0;
18 22         12 my $is_called_close_in_void = 0;
19 22         27 my $is_enabled_autodie = 0;
20 22         24 my @violations;
21 22         52 for (my $i = 0; my $token = $tokens->[$i]; $i++) {
22 288         196 my $token_type = $token->{type};
23 288         196 my $token_kind = $token->{kind};
24 288         195 my $token_data = $token->{data};
25              
26 288 100       321 if ($token_type == ASSIGN) {
27 5         7 $is_in_assign_context = 1;
28 5         7 next;
29             }
30              
31 283 100       313 if ($token_type == USED_NAME) {
32 18 100       34 if ($token_data eq 'Fatal') {
    100          
33 6         8 my $next_token = $tokens->[$i+1];
34 6         7 my $next_token_type = $next_token->{type};
35 6 100 66     31 if ($next_token_type == REG_LIST) {
    100 33        
    50          
36 2         5 for ($i += 3; my $token = $tokens->[$i]; $i++) {
37 3         3 my $token_type = $token->{type};
38 3 100 100     26 if ($token_type == REG_EXP && $token->{data} eq 'close') {
    100          
39 1         5 return [];
40             }
41             elsif ($token_type == REG_DELIM) {
42 1         3 last;
43             }
44             }
45             }
46             elsif ($next_token_type == LEFT_PAREN) {
47 2         4 my $left_paren_num = 1;
48 2         6 for ($i += 2; my $token = $tokens->[$i]; $i++) {
49 2         3 my $token_type = $token->{type};
50 2 50 66     16 if ($token_type == LEFT_PAREN) {
    50 33        
51 0         0 $left_paren_num++;
52             }
53             elsif (($token_type == STRING || $token_type == RAW_STRING) && $token->{data} eq 'close') {
54 2         8 return [];
55             }
56             else {
57 0 0       0 last if --$left_paren_num <= 0;
58             }
59             }
60             }
61             elsif (($next_token_type == STRING || $next_token_type == RAW_STRING) && $next_token->{data} eq 'close') {
62 2         3 last;
63             }
64             }
65             elsif ($token_data eq 'autodie') {
66 4 100       12 if ($tokens->[$i+1]->{type} == REG_LIST) {
67 2         5 for ($i += 3; my $token = $tokens->[$i]; $i++) {
68 4         4 my $token_type = $token->{type};
69 4 100 100     31 if ($token_type == REG_EXP && $token->{data} =~ /\A\s*:io\s*\Z/) {
    100          
70 1         2 $is_enabled_autodie = 1;
71             }
72             elsif ($token_type == REG_DELIM) {
73 2         3 last;
74             }
75             }
76             }
77             else {
78 2         3 $is_enabled_autodie = 1;
79             }
80             }
81              
82 13         19 next;
83             }
84              
85 265 100 66     389 if ($token_type == NAMESPACE && $token_data eq 'Fatal') {
86 1         3 my $skipped_token = $tokens->[$i+2];
87 1 50 33     10 if ($skipped_token && $skipped_token->{type} == NAMESPACE && $skipped_token->{data} eq 'Exception') {
      33        
88 1         4 for ($i += 3; my $token = $tokens->[$i]; $i++) {
89 3         4 my $token_type = $token->{type};
90 3 100 66     20 if ($token_type == REG_LIST) {
    50 66        
    50          
    50          
91 1         3 for ($i += 2; my $token = $tokens->[$i]; $i++) {
92 1         2 my $token_type = $token->{type};
93 1 50 33     12 if ($token_type == REG_EXP && $token->{data} eq 'close') {
    0          
94 1         6 return [];
95             }
96             elsif ($token_type == REG_DELIM) {
97 0         0 last;
98             }
99             }
100             }
101             elsif ($token_type == LEFT_PAREN) {
102 0         0 my $left_paren_num = 1;
103 0         0 for ($i++; my $token = $tokens->[$i]; $i++) {
104 0         0 my $token_type = $token->{type};
105 0 0 0     0 if ($token_type == LEFT_PAREN) {
    0 0        
106 0         0 $left_paren_num++;
107             }
108             elsif (($token_type == STRING || $token_type == RAW_STRING) && $token->{data} eq 'close') {
109 0         0 return [];
110             }
111             else {
112 0 0       0 last if --$left_paren_num <= 0;
113             }
114             }
115             }
116             elsif (($token_type == STRING || $token_type == RAW_STRING) && $token->{data} eq 'close') {
117 0         0 last;
118             }
119             elsif ($token->{kind} == KIND_STMT_END) {
120 0         0 last;
121             }
122             }
123             }
124              
125 0         0 next;
126             }
127              
128 264 100       291 if ($token_kind == KIND_STMT) {
129 14         12 $is_in_statement_context = 1;
130              
131 14 100       29 if ($tokens->[$i+1]->{type} == LEFT_PAREN) {
132 2         3 $i++;
133 2         3 my $left_paren_num = 1;
134 2         12 for ($i++; my $token = $tokens->[$i]; $i++) {
135 2         3 my $token_type = $token->{type};
136 2 50       6 if ($token_type == LEFT_PAREN) {
137 0         0 $left_paren_num++;
138             }
139             else {
140 2 50       7 last if --$left_paren_num <= 0;
141             }
142             }
143             }
144 14         23 next;
145             }
146              
147 250 100       308 if ($token_type == BUILTIN_FUNC) {
148 46 100       68 if ($token_data eq 'close') {
    100          
149 34 100 66     73 if (!$is_in_assign_context && !$is_in_statement_context) {
150 18         15 $is_called_close_in_void = 1;
151             }
152             }
153             elsif ($token_data eq 'no') {
154 1         2 my $next_token = $tokens->[++$i];
155 1 50 33     7 if ($next_token->{type} == KEY && $next_token->{data} eq 'autodie') {
156 1         2 $is_enabled_autodie = 0;
157             }
158             }
159 46         67 next;
160             }
161              
162 204 100       220 if ($token_kind == KIND_OP) {
163 8         8 $is_called_close_in_void = 0;
164 8         11 next;
165             }
166              
167 196 100       317 if ($token_kind == KIND_STMT_END) {
168 53 100       69 next if $is_enabled_autodie;
169              
170 48 100       58 if ($is_called_close_in_void) {
171             push @violations, {
172             filename => $file,
173             line => $token->{line},
174 10         31 description => DESC,
175             explanation => EXPL,
176             policy => __PACKAGE__,
177             };
178             }
179              
180 48         38 $is_in_assign_context = 0;
181 48         29 $is_in_statement_context = 0;
182 48         29 $is_called_close_in_void = 0;
183 48         72 next;
184             }
185              
186             }
187              
188 18         97 return \@violations;
189             }
190              
191             1;
192