line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Perl::Critic::Policy::RegularExpressions::ProhibitCaptureWithoutTest; |
2
|
|
|
|
|
|
|
|
3
|
40
|
|
|
40
|
|
29055
|
use 5.010001; |
|
40
|
|
|
|
|
198
|
|
4
|
40
|
|
|
40
|
|
279
|
use strict; |
|
40
|
|
|
|
|
131
|
|
|
40
|
|
|
|
|
827
|
|
5
|
40
|
|
|
40
|
|
240
|
use warnings; |
|
40
|
|
|
|
|
126
|
|
|
40
|
|
|
|
|
1087
|
|
6
|
40
|
|
|
40
|
|
259
|
use Readonly; |
|
40
|
|
|
|
|
146
|
|
|
40
|
|
|
|
|
2264
|
|
7
|
|
|
|
|
|
|
|
8
|
40
|
|
|
40
|
|
350
|
use Perl::Critic::Utils qw{ :booleans :data_conversion :severities }; |
|
40
|
|
|
|
|
154
|
|
|
40
|
|
|
|
|
2129
|
|
9
|
40
|
|
|
40
|
|
8412
|
use parent 'Perl::Critic::Policy'; |
|
40
|
|
|
|
|
148
|
|
|
40
|
|
|
|
|
254
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our $VERSION = '1.148'; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
Readonly::Hash my %CONDITIONAL_OPERATOR => hashify( qw{ && || ? and or xor } ); |
16
|
|
|
|
|
|
|
Readonly::Hash my %UNAMBIGUOUS_CONTROL_TRANSFER => hashify( |
17
|
|
|
|
|
|
|
qw< next last redo return > ); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
Readonly::Scalar my $DESC => q{Capture variable used outside conditional}; |
20
|
|
|
|
|
|
|
Readonly::Scalar my $EXPL => [ 253 ]; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub supported_parameters { return ( |
25
|
|
|
|
|
|
|
{ |
26
|
115
|
|
|
115
|
0
|
2270
|
name => 'exception_source', |
27
|
|
|
|
|
|
|
description => 'Names of ways to generate exceptions', |
28
|
|
|
|
|
|
|
behavior => 'string list', |
29
|
|
|
|
|
|
|
list_always_present_values => [ qw{ die croak confess } ], |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
); |
32
|
|
|
|
|
|
|
} |
33
|
86
|
|
|
86
|
1
|
486
|
sub default_severity { return $SEVERITY_MEDIUM } |
34
|
86
|
|
|
86
|
1
|
408
|
sub default_themes { return qw(core pbp maintenance certrule ) } |
35
|
55
|
|
|
55
|
1
|
183
|
sub applies_to { return 'PPI::Token::Magic' } |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
sub violates { |
40
|
76
|
|
|
76
|
1
|
181
|
my ($self, $elem, $doc) = @_; |
41
|
|
|
|
|
|
|
# TODO named capture variables |
42
|
76
|
100
|
|
|
|
214
|
return if $elem !~ m/\A \$[1-9] \z/xms; |
43
|
59
|
100
|
|
|
|
420
|
return if _is_in_conditional_expression($elem); |
44
|
51
|
100
|
|
|
|
148
|
return if $self->_is_in_conditional_structure($elem); |
45
|
12
|
|
|
|
|
51
|
return $self->violation( $DESC, $EXPL, $elem ); |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub _is_in_conditional_expression { |
49
|
79
|
|
|
79
|
|
145
|
my $elem = shift; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# simplistic check: is there a conditional operator between a match and |
52
|
|
|
|
|
|
|
# the capture var? |
53
|
79
|
|
|
|
|
220
|
my $psib = $elem->sprevious_sibling; |
54
|
79
|
|
|
|
|
2272
|
while ($psib) { |
55
|
105
|
100
|
|
|
|
1126
|
if ($psib->isa('PPI::Token::Operator')) { |
56
|
24
|
|
|
|
|
68
|
my $op = $psib->content; |
57
|
24
|
100
|
|
|
|
161
|
if ( $CONDITIONAL_OPERATOR{ $op } ) { |
58
|
12
|
|
|
|
|
89
|
$psib = $psib->sprevious_sibling; |
59
|
12
|
|
|
|
|
307
|
while ($psib) { |
60
|
12
|
100
|
|
|
|
81
|
return 1 if ($psib->isa('PPI::Token::Regexp::Match')); |
61
|
4
|
50
|
|
|
|
25
|
return 1 if ($psib->isa('PPI::Token::Regexp::Substitute')); |
62
|
0
|
|
|
|
|
0
|
$psib = $psib->sprevious_sibling; |
63
|
|
|
|
|
|
|
} |
64
|
0
|
|
|
|
|
0
|
return; # false |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
} |
67
|
93
|
|
|
|
|
337
|
$psib = $psib->sprevious_sibling; |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
|
70
|
67
|
|
|
|
|
1092
|
return; # false |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub _is_in_conditional_structure { |
74
|
67
|
|
|
67
|
|
169
|
my ( $self, $elem ) = @_; |
75
|
|
|
|
|
|
|
|
76
|
67
|
|
|
|
|
206
|
my $stmt = $elem->statement(); |
77
|
67
|
|
33
|
|
|
1333
|
while ($stmt && $elem->isa('PPI::Statement::Expression')) { |
78
|
|
|
|
|
|
|
#return if _is_in_conditional_expression($stmt); |
79
|
0
|
|
|
|
|
0
|
$stmt = $stmt->statement(); |
80
|
|
|
|
|
|
|
} |
81
|
67
|
50
|
|
|
|
229
|
return if !$stmt; |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
# Check if any previous statements in the same scope have regexp matches |
84
|
67
|
|
|
|
|
199
|
my $psib = $stmt->sprevious_sibling; |
85
|
67
|
|
|
|
|
1833
|
while ($psib) { |
86
|
43
|
100
|
66
|
|
|
228
|
if ( $psib->isa( 'PPI::Node' ) and |
87
|
|
|
|
|
|
|
my $match = _find_exposed_match_or_substitute( $psib ) ) { |
88
|
35
|
|
100
|
|
|
98
|
return _is_control_transfer_to_left( $self, $match, $elem ) || |
89
|
|
|
|
|
|
|
_is_control_transfer_to_right( $self, $match, $elem ); |
90
|
|
|
|
|
|
|
} |
91
|
8
|
|
|
|
|
31
|
$psib = $psib->sprevious_sibling; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
# Check for an enclosing 'if', 'unless', 'elsif', 'else', or 'when' |
95
|
32
|
|
|
|
|
212
|
my $parent = $stmt->parent; |
96
|
32
|
|
|
|
|
182
|
while ($parent) { # never false as long as we're inside a PPI::Document |
97
|
43
|
100
|
100
|
|
|
349
|
if ($parent->isa('PPI::Statement::Compound') || |
|
|
100
|
|
|
|
|
|
98
|
|
|
|
|
|
|
$parent->isa('PPI::Statement::When' ) |
99
|
|
|
|
|
|
|
) { |
100
|
8
|
|
|
|
|
49
|
return 1; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
elsif ($parent->isa('PPI::Structure')) { |
103
|
20
|
100
|
|
|
|
121
|
return 1 if _is_in_conditional_expression($parent); |
104
|
16
|
100
|
|
|
|
44
|
return 1 if $self->_is_in_conditional_structure($parent); |
105
|
11
|
|
|
|
|
77
|
$parent = $parent->parent; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
else { |
108
|
15
|
|
|
|
|
36
|
last; |
109
|
|
|
|
|
|
|
} |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
15
|
|
|
|
|
58
|
return; # fail |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# This subroutine returns true if there is a control transfer to the left of |
116
|
|
|
|
|
|
|
# the match operation which would bypass the capture variable. The arguments |
117
|
|
|
|
|
|
|
# are the match operation and the capture variable. |
118
|
|
|
|
|
|
|
sub _is_control_transfer_to_left { |
119
|
35
|
|
|
35
|
|
79
|
my ( $self, $match, $elem ) = @_; |
120
|
|
|
|
|
|
|
# If a regexp match is found, we succeed if a match failure |
121
|
|
|
|
|
|
|
# appears to throw an exception, and fail otherwise. RT 36081 |
122
|
35
|
100
|
|
|
|
92
|
my $prev = $match->sprevious_sibling() or return; |
123
|
9
|
|
100
|
|
|
282
|
while ( not ( $prev->isa( 'PPI::Token::Word' ) && |
124
|
|
|
|
|
|
|
q<unless> eq $prev->content() ) ) { |
125
|
13
|
100
|
|
|
|
230
|
$prev = $prev->sprevious_sibling() or return; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
# In this case we analyze the first thing to appear in the parent of the |
128
|
|
|
|
|
|
|
# 'unless'. This is the simplest case, and it will not be hard to dream up |
129
|
|
|
|
|
|
|
# cases where this is insufficient (e.g. do {something(); die} unless ...) |
130
|
4
|
50
|
|
|
|
34
|
my $parent = $prev->parent() or return; |
131
|
4
|
50
|
|
|
|
29
|
my $first = $parent->schild( 0 ) or return; |
132
|
4
|
50
|
|
|
|
61
|
if ( my $method = _get_method_name( $first ) ) { |
133
|
|
|
|
|
|
|
# Methods can also be exception sources. |
134
|
0
|
|
|
|
|
0
|
return $self->{_exception_source}{ $method->content() }; |
135
|
|
|
|
|
|
|
} |
136
|
4
|
|
66
|
|
|
14
|
return $self->{_exception_source}{ $first->content() } || |
137
|
|
|
|
|
|
|
_unambiguous_control_transfer( $first, $elem ); |
138
|
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# This subroutine returns true if there is a control transfer to the right of |
141
|
|
|
|
|
|
|
# the match operation which would bypass the capture variable. The arguments |
142
|
|
|
|
|
|
|
# are the match operation and the capture variable. |
143
|
|
|
|
|
|
|
sub _is_control_transfer_to_right { |
144
|
31
|
|
|
31
|
|
670
|
my ( $self, $match, $elem ) = @_; |
145
|
|
|
|
|
|
|
# If a regexp match is found, we succeed if a match failure |
146
|
|
|
|
|
|
|
# appears to throw an exception, and fail otherwise. RT 36081 |
147
|
31
|
100
|
|
|
|
107
|
my $oper = $match->snext_sibling() or return; # fail |
148
|
29
|
|
|
|
|
671
|
my $oper_content = $oper->content(); |
149
|
|
|
|
|
|
|
# We do not check '//' because a match failure does not |
150
|
|
|
|
|
|
|
# return an undefined value. |
151
|
29
|
100
|
100
|
|
|
207
|
q{or} eq $oper_content |
152
|
|
|
|
|
|
|
or q{||} eq $oper_content |
153
|
|
|
|
|
|
|
or return; # fail |
154
|
26
|
50
|
|
|
|
67
|
my $next = $oper->snext_sibling() or return; # fail |
155
|
26
|
100
|
|
|
|
597
|
if ( my $method = _get_method_name( $next ) ) { |
156
|
|
|
|
|
|
|
# Methods can also be exception sources. |
157
|
1
|
|
|
|
|
7
|
return $self->{_exception_source}{ $method->content() }; |
158
|
|
|
|
|
|
|
} |
159
|
25
|
|
100
|
|
|
80
|
return $self->{_exception_source}{ $next->content() } || |
160
|
|
|
|
|
|
|
_unambiguous_control_transfer( $next, $elem ); |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
# Given a PPI::Node, find the last regexp match or substitution that is |
164
|
|
|
|
|
|
|
# in-scope to the node's next sibling. |
165
|
|
|
|
|
|
|
sub _find_exposed_match_or_substitute { # RT 36081 |
166
|
43
|
|
|
43
|
|
88
|
my $elem = shift; |
167
|
|
|
|
|
|
|
FIND_REGEXP_NOT_IN_BLOCK: |
168
|
43
|
|
|
|
|
81
|
foreach my $regexp ( reverse @{ $elem->find( |
169
|
|
|
|
|
|
|
sub { |
170
|
397
|
|
100
|
397
|
|
5744
|
return $_[1]->isa( 'PPI::Token::Regexp::Substitute' ) |
171
|
|
|
|
|
|
|
|| $_[1]->isa( 'PPI::Token::Regexp::Match' ); |
172
|
|
|
|
|
|
|
} |
173
|
43
|
100
|
|
|
|
196
|
) || [] } ) { |
174
|
38
|
|
|
|
|
589
|
my $parent = $regexp->parent(); |
175
|
38
|
|
|
|
|
225
|
while ( $parent != $elem ) { |
176
|
10
|
100
|
|
|
|
136
|
$parent->isa( 'PPI::Structure::Block' ) |
177
|
|
|
|
|
|
|
and next FIND_REGEXP_NOT_IN_BLOCK; |
178
|
7
|
50
|
|
|
|
19
|
$parent = $parent->parent() |
179
|
|
|
|
|
|
|
or next FIND_REGEXP_NOT_IN_BLOCK; |
180
|
|
|
|
|
|
|
} |
181
|
35
|
|
|
|
|
470
|
return $regexp; |
182
|
|
|
|
|
|
|
} |
183
|
8
|
|
|
|
|
140
|
return; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# If the argument introduces a method call, return the method name; |
187
|
|
|
|
|
|
|
# otherwise just return. |
188
|
|
|
|
|
|
|
sub _get_method_name { |
189
|
30
|
|
|
30
|
|
63
|
my ( $elem ) = @_; |
190
|
|
|
|
|
|
|
# We fail unless the element we were given looks like it might be an |
191
|
|
|
|
|
|
|
# object or a class name. |
192
|
30
|
50
|
|
|
|
97
|
$elem or return; |
193
|
|
|
|
|
|
|
( |
194
|
30
|
50
|
66
|
|
|
223
|
$elem->isa( 'PPI::Token::Symbol' ) && |
|
|
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
195
|
|
|
|
|
|
|
q<$> eq $elem->raw_type() || |
196
|
|
|
|
|
|
|
$elem->isa( 'PPI::Token::Word' ) && |
197
|
|
|
|
|
|
|
$elem->content() =~ m/ \A [\w:]+ \z /smx |
198
|
|
|
|
|
|
|
) or return; |
199
|
|
|
|
|
|
|
# We skip over all the subscripts and '->' operators to the right of |
200
|
|
|
|
|
|
|
# the original element, failing if we run out of objects. |
201
|
30
|
|
|
|
|
283
|
my $prior; |
202
|
30
|
50
|
|
|
|
84
|
my $next = $elem->snext_sibling() or return; |
203
|
30
|
|
66
|
|
|
883
|
while ( $next->isa( 'PPI::Token::Subscript' ) || |
|
|
|
66
|
|
|
|
|
204
|
|
|
|
|
|
|
$next->isa( 'PPI::Token::Operator' ) && |
205
|
|
|
|
|
|
|
q{->} eq $next->content() ) { |
206
|
1
|
|
|
|
|
14
|
$prior = $next; |
207
|
1
|
50
|
|
|
|
5
|
$next = $next->snext_sibling or return; # fail |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
# A method call must have a '->' operator before it. |
210
|
30
|
50
|
66
|
|
|
225
|
( $prior && |
|
|
|
66
|
|
|
|
|
211
|
|
|
|
|
|
|
$prior->isa( 'PPI::Token::Operator' ) && |
212
|
|
|
|
|
|
|
q{->} eq $prior->content() |
213
|
|
|
|
|
|
|
) or return; |
214
|
|
|
|
|
|
|
# Anything other than a PPI::Token::Word can not be statically |
215
|
|
|
|
|
|
|
# recognized as a method name. |
216
|
1
|
50
|
|
|
|
11
|
$next->isa( 'PPI::Token::Word' ) or return; |
217
|
|
|
|
|
|
|
# Whatever we have left at this point looks very like a method name. |
218
|
1
|
|
|
|
|
6
|
return $next; |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# Determine whether the given element represents an unambiguous transfer of |
222
|
|
|
|
|
|
|
# control around anything that follows it in the same block. The arguments are |
223
|
|
|
|
|
|
|
# the element to check, and the capture variable that is the subject of this |
224
|
|
|
|
|
|
|
# call to the policy. |
225
|
|
|
|
|
|
|
sub _unambiguous_control_transfer { # RT 36081. |
226
|
19
|
|
|
19
|
|
144
|
my ( $xfer, $elem ) = @_; |
227
|
|
|
|
|
|
|
|
228
|
19
|
|
|
|
|
53
|
my $content = $xfer->content(); |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
# Anything in the hash is always a transfer of control. |
231
|
19
|
100
|
|
|
|
137
|
return $TRUE if $UNAMBIGUOUS_CONTROL_TRANSFER{ $content }; |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# A goto is not unambiguous on the face of it, but at least some forms of |
234
|
|
|
|
|
|
|
# it can be accepted. |
235
|
8
|
100
|
|
|
|
93
|
q<goto> eq $content |
236
|
|
|
|
|
|
|
and return _unambiguous_goto( $xfer, $elem ); |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
# Anything left at this point is _not_ an unambiguous transfer of control |
239
|
|
|
|
|
|
|
# around whatever follows it. |
240
|
1
|
|
|
|
|
7
|
return; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# Determine whether the given goto represents an unambiguous transfer of |
244
|
|
|
|
|
|
|
# control around anything that follows it in the same block. The arguments are |
245
|
|
|
|
|
|
|
# the element to check, and the capture variable that is the subject of this |
246
|
|
|
|
|
|
|
# call to the policy. |
247
|
|
|
|
|
|
|
sub _unambiguous_goto { |
248
|
7
|
|
|
7
|
|
24
|
my ( $xfer, $elem ) = @_; |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
# A goto without a target? |
251
|
7
|
50
|
|
|
|
21
|
my $target = $xfer->snext_sibling() or return; |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
# The co-routine form of goto is an unambiguous transfer of control. |
254
|
7
|
100
|
66
|
|
|
227
|
$target->isa( 'PPI::Token::Symbol' ) |
255
|
|
|
|
|
|
|
and q<&> eq $target->raw_type() |
256
|
|
|
|
|
|
|
and return $TRUE; |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# The label form of goto is an unambiguous transfer of control, |
259
|
|
|
|
|
|
|
# provided the label does not occur between the goto and the capture |
260
|
|
|
|
|
|
|
# variable. |
261
|
6
|
100
|
|
|
|
31
|
if ( $target->isa( 'PPI::Token::Word' ) ) { |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
# We need to search in our most-local block, or the document if |
264
|
|
|
|
|
|
|
# there is no enclosing block. |
265
|
5
|
|
|
|
|
9
|
my $container = $target; |
266
|
5
|
|
|
|
|
17
|
while ( my $parent = $container->parent() ) { |
267
|
10
|
|
|
|
|
59
|
$container = $parent; |
268
|
10
|
100
|
|
|
|
65
|
$container->isa( 'PPI::Structure::Block' ) and last; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
# We search the container for our label. If we find it, we return |
272
|
|
|
|
|
|
|
# true if it occurs before the goto or after the capture variable, |
273
|
|
|
|
|
|
|
# otherwise we return false. If we do not find it we return true. |
274
|
|
|
|
|
|
|
# Note that perl does not seem to consider duplicate labels an |
275
|
|
|
|
|
|
|
# error, but also seems to take the first one in the relevant |
276
|
|
|
|
|
|
|
# scope when this happens. |
277
|
5
|
|
|
|
|
20
|
my $looking_for = qr/ \A @{[ $target->content() ]} \s* : \z /smx; |
|
5
|
|
|
|
|
14
|
|
278
|
5
|
50
|
|
|
|
78
|
my ($start_line, $start_char) = @{ $xfer->location() || [] }; |
|
5
|
|
|
|
|
19
|
|
279
|
5
|
50
|
|
|
|
90
|
defined $start_line or return; # document not indexed. |
280
|
5
|
50
|
|
|
|
10
|
my ($end_line, $end_char) = @{ $elem->location() || [] }; |
|
5
|
|
|
|
|
15
|
|
281
|
5
|
|
|
|
|
102
|
foreach my $label ( |
282
|
5
|
100
|
|
|
|
22
|
@{ $container->find( 'PPI::Token::Label' ) || [] } ) |
283
|
|
|
|
|
|
|
{ |
284
|
3
|
50
|
|
|
|
2415
|
$label->content() =~ m/$looking_for/smx or next; |
285
|
3
|
50
|
|
|
|
27
|
my ( $line, $char ) = @{ $label->location() || [] }; |
|
3
|
|
|
|
|
11
|
|
286
|
3
|
100
|
66
|
|
|
67
|
return $TRUE |
|
|
|
66
|
|
|
|
|
287
|
|
|
|
|
|
|
if $line < $start_line || |
288
|
|
|
|
|
|
|
$line == $start_line && $char < $start_char; |
289
|
2
|
100
|
33
|
|
|
26
|
return $TRUE |
|
|
|
66
|
|
|
|
|
290
|
|
|
|
|
|
|
if $line > $end_line || |
291
|
|
|
|
|
|
|
$line == $end_line && $char > $end_char; |
292
|
1
|
|
|
|
|
10
|
return; |
293
|
|
|
|
|
|
|
} |
294
|
2
|
|
|
|
|
8567
|
return $TRUE; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
# Any other form of goto can not be statically analyzed, and so is not |
298
|
|
|
|
|
|
|
# an unambiguous transfer of control around the capture variable. |
299
|
1
|
|
|
|
|
16
|
return; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
1; |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
#----------------------------------------------------------------------------- |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
__END__ |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
=pod |
309
|
|
|
|
|
|
|
|
310
|
|
|
|
|
|
|
=head1 NAME |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
Perl::Critic::Policy::RegularExpressions::ProhibitCaptureWithoutTest - Capture variable used outside conditional. |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=head1 AFFILIATION |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
This Policy is part of the core L<Perl::Critic|Perl::Critic> |
317
|
|
|
|
|
|
|
distribution. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=head1 DESCRIPTION |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
If a regexp match fails, then any capture variables (C<$1>, C<$2>, |
322
|
|
|
|
|
|
|
...) will be unaffected. They will retain whatever old values they may |
323
|
|
|
|
|
|
|
have had. Therefore it's important to check the return value of a match |
324
|
|
|
|
|
|
|
before using those variables. |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
'12312123' =~ /(2)/; |
327
|
|
|
|
|
|
|
print $1; # Prints 2 |
328
|
|
|
|
|
|
|
'123123123' =~ /(X)/; |
329
|
|
|
|
|
|
|
print $1; # Prints 2, because $1 has not changed. |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
Note that because the values of C<$1> etc will be unaffected, you cannot |
332
|
|
|
|
|
|
|
determine if a match succeeded by checking to see if the capture variables |
333
|
|
|
|
|
|
|
have values. |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
# WRONG |
336
|
|
|
|
|
|
|
$str =~ /foo(.+)/; |
337
|
|
|
|
|
|
|
if ( $1 ) { |
338
|
|
|
|
|
|
|
print "I found $1 after 'foo'"; |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
This policy checks that the previous regexp for which the capture |
342
|
|
|
|
|
|
|
variable is in-scope is either in a conditional or causes an exception |
343
|
|
|
|
|
|
|
or other control transfer (i.e. C<next>, C<last>, C<redo>, C<return>, or |
344
|
|
|
|
|
|
|
sometimes C<goto>) if the match fails. |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
A C<goto> is only accepted by this policy if it is a co-routine call |
347
|
|
|
|
|
|
|
(i.e. C<goto &foo>) or a C<goto LABEL> where the label does not fall |
348
|
|
|
|
|
|
|
between the C<goto> and the capture variable in the scope of the |
349
|
|
|
|
|
|
|
C<goto>. A computed C<goto> (i.e. something like C<goto (qw{foo bar |
350
|
|
|
|
|
|
|
baz})[$i]>) is not accepted by this policy because its target can not be |
351
|
|
|
|
|
|
|
statically determined. |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
This policy does not check whether that conditional is actually |
354
|
|
|
|
|
|
|
testing a regexp result, nor does it check whether a regexp actually |
355
|
|
|
|
|
|
|
has a capture in it. Those checks are too hard. |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
This policy also does not check arbitrarily complex conditionals guarding |
358
|
|
|
|
|
|
|
regexp results, for pretty much the same reason. Simple things like |
359
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
m/(foo)/ or die "No foo!"; |
361
|
|
|
|
|
|
|
die "No foo!" unless m/(foo)/; |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
will be handled, but something like |
364
|
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
m/(foo)/ or do { |
366
|
|
|
|
|
|
|
... lots of complicated calculations here ... |
367
|
|
|
|
|
|
|
die "No foo!"; |
368
|
|
|
|
|
|
|
}; |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
are beyond its scope. |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
=head1 CONFIGURATION |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
By default, this policy considers C<die>, C<croak>, and C<confess> to |
376
|
|
|
|
|
|
|
throw exceptions. If you have additional subroutines or methods that may |
377
|
|
|
|
|
|
|
be used in lieu of one of these, you can configure them in your |
378
|
|
|
|
|
|
|
perlcriticrc as follows: |
379
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
[RegularExpressions::ProhibitCaptureWithoutTest] |
381
|
|
|
|
|
|
|
exception_source = my_exception_generator |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
=head1 BUGS |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
This policy does not recognize named capture variables. Yet. |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
=head1 AUTHOR |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
Chris Dolan <cdolan@cpan.org> |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
=head1 COPYRIGHT |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
Copyright (c) 2006-2017 Chris Dolan. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify |
396
|
|
|
|
|
|
|
it under the same terms as Perl itself. |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
=cut |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
# Local Variables: |
401
|
|
|
|
|
|
|
# mode: cperl |
402
|
|
|
|
|
|
|
# cperl-indent-level: 4 |
403
|
|
|
|
|
|
|
# fill-column: 78 |
404
|
|
|
|
|
|
|
# indent-tabs-mode: nil |
405
|
|
|
|
|
|
|
# c-indentation-style: bsd |
406
|
|
|
|
|
|
|
# End: |
407
|
|
|
|
|
|
|
# ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround : |