line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Perl::Critic::Policy::Variables::ProhibitPunctuationVars; |
2
|
|
|
|
|
|
|
|
3
|
40
|
|
|
40
|
|
29622
|
use 5.010001; |
|
40
|
|
|
|
|
201
|
|
4
|
40
|
|
|
40
|
|
275
|
use strict; |
|
40
|
|
|
|
|
132
|
|
|
40
|
|
|
|
|
908
|
|
5
|
40
|
|
|
40
|
|
235
|
use warnings; |
|
40
|
|
|
|
|
122
|
|
|
40
|
|
|
|
|
973
|
|
6
|
40
|
|
|
40
|
|
253
|
use Readonly; |
|
40
|
|
|
|
|
143
|
|
|
40
|
|
|
|
|
2858
|
|
7
|
40
|
|
|
40
|
|
354
|
use English qw< -no_match_vars >; |
|
40
|
|
|
|
|
127
|
|
|
40
|
|
|
|
|
403
|
|
8
|
|
|
|
|
|
|
|
9
|
40
|
|
|
40
|
|
17590
|
use PPI::Token::Magic; |
|
40
|
|
|
|
|
117
|
|
|
40
|
|
|
|
|
1983
|
|
10
|
|
|
|
|
|
|
|
11
|
40
|
|
|
|
|
2688
|
use Perl::Critic::Utils qw< |
12
|
|
|
|
|
|
|
:characters :severities :data_conversion :booleans |
13
|
40
|
|
|
40
|
|
274
|
>; |
|
40
|
|
|
|
|
114
|
|
14
|
|
|
|
|
|
|
|
15
|
40
|
|
|
40
|
|
15273
|
use PPIx::Regexp; |
|
40
|
|
|
|
|
180
|
|
|
40
|
|
|
|
|
2010
|
|
16
|
40
|
|
|
|
|
2349
|
use PPIx::Regexp::Util 0.068 qw< |
17
|
|
|
|
|
|
|
is_ppi_regexp_element |
18
|
40
|
|
|
40
|
|
308
|
>; |
|
40
|
|
|
|
|
1067
|
|
19
|
|
|
|
|
|
|
|
20
|
40
|
|
|
40
|
|
326
|
use parent 'Perl::Critic::Policy'; |
|
40
|
|
|
|
|
141
|
|
|
40
|
|
|
|
|
341
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our $VERSION = '1.146'; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
Readonly::Scalar my $DESC => q<Magic punctuation variable %s used>; |
27
|
|
|
|
|
|
|
Readonly::Scalar my $EXPL => [79]; |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# There is no English.pm equivalent for $]. |
32
|
|
|
|
|
|
|
sub supported_parameters { |
33
|
|
|
|
|
|
|
return ( |
34
|
|
|
|
|
|
|
{ |
35
|
123
|
|
|
123
|
0
|
3343
|
name => 'allow', |
36
|
|
|
|
|
|
|
description => 'The additional variables to allow.', |
37
|
|
|
|
|
|
|
default_string => $EMPTY, |
38
|
|
|
|
|
|
|
behavior => 'string list', |
39
|
|
|
|
|
|
|
list_always_present_values => |
40
|
|
|
|
|
|
|
[ qw< $_ @_ $1 $2 $3 $4 $5 $6 $7 $8 $9 _ $] > ], |
41
|
|
|
|
|
|
|
}, |
42
|
|
|
|
|
|
|
{ |
43
|
|
|
|
|
|
|
name => 'string_mode', |
44
|
|
|
|
|
|
|
description => |
45
|
|
|
|
|
|
|
'Controls checking interpolated strings for punctuation variables.', |
46
|
|
|
|
|
|
|
default_string => 'thorough', |
47
|
|
|
|
|
|
|
behavior => 'enumeration', |
48
|
|
|
|
|
|
|
enumeration_values => [ qw< simple disable thorough > ], |
49
|
|
|
|
|
|
|
enumeration_allow_multiple_values => 0, |
50
|
|
|
|
|
|
|
}, |
51
|
|
|
|
|
|
|
); |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
194
|
|
|
194
|
1
|
801
|
sub default_severity { return $SEVERITY_LOW } |
55
|
84
|
|
|
84
|
1
|
370
|
sub default_themes { return qw< core pbp cosmetic > } |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
sub applies_to { |
58
|
61
|
|
|
61
|
1
|
322
|
return qw< |
59
|
|
|
|
|
|
|
PPI::Token::Magic |
60
|
|
|
|
|
|
|
PPI::Token::Quote::Double |
61
|
|
|
|
|
|
|
PPI::Token::Quote::Interpolate |
62
|
|
|
|
|
|
|
PPI::Token::QuoteLike::Command |
63
|
|
|
|
|
|
|
PPI::Token::QuoteLike::Backtick |
64
|
|
|
|
|
|
|
PPI::Token::QuoteLike::Regexp |
65
|
|
|
|
|
|
|
PPI::Token::QuoteLike::Readline |
66
|
|
|
|
|
|
|
PPI::Token::HereDoc |
67
|
|
|
|
|
|
|
>; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
# This list matches the initialization of %PPI::Token::Magic::magic. |
74
|
|
|
|
|
|
|
## no critic (ValuesAndExpressions::RequireInterpolationOfMetachars) |
75
|
|
|
|
|
|
|
Readonly::Array my @MAGIC_VARIABLES => |
76
|
|
|
|
|
|
|
qw{ |
77
|
|
|
|
|
|
|
$1 $2 $3 $4 $5 $6 $7 $8 $9 |
78
|
|
|
|
|
|
|
$_ $& $` $' $+ @+ %+ $* $. $/ $| |
79
|
|
|
|
|
|
|
$\\ $" $; $% $= $- @- %- $) |
80
|
|
|
|
|
|
|
$~ $^ $: $? $! %! $@ $$ $< $> |
81
|
|
|
|
|
|
|
$( $0 $[ $] @_ @* |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
$^L $^A $^E $^C $^D $^F $^H |
84
|
|
|
|
|
|
|
$^I $^M $^N $^O $^P $^R $^S |
85
|
|
|
|
|
|
|
$^T $^V $^W $^X %^H |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
$::| |
88
|
|
|
|
|
|
|
}, |
89
|
|
|
|
|
|
|
q<$}>, |
90
|
|
|
|
|
|
|
q<$,>, |
91
|
|
|
|
|
|
|
q<$#>, |
92
|
|
|
|
|
|
|
q<$#+>, |
93
|
|
|
|
|
|
|
q<$#->; |
94
|
|
|
|
|
|
|
## use critic |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
# The main regular expression for detecting magic variables. |
97
|
|
|
|
|
|
|
Readonly::Scalar my $MAGIC_REGEX => _create_magic_detector(); |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# The magic vars in this array will be ignored in interpolated strings |
100
|
|
|
|
|
|
|
# in simple mode. See CONFIGURATION in the pod. |
101
|
|
|
|
|
|
|
Readonly::Array my @IGNORE_FOR_INTERPOLATION => |
102
|
|
|
|
|
|
|
( q{$'}, q{$$}, q{$#}, q{$:}, ); ## no critic ( RequireInterpolationOfMetachars, ProhibitQuotedWordLists ) |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub violates { |
107
|
167
|
|
|
167
|
1
|
371
|
my ( $self, $elem, $doc ) = @_; |
108
|
|
|
|
|
|
|
|
109
|
167
|
100
|
|
|
|
1313
|
if ( $elem->isa('PPI::Token::Magic') ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
110
|
29
|
|
|
|
|
74
|
return _violates_magic( $self, $elem ); |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
elsif ( $elem->isa('PPI::Token::HereDoc') ) { |
113
|
11
|
|
|
|
|
36
|
return _violates_heredoc( $self, $elem ); |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
elsif ( is_ppi_regexp_element( $elem ) ) { # GitHub #843 |
116
|
4
|
|
|
|
|
86
|
return _violates_regexp( $self, $elem, $doc ); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
#the remaining applies_to() classes are all interpolated strings |
120
|
123
|
|
|
|
|
2291
|
return _violates_string( $self, $elem ); |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# Helper functions for the four types of violations: code, quotes, heredoc, |
126
|
|
|
|
|
|
|
# regexp |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
sub _violates_magic { |
129
|
29
|
|
|
29
|
|
82
|
my ( $self, $elem, undef ) = @_; |
130
|
|
|
|
|
|
|
|
131
|
29
|
100
|
|
|
|
85
|
if ( !exists $self->{_allow}->{$elem} ) { |
132
|
20
|
|
|
|
|
124
|
return $self->_make_violation( $DESC, $EXPL, $elem ); |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
9
|
|
|
|
|
60
|
return; # no violation |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub _violates_string { |
139
|
123
|
|
|
123
|
|
305
|
my ( $self, $elem, undef ) = @_; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# RT #55604: Variables::ProhibitPunctuationVars gives false-positive on |
142
|
|
|
|
|
|
|
# qr// regexp's ending in '$' |
143
|
|
|
|
|
|
|
# We want to analyze the content of the string in the dictionary sense of |
144
|
|
|
|
|
|
|
# the word 'content'. We can not simply use the PPI content() method to |
145
|
|
|
|
|
|
|
# get this, because content() includes the delimiters. |
146
|
123
|
|
|
|
|
236
|
my $string; |
147
|
123
|
100
|
|
|
|
585
|
if ( $elem->can( 'string' ) ) { |
148
|
|
|
|
|
|
|
# If we have a string() method (currently only the PPI::Token::Quote |
149
|
|
|
|
|
|
|
# classes) use it to extract the content of the string. |
150
|
117
|
|
|
|
|
362
|
$string = $elem->string(); |
151
|
|
|
|
|
|
|
} else { |
152
|
|
|
|
|
|
|
# Lacking string(), we fake it under the assumption that the content |
153
|
|
|
|
|
|
|
# of our element represents one of the 'normal' Perl strings, with a |
154
|
|
|
|
|
|
|
# single-character delimiter, possibly preceded by an operator like |
155
|
|
|
|
|
|
|
# 'qx' or 'qr'. If there is a leading operator, spaces may appear |
156
|
|
|
|
|
|
|
# after it. |
157
|
6
|
|
|
|
|
26
|
$string = $elem->content(); |
158
|
6
|
|
|
|
|
47
|
$string =~ s/ \A \w* \s* . //smx; |
159
|
6
|
|
|
|
|
23
|
chop $string; |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
123
|
|
|
|
|
954
|
my %matches = _strings_helper( $self, $string ); |
163
|
123
|
100
|
|
|
|
368
|
if (%matches) { |
164
|
90
|
|
|
|
|
254
|
my $DESC = qq<$DESC in interpolated string>; |
165
|
90
|
|
|
|
|
301
|
return $self->_make_violation( $DESC, $EXPL, $elem, \%matches ); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
33
|
|
|
|
|
141
|
return; # no violation |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub _violates_heredoc { |
172
|
11
|
|
|
11
|
|
26
|
my ( $self, $elem, undef ) = @_; |
173
|
|
|
|
|
|
|
|
174
|
11
|
100
|
100
|
|
|
53
|
if ( $elem->{_mode} eq 'interpolate' or $elem->{_mode} eq 'command' ) { |
175
|
10
|
|
|
|
|
36
|
my $heredoc_string = join "\n", $elem->heredoc(); |
176
|
10
|
|
|
|
|
87
|
my %matches = _strings_helper( $self, $heredoc_string ); |
177
|
10
|
100
|
|
|
|
31
|
if (%matches) { |
178
|
9
|
|
|
|
|
54
|
my $DESC = qq<$DESC in interpolated here-document>; |
179
|
9
|
|
|
|
|
36
|
return $self->_make_violation( $DESC, $EXPL, $elem, \%matches ); |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
2
|
|
|
|
|
10
|
return; # no violation |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
sub _violates_regexp { # GitHub #843 (https://github.com/Perl-Critic/Perl-Critic/issues/843) |
187
|
4
|
|
|
4
|
|
14
|
my ( $self, $elem, $doc ) = @_; |
188
|
|
|
|
|
|
|
|
189
|
4
|
50
|
|
|
|
17
|
return if ( $self->{_string_mode} eq 'disable' ); |
190
|
|
|
|
|
|
|
|
191
|
4
|
50
|
|
|
|
19
|
my $pre = $doc->ppix_regexp_from_element( $elem ) |
192
|
|
|
|
|
|
|
or return; |
193
|
4
|
50
|
|
|
|
15625
|
$pre->failures() |
194
|
|
|
|
|
|
|
and return; |
195
|
|
|
|
|
|
|
|
196
|
4
|
|
|
|
|
31
|
my @raw_matches; |
197
|
4
|
100
|
|
|
|
10
|
foreach my $code ( @{ $pre->find( 'PPIx::Regexp::Token::Code' ) || [] } ) { |
|
4
|
|
|
|
|
18
|
|
198
|
1
|
50
|
|
|
|
185
|
my $code_doc = $code->ppi() |
199
|
|
|
|
|
|
|
or next; |
200
|
1
|
|
|
|
|
214
|
push @raw_matches, map { $_->symbol() } @{ |
201
|
1
|
50
|
|
|
|
13
|
$code_doc->find( 'PPI::Token::Magic' ) || [] }; |
|
1
|
|
|
|
|
5
|
|
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
4
|
|
|
|
|
743
|
my %matches = hashify( @raw_matches ); |
205
|
4
|
|
|
|
|
11
|
delete @matches{ keys %{ $self->{_allow} } }; |
|
4
|
|
|
|
|
32
|
|
206
|
4
|
50
|
|
|
|
23
|
if ( $self->{_string_mode} eq 'simple' ) { |
207
|
0
|
|
|
|
|
0
|
delete @matches{@IGNORE_FOR_INTERPOLATION}; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
|
210
|
4
|
100
|
|
|
|
15
|
if ( keys %matches ) { |
211
|
1
|
|
|
|
|
5
|
my $DESC = qq<$DESC in interpolated Regexp>; |
212
|
1
|
|
|
|
|
7
|
return $self->_make_violation( $DESC, $EXPL, $elem, \%matches ); |
213
|
|
|
|
|
|
|
} |
214
|
|
|
|
|
|
|
|
215
|
3
|
|
|
|
|
19
|
return; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
# Helper functions specific to interpolated strings |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub _strings_helper { |
223
|
133
|
|
|
133
|
|
317
|
my ( $self, $target_string, undef ) = @_; |
224
|
|
|
|
|
|
|
|
225
|
133
|
100
|
|
|
|
439
|
return if ( $self->{_string_mode} eq 'disable' ); |
226
|
|
|
|
|
|
|
return _strings_thorough( $self, $target_string ) |
227
|
132
|
100
|
|
|
|
616
|
if $self->{_string_mode} eq 'thorough'; |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
# we are in string_mode = simple |
230
|
|
|
|
|
|
|
|
231
|
9
|
|
|
|
|
81
|
my @raw_matches = map { _unbracket_variable_name( $_ ) } |
|
10
|
|
|
|
|
33
|
|
232
|
|
|
|
|
|
|
$target_string =~ m/$MAGIC_REGEX/goxms; |
233
|
9
|
50
|
|
|
|
31
|
return if not @raw_matches; |
234
|
|
|
|
|
|
|
|
235
|
9
|
|
|
|
|
30
|
my %matches = hashify(@raw_matches); |
236
|
|
|
|
|
|
|
|
237
|
9
|
|
|
|
|
23
|
delete @matches{ keys %{ $self->{_allow} } }; |
|
9
|
|
|
|
|
48
|
|
238
|
9
|
|
|
|
|
50
|
delete @matches{@IGNORE_FOR_INTERPOLATION}; |
239
|
|
|
|
|
|
|
|
240
|
9
|
|
|
|
|
225
|
return %matches; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
sub _strings_thorough { |
244
|
123
|
|
|
123
|
|
286
|
my ( $self, $target_string, undef ) = @_; |
245
|
123
|
|
|
|
|
236
|
my %matches; |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
MATCH: |
248
|
123
|
|
|
|
|
1342
|
while ( my ($match) = $target_string =~ m/$MAGIC_REGEX/gcxms ) { |
249
|
109
|
|
|
|
|
441
|
my $nextchar = substr $target_string, $LAST_MATCH_END[0], 1; |
250
|
109
|
|
|
|
|
322
|
my $vname = _unbracket_variable_name( $match ); |
251
|
109
|
|
|
|
|
275
|
my $c = $vname . $nextchar; |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
# These tests closely parallel those in PPI::Token::Magic, |
254
|
|
|
|
|
|
|
# from which the regular expressions were taken. |
255
|
|
|
|
|
|
|
# A degree of simplicity is sacrificed to maintain the parallel. |
256
|
|
|
|
|
|
|
# $c is so named by analogy to that module. |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# possibly *not* a magic variable |
259
|
109
|
100
|
|
|
|
503
|
if ($c =~ m/ ^ \$ .* [ \w : \$ { ] $ /xms) { |
260
|
|
|
|
|
|
|
## no critic (RequireInterpolationOfMetachars) |
261
|
|
|
|
|
|
|
|
262
|
48
|
100
|
100
|
|
|
279
|
if ( |
263
|
|
|
|
|
|
|
$c =~ m/ ^(\$(?:\_[\w:]|::)) /xms |
264
|
|
|
|
|
|
|
or $c =~ m/ ^\$\'[\w] /xms ) |
265
|
|
|
|
|
|
|
{ |
266
|
|
|
|
|
|
|
next MATCH |
267
|
7
|
100
|
|
|
|
57
|
if $c !~ m/ ^\$\'\d$ /xms; |
268
|
|
|
|
|
|
|
# It not $' followed by a digit. |
269
|
|
|
|
|
|
|
# So it's magic var with something immediately after. |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
next MATCH |
273
|
42
|
100
|
|
|
|
128
|
if $c =~ m/ ^\$\$\w /xms; # It's a scalar dereference |
274
|
|
|
|
|
|
|
next MATCH |
275
|
41
|
100
|
100
|
|
|
204
|
if $c eq '$#$' |
276
|
|
|
|
|
|
|
or $c eq '$#{'; # It's an index dereferencing cast |
277
|
|
|
|
|
|
|
next MATCH |
278
|
39
|
100
|
|
|
|
120
|
if $c =~ m/ ^(\$\#)\w /xms |
279
|
|
|
|
|
|
|
; # It's an array index thingy, e.g. $#array_name |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
# PPI's checks for long escaped vars like $^WIDE_SYSTEM_CALLS |
282
|
|
|
|
|
|
|
# appear to be erroneous, and are omitted here. |
283
|
|
|
|
|
|
|
# if ( $c =~ m/^\$\^\w{2}$/xms ) { |
284
|
|
|
|
|
|
|
# } |
285
|
|
|
|
|
|
|
|
286
|
38
|
50
|
|
|
|
114
|
next MATCH if $c =~ m/ ^ \$ \# [{] /xms; # It's a $#{...} cast |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
# The additional checking that PPI::Token::Magic does at this point |
290
|
|
|
|
|
|
|
# is not necessary here, in an interpolated string context. |
291
|
|
|
|
|
|
|
|
292
|
99
|
|
|
|
|
572
|
$matches{$vname} = 1; |
293
|
|
|
|
|
|
|
} |
294
|
|
|
|
|
|
|
|
295
|
123
|
|
|
|
|
256
|
delete @matches{ keys %{ $self->{_allow} } }; |
|
123
|
|
|
|
|
769
|
|
296
|
|
|
|
|
|
|
|
297
|
123
|
|
|
|
|
540
|
return %matches; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
# RT #72910: A magic variable may appear in bracketed form; e.g. "$$" as |
301
|
|
|
|
|
|
|
# "${$}". Generate the bracketed form from the unbracketed form, and |
302
|
|
|
|
|
|
|
# return both. |
303
|
|
|
|
|
|
|
sub _bracketed_form_of_variable_name { |
304
|
2640
|
|
|
2640
|
|
4343
|
my ( $name ) = @_; |
305
|
2640
|
50
|
|
|
|
5064
|
length $name > 1 |
306
|
|
|
|
|
|
|
or return ( $name ); |
307
|
2640
|
|
|
|
|
3937
|
my $brktd = $name; |
308
|
2640
|
|
|
|
|
4190
|
substr $brktd, 1, 0, '{'; |
309
|
2640
|
|
|
|
|
3892
|
$brktd .= '}'; |
310
|
2640
|
|
|
|
|
6326
|
return( $name, $brktd ); |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
# RT #72910: Since we loaded both bracketed and unbracketed forms of the |
314
|
|
|
|
|
|
|
# punctuation variables into our detecting regex, we need to detect and |
315
|
|
|
|
|
|
|
# strip the brackets if they are present to recover the canonical name. |
316
|
|
|
|
|
|
|
sub _unbracket_variable_name { |
317
|
119
|
|
|
119
|
|
297
|
my ( $name ) = @_; |
318
|
119
|
100
|
|
|
|
316
|
$name =~ m/ \A ( . ) [{] ( .+ ) [}] \z /smx |
319
|
|
|
|
|
|
|
and return "$1$2"; |
320
|
118
|
|
|
|
|
295
|
return $name; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub _create_magic_detector { |
326
|
40
|
|
|
40
|
|
132
|
my ($config) = @_; |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# Set up the regexp alternation for matching magic variables. |
329
|
|
|
|
|
|
|
# We can't process $config->{_allow} here because of a quirk in the |
330
|
|
|
|
|
|
|
# way Perl::Critic handles testing. |
331
|
|
|
|
|
|
|
# |
332
|
|
|
|
|
|
|
# The sort is needed so that, e.g., $^ doesn't mask out $^M |
333
|
|
|
|
|
|
|
my $magic_alternation = |
334
|
|
|
|
|
|
|
'(?:' |
335
|
|
|
|
|
|
|
. ( |
336
|
|
|
|
|
|
|
join |
337
|
|
|
|
|
|
|
q<|>, |
338
|
5280
|
|
|
|
|
10220
|
map { quotemeta } |
339
|
25000
|
|
|
|
|
36423
|
reverse sort { length $a <=> length $b } |
340
|
2640
|
|
|
|
|
4665
|
map { _bracketed_form_of_variable_name( $_ ) } |
341
|
40
|
|
|
|
|
187
|
grep { q<%> ne substr $_, 0, 1 } |
|
2800
|
|
|
|
|
17609
|
|
342
|
|
|
|
|
|
|
@MAGIC_VARIABLES |
343
|
|
|
|
|
|
|
) |
344
|
|
|
|
|
|
|
. ')'; |
345
|
|
|
|
|
|
|
|
346
|
40
|
|
|
|
|
20103
|
return qr< |
347
|
|
|
|
|
|
|
(?: \A | [^\\] ) # beginning-of-string or any non-backslash |
348
|
|
|
|
|
|
|
(?: \\{2} )* # zero or more double-backslashes |
349
|
|
|
|
|
|
|
( $magic_alternation ) # any magic punctuation variable |
350
|
|
|
|
|
|
|
>xsm; |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
sub _make_violation { |
354
|
120
|
|
|
120
|
|
320
|
my ( $self, $desc, $expl, $elem, $vars ) = @_; |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
my $vname = 'HASH' eq ref $vars ? |
357
|
120
|
100
|
|
|
|
373
|
join ', ', sort keys %{ $vars } : |
|
100
|
|
|
|
|
336
|
|
358
|
|
|
|
|
|
|
$elem->content(); |
359
|
120
|
|
|
|
|
846
|
return $self->violation( sprintf( $desc, $vname ), $expl, $elem ); |
360
|
|
|
|
|
|
|
} |
361
|
|
|
|
|
|
|
|
362
|
|
|
|
|
|
|
1; |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
__END__ |
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
=pod |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
=head1 NAME |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
Perl::Critic::Policy::Variables::ProhibitPunctuationVars - Write C<$EVAL_ERROR> instead of C<$@>. |
373
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
=head1 AFFILIATION |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
This Policy is part of the core L<Perl::Critic|Perl::Critic> |
378
|
|
|
|
|
|
|
distribution. |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
=head1 DESCRIPTION |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
Perl's vocabulary of punctuation variables such as C<$!>, C<$.>, and |
384
|
|
|
|
|
|
|
C<$^> are perhaps the leading cause of its reputation as inscrutable |
385
|
|
|
|
|
|
|
line noise. The simple alternative is to use the L<English|English> |
386
|
|
|
|
|
|
|
module to give them clear names. |
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
$| = undef; #not ok |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
use English qw(-no_match_vars); |
391
|
|
|
|
|
|
|
local $OUTPUT_AUTOFLUSH = undef; #ok |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=head1 CONFIGURATION |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
The scratch variables C<$_> and C<@_> are very common and are pretty |
396
|
|
|
|
|
|
|
well understood, so they are exempt from this policy. The same goes |
397
|
|
|
|
|
|
|
for the less-frequently-used default filehandle C<_> used by stat(). |
398
|
|
|
|
|
|
|
All the regexp capture variables (C<$1>, C<$2>, ...) are exempt too. |
399
|
|
|
|
|
|
|
C<$]> is exempt because there is no L<English|English> equivalent and |
400
|
|
|
|
|
|
|
L<Module::CoreList|Module::CoreList> is based upon it. |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
You can add more exceptions to your configuration. In your |
403
|
|
|
|
|
|
|
perlcriticrc file, add a block like this: |
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
[Variables::ProhibitPunctuationVars] |
406
|
|
|
|
|
|
|
allow = $@ $! |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
The C<allow> property should be a whitespace-delimited list of |
409
|
|
|
|
|
|
|
punctuation variables. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
Other configuration options control the parsing of interpolated |
412
|
|
|
|
|
|
|
strings in the search for forbidden variables. They have no effect |
413
|
|
|
|
|
|
|
on detecting punctuation variables outside of interpolated strings. |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
[Variables::ProhibitPunctuationVars] |
416
|
|
|
|
|
|
|
string_mode = thorough |
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
The option C<string_mode> controls whether and how interpolated |
419
|
|
|
|
|
|
|
strings are searched for punctuation variables. Setting |
420
|
|
|
|
|
|
|
C<string_mode = thorough>, the default, checks for special cases |
421
|
|
|
|
|
|
|
that may look like punctuation variables but aren't, for example |
422
|
|
|
|
|
|
|
C<$#foo>, an array index count; C<$$bar>, a scalar dereference; or |
423
|
|
|
|
|
|
|
C<$::baz>, a global symbol. |
424
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
Setting C<string_mode = disable> causes all interpolated strings to |
426
|
|
|
|
|
|
|
be ignored entirely. |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
Setting C<string_mode = simple> uses a simple regular expression to |
429
|
|
|
|
|
|
|
find matches. In this mode, the magic variables C<$$>, C<$'>, C<$#> |
430
|
|
|
|
|
|
|
and C<$:> are ignored within interpolated strings due to the high |
431
|
|
|
|
|
|
|
risk of false positives. Simple mode is retained from an earlier |
432
|
|
|
|
|
|
|
draft of the interpolated- strings code. Its use is only recommended |
433
|
|
|
|
|
|
|
as a workaround if bugs appear in thorough mode. |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
The C<string_mode> option will go away when the parsing of |
436
|
|
|
|
|
|
|
interpolated strings is implemented in PPI. See L</CAVEATS> below. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
=head1 BUGS |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
Punctuation variables that confuse PPI's document parsing may not be |
442
|
|
|
|
|
|
|
detected correctly or at all, and may prevent detection of |
443
|
|
|
|
|
|
|
subsequent ones. In particular, C<$"> is known to cause difficulties |
444
|
|
|
|
|
|
|
in interpolated strings. |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
=head1 CAVEATS |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
ProhibitPunctuationVars relies exclusively on PPI to find |
450
|
|
|
|
|
|
|
punctuation variables in code, but does all the parsing itself for |
451
|
|
|
|
|
|
|
interpolated strings. When, at some point, this functionality is |
452
|
|
|
|
|
|
|
transferred to PPI, ProhibitPunctuationVars will cease doing the |
453
|
|
|
|
|
|
|
interpolating and the C<string_mode> option will go away. |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
=head1 AUTHOR |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
Jeffrey Ryan Thalhammer <jeff@imaginative-software.com> |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=head1 COPYRIGHT |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
Copyright (c) 2005-2011 Imaginative Software Systems. All rights reserved. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify |
466
|
|
|
|
|
|
|
it under the same terms as Perl itself. The full text of this license |
467
|
|
|
|
|
|
|
can be found in the LICENSE file included with this module. |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
=cut |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
# Local Variables: |
472
|
|
|
|
|
|
|
# mode: cperl |
473
|
|
|
|
|
|
|
# cperl-indent-level: 4 |
474
|
|
|
|
|
|
|
# fill-column: 78 |
475
|
|
|
|
|
|
|
# indent-tabs-mode: nil |
476
|
|
|
|
|
|
|
# c-indentation-style: bsd |
477
|
|
|
|
|
|
|
# End: |
478
|
|
|
|
|
|
|
# ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround : |