File Coverage

blib/lib/Perl/Lint/Policy/RegularExpressions/RequireDotMatchAnything.pm
Criterion Covered Total %
statement 73 73 100.0
branch 28 30 93.3
condition 40 55 72.7
subroutine 6 6 100.0
pod 0 1 0.0
total 147 165 89.0


line stmt bran cond sub pod time code
1             package Perl::Lint::Policy::RegularExpressions::RequireDotMatchAnything;
2 134     134   71602 use strict;
  134         185  
  134         3244  
3 134     134   395 use warnings;
  134         143  
  134         2401  
4 134     134   752 use Perl::Lint::Constants::Type;
  134         147  
  134         60115  
5 134     134   534 use parent "Perl::Lint::Policy";
  134         142  
  134         566  
6              
7             use constant {
8 134         57612 DESC => 'Regular expression without "/s" flag',
9             EXPL => [240, 241],
10 134     134   6990 };
  134         204  
11              
12             sub evaluate {
13 10     10 0 14 my ($class, $file, $tokens, $src, $args) = @_;
14              
15 10         9 my @violations;
16              
17 10         8 my $depth = 0;
18 10         7 my $is_non_target_reg = 0;
19              
20 10         8 my $enabled_re_m_depth = -1; # use negative value as default
21 10         6 my @enabled_re_m_depths;
22              
23 10         9 my $disable_re_m_depth = -1; # use negative value as default
24 10         7 my @disable_re_m_depths;
25              
26 10         25 for (my $i = 0; my $token = $tokens->[$i]; $i++) {
27 532         337 my $token_type = $token->{type};
28 532         331 my $token_data = $token->{data};
29              
30 532         394 my $next_token = $tokens->[$i+1];
31 532         356 my $next_token_type = $next_token->{type};
32 532         355 my $next_token_data = $next_token->{data};
33              
34 532 100 100     1173 if (!$is_non_target_reg && $token_type == REG_DELIM) {
35 86 100 66     261 if (
      33        
36             defined $next_token_type &&
37             (
38             $next_token_type == SEMI_COLON || # when any regex options don't exist
39             ($next_token_type == REG_OPT && $next_token_data !~ /s/) # when the `m` regex option doesn't exist
40             )
41             ) {
42 26 100 66     67 if (
      66        
      66        
43             !($enabled_re_m_depth >= 0 && $depth >= $enabled_re_m_depth) ||
44             ($disable_re_m_depth >= 0 && $disable_re_m_depth > $enabled_re_m_depth)
45             ) {
46             push @violations, {
47             filename => $file,
48             line => $token->{line},
49 24         59 description => DESC,
50             explanation => EXPL,
51             policy => __PACKAGE__,
52             };
53             }
54             }
55              
56 86         132 next;
57             }
58              
59             # Ignore regexes which are unnecessary to check
60             # XXX more?
61 446 50 100     2005 if (
      66        
      66        
62             $token_type == REG_ALL_REPLACE ||
63             $token_type == REG_LIST ||
64             $token_type == REG_QUOTE ||
65             $token_type == REG_EXEC
66             ) {
67 10         8 $is_non_target_reg = 1;
68 10         16 next;
69             }
70              
71 436 100       431 if ($token_type == SEMI_COLON) {
72 62         47 $is_non_target_reg = 0;
73 62         90 next;
74             }
75              
76             # Represent block scope hierarchy
77 374 100       376 if ($token_type == LEFT_BRACE) {
78 3         4 $depth++;
79 3         7 next;
80             }
81 371 100       396 if ($token_type == RIGHT_BRACE) {
82 3 100       7 if ($enabled_re_m_depth == $depth) {
83 1         2 pop @enabled_re_m_depths;
84 1   50     4 $enabled_re_m_depth = $enabled_re_m_depths[-1] // -1;
85             }
86 3 100       6 if ($disable_re_m_depth == $depth) {
87 1         1 pop @disable_re_m_depths;
88 1   50     4 $disable_re_m_depth = $disable_re_m_depths[-1] // -1;
89             }
90 3         4 $depth--;
91 3         8 next;
92             }
93              
94             # for
95             # `use re qw{/s}`
96             # `use re '/s'`
97 368 100 100     481 if ($token_type == USED_NAME && $token_data eq 're') {
98 4         11 for ($i++; $token = $tokens->[$i]; $i++) {
99 17         15 $token_type = $token->{type};
100 17         12 $token_data = $token->{data};
101 17 100       21 if ($token_type == SEMI_COLON) {
102 4         5 last;
103             }
104 13 100 100     78 if (
      66        
105             ($token_type == RAW_STRING || $token_type == STRING || $token_type == REG_EXP) &&
106             $token_data =~ /s/
107             ) {
108 4         5 push @enabled_re_m_depths, $depth;
109 4         7 $enabled_re_m_depth = $depth;
110             }
111             }
112              
113 4         7 next;
114             }
115              
116             # for
117             # `no re qw{/s}`
118             # `no re '/s'`
119 364 50 100     756 if (
      66        
      66        
120             $token_type == BUILTIN_FUNC &&
121             $token_data eq 'no' &&
122             $next_token_type == KEY &&
123             $next_token_data eq 're'
124             ) {
125 1         4 for ($i++; $token = $tokens->[$i]; $i++) {
126 6         5 $token_type = $token->{type};
127 6         4 $token_data = $token->{data};
128 6 100       9 if ($token_type == SEMI_COLON) {
129 1         1 last;
130             }
131 5 100 66     31 if (
      66        
132             ($token_type == RAW_STRING || $token_type == STRING || $token_type == REG_EXP) &&
133             $token_data =~ /s/
134             ) {
135 1         2 push @disable_re_m_depths, $depth;
136 1         2 $disable_re_m_depth = $depth;
137             }
138             }
139              
140 1         2 next;
141             }
142             }
143              
144 10         38 return \@violations;
145             }
146              
147             1;
148