File Coverage

blib/lib/Perl/Lint/Policy/RegularExpressions/RequireExtendedFormatting.pm
Criterion Covered Total %
statement 80 80 100.0
branch 32 34 94.1
condition 42 62 67.7
subroutine 6 6 100.0
pod 0 1 0.0
total 160 183 87.4


line stmt bran cond sub pod time code
1             package Perl::Lint::Policy::RegularExpressions::RequireExtendedFormatting;
2 133     133   70123 use strict;
  133         168  
  133         3155  
3 133     133   443 use warnings;
  133         151  
  133         2441  
4 133     133   773 use Perl::Lint::Constants::Type;
  133         147  
  133         60865  
5 133     133   568 use parent "Perl::Lint::Policy";
  133         152  
  133         585  
6              
7             use constant {
8 133         62568 DESC => 'Regular expression without "/x" flag',
9             EXPL => [236],
10 133     133   6898 };
  133         158  
11              
12             sub evaluate {
13 13     13 0 26 my ($class, $file, $tokens, $src, $args) = @_;
14              
15 13         17 my $require_extended_formatting_arg = $args->{require_extended_formatting};
16 13   100     39 my $minimum_regex_length_to_complain_about = $require_extended_formatting_arg->{minimum_regex_length_to_complain_about} || 0;
17 13   100     37 my $strict = $require_extended_formatting_arg->{strict} || 0;
18              
19 13         11 my @violations;
20              
21 13         10 my $depth = 0;
22 13         11 my $is_non_target_reg = 0;
23              
24 13         11 my $enabled_re_x_depth = -1; # use negative value as default
25 13         11 my @enabled_re_x_depths;
26              
27 13         12 my $disabled_re_x_depth = -1; # use negative value as default
28 13         8 my @disabled_re_x_depths;
29              
30 13         39 for (my $i = 0; my $token = $tokens->[$i]; $i++) {
31 615         389 my $token_type = $token->{type};
32 615         414 my $token_data = $token->{data};
33              
34 615         423 my $next_token = $tokens->[$i+1];
35 615         405 my $next_token_type = $next_token->{type};
36 615         401 my $next_token_data = $next_token->{data};
37              
38 615 100 100     1365 if (!$is_non_target_reg && $token_type == REG_DELIM) {
39 109 100 66     318 if (
      33        
40             defined $next_token_type &&
41             (
42             $next_token_type == SEMI_COLON || # when any regex options don't exist
43             ($next_token_type == REG_OPT && $next_token_data !~ /x/) # when the `x` regex option doesn't exist
44             )
45             ) {
46 35 100 66     89 if (
      66        
      66        
47             !($enabled_re_x_depth >= 0 && $depth >= $enabled_re_x_depth) ||
48             ($disabled_re_x_depth >= 0 && $disabled_re_x_depth > $enabled_re_x_depth)
49             ) {
50             push @violations, {
51             filename => $file,
52             line => $token->{line},
53 33         92 description => DESC,
54             explanation => EXPL,
55             policy => __PACKAGE__,
56             };
57             }
58             }
59              
60 109         165 next;
61             }
62              
63             # Ignore regexes which are unnecessary to check
64             # XXX more?
65 506 50 66     2304 if (
      66        
      33        
66             $token_type == REG_ALL_REPLACE ||
67             $token_type == REG_LIST ||
68             $token_type == REG_QUOTE ||
69             $token_type == REG_EXEC
70             ) {
71 8         4 $is_non_target_reg = 1;
72 8         14 next;
73             }
74              
75 498 100       517 if ($token_type == SEMI_COLON) {
76 67         47 $is_non_target_reg = 0;
77 67         110 next;
78             }
79              
80 431 100 100     947 if ($token_type == REG_EXP || $token_type == REG_REPLACE_FROM) {
81 65 100       94 if (length $token_data <= $minimum_regex_length_to_complain_about) {
82 5         6 $is_non_target_reg = 1;
83             }
84 65         87 next;
85             }
86              
87             # Represent block scope hierarchy
88 366 100       381 if ($token_type == LEFT_BRACE) {
89 2         3 $depth++;
90 2         4 next;
91             }
92 364 100       372 if ($token_type == RIGHT_BRACE) {
93 2 100       5 if ($enabled_re_x_depth == $depth) {
94 1         2 pop @enabled_re_x_depths;
95 1   50     4 $enabled_re_x_depth = $enabled_re_x_depths[-1] // -1;
96             }
97 2 100       4 if ($disabled_re_x_depth == $depth) {
98 1         2 pop @disabled_re_x_depths;
99 1   50     5 $disabled_re_x_depth = $disabled_re_x_depths[-1] // -1;
100             }
101 2         3 $depth--;
102 2         6 next;
103             }
104              
105             # for
106             # `use re qw{/x}`
107             # `use re '/x'`
108 362 100 66     447 if ($token_type == USED_NAME && $token_data eq 're') {
109 4         9 for ($i++; $token = $tokens->[$i]; $i++) {
110 17         15 $token_type = $token->{type};
111 17         35 $token_data = $token->{data};
112 17 100       22 if ($token_type == SEMI_COLON) {
113 4         5 last;
114             }
115 13 100 100     69 if (
      66        
116             ($token_type == RAW_STRING || $token_type == STRING || $token_type == REG_EXP) &&
117             $token_data =~ /x/
118             ) {
119 4         6 push @enabled_re_x_depths, $depth;
120 4         7 $enabled_re_x_depth = $depth;
121             }
122             }
123              
124 4         7 next;
125             }
126              
127             # for
128             # `no re qw{/x}`
129             # `no re '/x'`
130 358 50 66     730 if (
      66        
      33        
131             $token_type == BUILTIN_FUNC &&
132             $token_data eq 'no' &&
133             $next_token_type == KEY &&
134             $next_token_data eq 're'
135             ) {
136 1         6 for ($i++; $token = $tokens->[$i]; $i++) {
137 6         6 $token_type = $token->{type};
138 6         5 $token_data = $token->{data};
139 6 100       9 if ($token_type == SEMI_COLON) {
140 1         2 last;
141             }
142 5 100 66     31 if (
      66        
143             ($token_type == RAW_STRING || $token_type == STRING || $token_type == REG_EXP) &&
144             $token_data =~ /x/
145             ) {
146 1         1 push @disabled_re_x_depths, $depth;
147 1         2 $disabled_re_x_depth = $depth;
148             }
149             }
150              
151 1         2 next;
152             }
153             }
154              
155 13         54 return \@violations;
156             }
157              
158             1;
159