line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Perl::Lint::Policy::Variables::ProhibitPunctuationVars; |
2
|
134
|
|
|
134
|
|
78041
|
use strict; |
|
134
|
|
|
|
|
172
|
|
|
134
|
|
|
|
|
3089
|
|
3
|
134
|
|
|
134
|
|
429
|
use warnings; |
|
134
|
|
|
|
|
147
|
|
|
134
|
|
|
|
|
2583
|
|
4
|
134
|
|
|
134
|
|
830
|
use Compiler::Lexer; |
|
134
|
|
|
|
|
5861
|
|
|
134
|
|
|
|
|
4322
|
|
5
|
134
|
|
|
134
|
|
442
|
use List::Util qw/any/; |
|
134
|
|
|
|
|
138
|
|
|
134
|
|
|
|
|
9098
|
|
6
|
134
|
|
|
134
|
|
1271
|
use Perl::Lint::Constants::Type; |
|
134
|
|
|
|
|
143
|
|
|
134
|
|
|
|
|
60223
|
|
7
|
134
|
|
|
134
|
|
547
|
use parent "Perl::Lint::Policy"; |
|
134
|
|
|
|
|
176
|
|
|
134
|
|
|
|
|
568
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
use constant { |
10
|
134
|
|
|
|
|
99523
|
DESC => 'Magic punctuation variable %s used', |
11
|
|
|
|
|
|
|
EXPL => [79], |
12
|
134
|
|
|
134
|
|
6947
|
}; |
|
134
|
|
|
|
|
175
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
my %var_token_types = ( |
15
|
|
|
|
|
|
|
&VAR => 1, |
16
|
|
|
|
|
|
|
&ARRAY_VAR => 1, |
17
|
|
|
|
|
|
|
&HASH_VAR => 1, |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
&GLOBAL_VAR => 1, |
20
|
|
|
|
|
|
|
&GLOBAL_ARRAY_VAR => 1, |
21
|
|
|
|
|
|
|
&GLOBAL_HASH_VAR => 1, |
22
|
|
|
|
|
|
|
); |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
my %expands_regexp_token_types = ( |
25
|
|
|
|
|
|
|
®_EXEC => 1, |
26
|
|
|
|
|
|
|
®_DECL => 1, |
27
|
|
|
|
|
|
|
®_DOUBLE_QUOTE => 1, |
28
|
|
|
|
|
|
|
); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
my %special_variable_token_types = ( |
31
|
|
|
|
|
|
|
&SPECIFIC_VALUE => 1, |
32
|
|
|
|
|
|
|
&ARRAY_SIZE => 1, |
33
|
|
|
|
|
|
|
); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
my %magic_variables = ( |
36
|
|
|
|
|
|
|
'$1' => 1, '$2' => 1, '$3' => 1, |
37
|
|
|
|
|
|
|
'$4' => 1, '$5' => 1, '$6' => 1, |
38
|
|
|
|
|
|
|
'$7' => 1, '$8' => 1, '$9' => 1, |
39
|
|
|
|
|
|
|
'$_' => 1, '$&' => 1, '$`' => 1, |
40
|
|
|
|
|
|
|
'$+' => 1, '@+' => 1, '@*' => 1, |
41
|
|
|
|
|
|
|
'%+' => 1, '$*' => 1, '$.' => 1, |
42
|
|
|
|
|
|
|
'$/' => 1, '$|' => 1, '$(' => 1, |
43
|
|
|
|
|
|
|
'$"' => 1, '$;' => 1, '$%' => 1, |
44
|
|
|
|
|
|
|
'$=' => 1, '$-' => 1, '@-' => 1, |
45
|
|
|
|
|
|
|
'%-' => 1, '$)' => 1, '$~' => 1, |
46
|
|
|
|
|
|
|
'$^' => 1, '$:' => 1, '$?' => 1, |
47
|
|
|
|
|
|
|
'$!' => 1, '%!' => 1, '$@' => 1, |
48
|
|
|
|
|
|
|
'$$' => 1, '$<' => 1, '$>' => 1, |
49
|
|
|
|
|
|
|
'$0' => 1, '$[' => 1, '$]' => 1, |
50
|
|
|
|
|
|
|
'@_' => 1, |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
q{$'} => 1, |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
'$^L' => 1, '$^A' => 1, '$^E' => 1, |
55
|
|
|
|
|
|
|
'$^C' => 1, '$^D' => 1, '$^F' => 1, |
56
|
|
|
|
|
|
|
'$^H' => 1, '$^I' => 1, '$^M' => 1, |
57
|
|
|
|
|
|
|
'$^N' => 1, '$^O' => 1, '$^P' => 1, |
58
|
|
|
|
|
|
|
'$^R' => 1, '$^S' => 1, '$^T' => 1, |
59
|
|
|
|
|
|
|
'$^V' => 1, '$^W' => 1, '$^X' => 1, |
60
|
|
|
|
|
|
|
'%^H' => 1, |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
'$\\' => 1, |
63
|
|
|
|
|
|
|
'$::|' => 1, |
64
|
|
|
|
|
|
|
'$}' => 1, |
65
|
|
|
|
|
|
|
'$,' => 1, |
66
|
|
|
|
|
|
|
'$#' => 1, |
67
|
|
|
|
|
|
|
'$#+' => 1, |
68
|
|
|
|
|
|
|
'$#-' => 1, |
69
|
|
|
|
|
|
|
); |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
my %ignore_for_interpolation = ( |
72
|
|
|
|
|
|
|
q{$'} => 1, |
73
|
|
|
|
|
|
|
q{$$} => 1, |
74
|
|
|
|
|
|
|
q{$#} => 1, |
75
|
|
|
|
|
|
|
q{$:} => 1, |
76
|
|
|
|
|
|
|
); |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub evaluate { |
79
|
29
|
|
|
29
|
0
|
50
|
my ($class, $file, $tokens, $src, $args) = @_; |
80
|
|
|
|
|
|
|
|
81
|
29
|
|
|
|
|
33
|
my $string_mode = ''; |
82
|
29
|
|
|
|
|
202
|
my %exempt_vars = ( |
83
|
|
|
|
|
|
|
'$_' => 1, '@_' => 1, '$]' => 1, |
84
|
|
|
|
|
|
|
'$1' => 1, '$2' => 1, '$3' => 1, |
85
|
|
|
|
|
|
|
'$4' => 1, '$5' => 1, '$6' => 1, |
86
|
|
|
|
|
|
|
'$7' => 1, '$8' => 1, '$9' => 1, |
87
|
|
|
|
|
|
|
); |
88
|
|
|
|
|
|
|
|
89
|
29
|
100
|
|
|
|
74
|
if (my $this_policies_arg = $args->{prohibit_punctuation_vars}) { |
90
|
9
|
|
100
|
|
|
39
|
$string_mode = $this_policies_arg->{string_mode} || ''; |
91
|
9
|
100
|
|
|
|
28
|
if ($string_mode eq 'thorough') { |
92
|
3
|
|
|
|
|
7
|
%exempt_vars = (); |
93
|
|
|
|
|
|
|
} |
94
|
|
|
|
|
|
|
|
95
|
9
|
|
100
|
|
|
64
|
for my $exempt_var (split(/\s+/, $this_policies_arg->{allow} || '')) { |
96
|
6
|
|
|
|
|
10
|
$exempt_vars{$exempt_var} = 1; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
29
|
|
|
|
|
92
|
my $lexer_for_str = Compiler::Lexer->new; |
101
|
|
|
|
|
|
|
|
102
|
29
|
|
|
|
|
282
|
my @violations; |
103
|
29
|
|
|
|
|
105
|
for ( |
104
|
|
|
|
|
|
|
my $i = 0, my $token_type, my $token_data, my $is_ref = 0, my $is_raw_heredoc_tag = 0; |
105
|
|
|
|
|
|
|
my $token = $tokens->[$i]; |
106
|
|
|
|
|
|
|
$i++ |
107
|
|
|
|
|
|
|
) { |
108
|
514
|
|
|
|
|
432
|
$token_type = $token->{type}; |
109
|
514
|
|
|
|
|
386
|
$token_data = $token->{data}; |
110
|
|
|
|
|
|
|
|
111
|
514
|
100
|
|
|
|
698
|
if ($special_variable_token_types{$token_type}) { |
112
|
15
|
100
|
|
|
|
26
|
if ($is_ref) { |
113
|
1
|
|
|
|
|
2
|
$is_ref = 0; |
114
|
1
|
|
|
|
|
2
|
next; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
14
|
100
|
|
|
|
25
|
if ($exempt_vars{$token_data}) { |
118
|
7
|
|
|
|
|
11
|
next; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
7
|
50
|
|
|
|
17
|
if (! $magic_variables{$token_data}) { |
122
|
0
|
|
|
|
|
0
|
next; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
push @violations, { |
126
|
|
|
|
|
|
|
filename => $file, |
127
|
|
|
|
|
|
|
line => $token->{line}, |
128
|
7
|
|
|
|
|
43
|
description => sprintf(DESC, $token_data), |
129
|
|
|
|
|
|
|
explanation => EXPL, |
130
|
|
|
|
|
|
|
policy => __PACKAGE__, |
131
|
|
|
|
|
|
|
}; |
132
|
7
|
|
|
|
|
16
|
next; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
499
|
100
|
|
|
|
592
|
if ($var_token_types{$token_type}) { |
136
|
14
|
50
|
|
|
|
28
|
if ($is_ref) { |
137
|
0
|
|
|
|
|
0
|
$is_ref = 0; |
138
|
0
|
|
|
|
|
0
|
next; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
14
|
50
|
|
|
|
25
|
if ($exempt_vars{$token_data}) { |
142
|
0
|
|
|
|
|
0
|
next; |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
|
145
|
14
|
100
|
|
|
|
26
|
if (! $magic_variables{$token_data}) { |
146
|
13
|
|
|
|
|
22
|
next; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
1
|
50
|
|
|
|
6
|
if (substr($token_data, 1, 1) =~ /\A[^a-zA-Z]\Z/) { |
150
|
|
|
|
|
|
|
push @violations, { |
151
|
|
|
|
|
|
|
filename => $file, |
152
|
|
|
|
|
|
|
line => $token->{line}, |
153
|
1
|
|
|
|
|
8
|
description => sprintf(DESC, $token_data), |
154
|
|
|
|
|
|
|
explanation => EXPL, |
155
|
|
|
|
|
|
|
policy => __PACKAGE__, |
156
|
|
|
|
|
|
|
}; |
157
|
|
|
|
|
|
|
} |
158
|
1
|
|
|
|
|
3
|
next; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
485
|
100
|
|
|
|
599
|
if ($token_type == REF) { |
162
|
1
|
|
|
|
|
3
|
$is_ref = 1; |
163
|
1
|
|
|
|
|
2
|
next; |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
484
|
50
|
|
|
|
556
|
if ($token_type == HERE_DOCUMENT_RAW_TAG) { |
167
|
0
|
|
|
|
|
0
|
$is_raw_heredoc_tag = 1; |
168
|
0
|
|
|
|
|
0
|
next; |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
484
|
50
|
|
|
|
533
|
if ($token_type == HERE_DOCUMENT_END) { |
172
|
0
|
|
|
|
|
0
|
$is_raw_heredoc_tag = 0; |
173
|
0
|
|
|
|
|
0
|
next; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
484
|
100
|
|
|
|
570
|
if ($expands_regexp_token_types{$token_type}) { |
177
|
11
|
|
|
|
|
15
|
$i += 2; |
178
|
11
|
|
|
|
|
10
|
$token = $tokens->[$i]; |
179
|
11
|
50
|
|
|
|
21
|
if ($token->{type} != REG_EXP) { # when content is empty |
180
|
0
|
|
|
|
|
0
|
next; |
181
|
|
|
|
|
|
|
} |
182
|
11
|
|
|
|
|
32
|
$token_data = $token->data; |
183
|
11
|
|
|
|
|
52
|
$token_type = STRING; |
184
|
|
|
|
|
|
|
} # fall through |
185
|
|
|
|
|
|
|
|
186
|
484
|
100
|
100
|
|
|
1489
|
if ( |
187
|
|
|
|
|
|
|
$token_type == STRING || |
188
|
|
|
|
|
|
|
$token_type == EXEC_STRING |
189
|
|
|
|
|
|
|
# ($token_type == HERE_DOCUMENT && $is_raw_heredoc_tag) |
190
|
|
|
|
|
|
|
) { |
191
|
114
|
100
|
|
|
|
187
|
if ($string_mode eq 'disable') { |
192
|
1
|
|
|
|
|
5
|
next; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
113
|
|
|
|
|
4968
|
my $parts = $lexer_for_str->tokenize($token_data); |
196
|
113
|
|
|
|
|
128
|
my $ref_count = 0; |
197
|
113
|
|
|
|
|
234
|
for (my $j = 0, my $part_type, my $used_var; my $part = $parts->[$j]; $j++) { |
198
|
266
|
|
|
|
|
230
|
$part_type = $part->{type}; |
199
|
266
|
|
|
|
|
186
|
$used_var = $part->{data}; |
200
|
|
|
|
|
|
|
|
201
|
266
|
100
|
|
|
|
325
|
if ($part_type == REF) { |
202
|
26
|
|
|
|
|
24
|
$ref_count++; |
203
|
26
|
|
|
|
|
43
|
next; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
240
|
100
|
|
|
|
335
|
if ($ref_count % 2 != 0) { |
207
|
17
|
|
|
|
|
21
|
$ref_count = 0; |
208
|
17
|
|
|
|
|
27
|
next; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
223
|
100
|
|
|
|
328
|
if ($part_type == SPECIFIC_VALUE) { |
|
|
100
|
|
|
|
|
|
212
|
98
|
100
|
|
|
|
126
|
if ($used_var eq '$:') { |
213
|
13
|
|
|
|
|
22
|
$part = $parts->[$j+1]; |
214
|
|
|
|
|
|
|
|
215
|
13
|
100
|
100
|
|
|
48
|
if ($part && $part->{type} == COLON) { |
216
|
7
|
|
|
|
|
11
|
$part = $parts->[$j+2]; |
217
|
7
|
100
|
100
|
|
|
26
|
if ($part && $part->{type} == BIT_OR) { |
218
|
1
|
|
|
|
|
1
|
$used_var = '$::|'; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
else { |
221
|
6
|
|
|
|
|
12
|
next; |
222
|
|
|
|
|
|
|
} |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
} |
225
|
|
|
|
|
|
|
# TODO |
226
|
|
|
|
|
|
|
# elsif ($used_var eq q{$'}) { |
227
|
|
|
|
|
|
|
# $part = $parts->[$j+1]; |
228
|
|
|
|
|
|
|
# if ($part && $part->{type} == KEY) { |
229
|
|
|
|
|
|
|
# # next; |
230
|
|
|
|
|
|
|
# } |
231
|
|
|
|
|
|
|
# } |
232
|
|
|
|
|
|
|
} |
233
|
|
|
|
|
|
|
elsif ($part_type != ARRAY_SIZE) { |
234
|
120
|
100
|
|
|
|
160
|
if (!$var_token_types{$part_type}) { |
235
|
113
|
|
|
|
|
185
|
next; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
7
|
|
|
|
|
9
|
$part = $parts->[++$j]; |
239
|
7
|
100
|
|
|
|
15
|
if ($part) { |
240
|
3
|
100
|
|
|
|
21
|
if ($used_var eq '$') { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
241
|
1
|
50
|
|
|
|
4
|
if ($part->{type} == RIGHT_BRACE) { |
242
|
1
|
|
|
|
|
1
|
$used_var = '$}'; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
elsif ($used_var eq '@') { |
246
|
1
|
50
|
|
|
|
4
|
if ($part->{type} == MUL) { |
247
|
1
|
|
|
|
|
2
|
$used_var = '@*'; |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
} |
250
|
|
|
|
|
|
|
elsif ($used_var eq '%-') { |
251
|
1
|
50
|
|
|
|
4
|
if ($part->{type} == INT) { # for formatting. e.g. "%-04f" |
252
|
1
|
|
|
|
|
3
|
next; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
|
258
|
103
|
100
|
|
|
|
150
|
if ($exempt_vars{$used_var}) { |
259
|
4
|
|
|
|
|
8
|
next; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
99
|
100
|
66
|
|
|
159
|
if ($string_mode eq 'simple' && $ignore_for_interpolation{$used_var}) { |
263
|
4
|
|
|
|
|
7
|
next; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
95
|
100
|
|
|
|
157
|
if ($magic_variables{$used_var}) { |
267
|
|
|
|
|
|
|
push @violations, { |
268
|
|
|
|
|
|
|
filename => $file, |
269
|
|
|
|
|
|
|
line => $token->{line}, |
270
|
93
|
|
|
|
|
555
|
description => sprintf(DESC, $used_var), |
271
|
|
|
|
|
|
|
explanation => EXPL, |
272
|
|
|
|
|
|
|
policy => __PACKAGE__, |
273
|
|
|
|
|
|
|
}; |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
113
|
|
|
|
|
360
|
next; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
29
|
|
|
|
|
226
|
return \@violations; |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
1; |
285
|
|
|
|
|
|
|
|