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   70789 use strict;
  134         197  
  134         3358  
3 134     134   411 use warnings;
  134         150  
  134         2506  
4 134     134   778 use Perl::Lint::Constants::Type;
  134         157  
  134         60888  
5 134     134   544 use parent "Perl::Lint::Policy";
  134         144  
  134         563  
6              
7             use constant {
8 134         58558 DESC => 'Regular expression without "/s" flag',
9             EXPL => [240, 241],
10 134     134   7285 };
  134         190  
11              
12             sub evaluate {
13 10     10 0 19 my ($class, $file, $tokens, $src, $args) = @_;
14              
15 10         7 my @violations;
16              
17 10         8 my $depth = 0;
18 10         11 my $is_non_target_reg = 0;
19              
20 10         7 my $enabled_re_m_depth = -1; # use negative value as default
21 10         6 my @enabled_re_m_depths;
22              
23 10         8 my $disable_re_m_depth = -1; # use negative value as default
24 10         5 my @disable_re_m_depths;
25              
26 10         27 for (my $i = 0; my $token = $tokens->[$i]; $i++) {
27 532         378 my $token_type = $token->{type};
28 532         345 my $token_data = $token->{data};
29              
30 532         362 my $next_token = $tokens->[$i+1];
31 532         350 my $next_token_type = $next_token->{type};
32 532         375 my $next_token_data = $next_token->{data};
33              
34 532 100 100     1142 if (!$is_non_target_reg && $token_type == REG_DELIM) {
35 86 100 66     253 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     60 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         58 description => DESC,
50             explanation => EXPL,
51             policy => __PACKAGE__,
52             };
53             }
54             }
55              
56 86         122 next;
57             }
58              
59             # Ignore regexes which are unnecessary to check
60             # XXX more?
61 446 50 100     1934 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         7 $is_non_target_reg = 1;
68 10         18 next;
69             }
70              
71 436 100       430 if ($token_type == SEMI_COLON) {
72 62         46 $is_non_target_reg = 0;
73 62         89 next;
74             }
75              
76             # Represent block scope hierarchy
77 374 100       366 if ($token_type == LEFT_BRACE) {
78 3         5 $depth++;
79 3         6 next;
80             }
81 371 100       366 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       8 if ($disable_re_m_depth == $depth) {
87 1         1 pop @disable_re_m_depths;
88 1   50     5 $disable_re_m_depth = $disable_re_m_depths[-1] // -1;
89             }
90 3         3 $depth--;
91 3         10 next;
92             }
93              
94             # for
95             # `use re qw{/s}`
96             # `use re '/s'`
97 368 100 100     465 if ($token_type == USED_NAME && $token_data eq 're') {
98 4         8 for ($i++; $token = $tokens->[$i]; $i++) {
99 17         15 $token_type = $token->{type};
100 17         12 $token_data = $token->{data};
101 17 100       24 if ($token_type == SEMI_COLON) {
102 4         5 last;
103             }
104 13 100 100     96 if (
      66        
105             ($token_type == RAW_STRING || $token_type == STRING || $token_type == REG_EXP) &&
106             $token_data =~ /s/
107             ) {
108 4         3 push @enabled_re_m_depths, $depth;
109 4         7 $enabled_re_m_depth = $depth;
110             }
111             }
112              
113 4         6 next;
114             }
115              
116             # for
117             # `no re qw{/s}`
118             # `no re '/s'`
119 364 50 100     715 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         3 for ($i++; $token = $tokens->[$i]; $i++) {
126 6         7 $token_type = $token->{type};
127 6         5 $token_data = $token->{data};
128 6 100       9 if ($token_type == SEMI_COLON) {
129 1         2 last;
130             }
131 5 100 66     30 if (
      66        
132             ($token_type == RAW_STRING || $token_type == STRING || $token_type == REG_EXP) &&
133             $token_data =~ /s/
134             ) {
135 1         1 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         33 return \@violations;
145             }
146              
147             1;
148