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   95451 use strict;
  133         257  
  133         5105  
3 133     133   620 use warnings;
  133         203  
  133         3467  
4 133     133   1009 use Perl::Lint::Constants::Type;
  133         204  
  133         85392  
5 133     133   799 use parent "Perl::Lint::Policy";
  133         223  
  133         768  
6              
7             use constant {
8 133         81293 DESC => 'Regular expression without "/x" flag',
9             EXPL => [236],
10 133     133   8929 };
  133         369  
11              
12             sub evaluate {
13 13     13 0 29 my ($class, $file, $tokens, $src, $args) = @_;
14              
15 13         23 my $require_extended_formatting_arg = $args->{require_extended_formatting};
16 13   100     51 my $minimum_regex_length_to_complain_about = $require_extended_formatting_arg->{minimum_regex_length_to_complain_about} || 0;
17 13   100     47 my $strict = $require_extended_formatting_arg->{strict} || 0;
18              
19 13         20 my @violations;
20              
21 13         14 my $depth = 0;
22 13         16 my $is_non_target_reg = 0;
23              
24 13         13 my $enabled_re_x_depth = -1; # use negative value as default
25 13         15 my @enabled_re_x_depths;
26              
27 13         16 my $disabled_re_x_depth = -1; # use negative value as default
28 13         15 my @disabled_re_x_depths;
29              
30 13         43 for (my $i = 0; my $token = $tokens->[$i]; $i++) {
31 615         460 my $token_type = $token->{type};
32 615         551 my $token_data = $token->{data};
33              
34 615         587 my $next_token = $tokens->[$i+1];
35 615         503 my $next_token_type = $next_token->{type};
36 615         551 my $next_token_data = $next_token->{data};
37              
38 615 100 100     1625 if (!$is_non_target_reg && $token_type == REG_DELIM) {
39 109 100 66     394 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     108 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 33         155 push @violations, {
51             filename => $file,
52             line => $token->{line},
53             description => DESC,
54             explanation => EXPL,
55             policy => __PACKAGE__,
56             };
57             }
58             }
59              
60 109         232 next;
61             }
62              
63             # Ignore regexes which are unnecessary to check
64             # XXX more?
65 506 50 66     2824 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         10 $is_non_target_reg = 1;
72 8         23 next;
73             }
74              
75 498 100       626 if ($token_type == SEMI_COLON) {
76 67         55 $is_non_target_reg = 0;
77 67         129 next;
78             }
79              
80 431 100 100     1089 if ($token_type == REG_EXP || $token_type == REG_REPLACE_FROM) {
81 65 100       99 if (length $token_data <= $minimum_regex_length_to_complain_about) {
82 5         6 $is_non_target_reg = 1;
83             }
84 65         129 next;
85             }
86              
87             # Represent block scope hierarchy
88 366 100       469 if ($token_type == LEFT_BRACE) {
89 2         3 $depth++;
90 2         4 next;
91             }
92 364 100       460 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     5 $enabled_re_x_depth = $enabled_re_x_depths[-1] // -1;
96             }
97 2 100       5 if ($disabled_re_x_depth == $depth) {
98 1         1 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         4 next;
103             }
104              
105             # for
106             # `use re qw{/x}`
107             # `use re '/x'`
108 362 100 66     607 if ($token_type == USED_NAME && $token_data eq 're') {
109 4         11 for ($i++; $token = $tokens->[$i]; $i++) {
110 17         14 $token_type = $token->{type};
111 17         16 $token_data = $token->{data};
112 17 100       23 if ($token_type == SEMI_COLON) {
113 4         8 last;
114             }
115 13 100 100     80 if (
      66        
116             ($token_type == RAW_STRING || $token_type == STRING || $token_type == REG_EXP) &&
117             $token_data =~ /x/
118             ) {
119 4         5 push @enabled_re_x_depths, $depth;
120 4         7 $enabled_re_x_depth = $depth;
121             }
122             }
123              
124 4         9 next;
125             }
126              
127             # for
128             # `no re qw{/x}`
129             # `no re '/x'`
130 358 50 66     1023 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         7 for ($i++; $token = $tokens->[$i]; $i++) {
137 6         5 $token_type = $token->{type};
138 6         8 $token_data = $token->{data};
139 6 100       8 if ($token_type == SEMI_COLON) {
140 1         2 last;
141             }
142 5 100 66     41 if (
      66        
143             ($token_type == RAW_STRING || $token_type == STRING || $token_type == REG_EXP) &&
144             $token_data =~ /x/
145             ) {
146 1         2 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         81 return \@violations;
156             }
157              
158             1;
159