File Coverage

lib/Perl/Critic/Policy/ValuesAndExpressions/RequireConsistentQuoting.pm
Criterion Covered Total %
statement 340 341 99.7
branch 159 166 95.7
condition 84 95 88.4
subroutine 43 43 100.0
pod 17 17 100.0
total 643 662 97.1


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::ValuesAndExpressions::RequireConsistentQuoting v0.2.4;
2              
3 12     12   1894731 use v5.26.0;
  12         45  
4 12     12   62 use strict;
  12         39  
  12         252  
5 12     12   44 use warnings;
  12         23  
  12         547  
6 12     12   47 use feature "signatures";
  12         29  
  12         1388  
7 12     12   428 use experimental "signatures";
  12         1248  
  12         62  
8              
9 12     12   4410 use parent qw( Perl::Critic::Policy );
  12         2744  
  12         54  
10              
11 12     12   1848156 use List::Util qw( any );
  12         36  
  12         808  
12 12     12   63 use Perl::Critic::Utils qw( $SEVERITY_MEDIUM );
  12         30  
  12         49264  
13              
14             my $Desc = "Quoting";
15             my $Expl_double = 'use ""';
16             my $Expl_single = "use ''";
17             my $Expl_optimal = "use %s";
18             my $Expl_use_qw = "use qw()";
19              
20       11 1   sub supported_parameters { }
21 244     244 1 3101 sub default_severity { $SEVERITY_MEDIUM }
22 1     1 1 6044 sub default_themes { qw( cosmetic ) }
23              
24 488     488 1 1294439 sub applies_to { qw(
25             PPI::Token::Quote::Single
26             PPI::Token::Quote::Double
27             PPI::Token::Quote::Literal
28             PPI::Token::Quote::Interpolate
29             PPI::Token::QuoteLike::Words
30             PPI::Token::QuoteLike::Command
31             PPI::Statement::Include
32             ) }
33              
34 375     375 1 1184 sub would_interpolate ($self, $string) {
  375         409  
  375         469  
  375         376  
35             # This is the authoritative way to check - let PPI decide
36 375         539 my $test_content = qq("$string");
37 375         1151 my $test_doc = PPI::Document->new(\$test_content);
38              
39 375         235787 my $would_interpolate = 0;
40 794         946 $test_doc->find(
41 794     794   10041 sub ($top, $test_elem) {
  794         791  
  794         816  
42 794 100       2874 $would_interpolate = $test_elem->interpolations
43             if $test_elem->isa("PPI::Token::Quote::Double");
44 794         3668 0
45             }
46 375         2605 );
47              
48 375         4784 $would_interpolate
49             }
50              
51 126     126 1 166 sub would_interpolate_from_single_quotes ($self, $string) {
  126         171  
  126         146  
  126         135  
52             # Test whether a string from single quotes would interpolate if converted
53             # to double quotes. This is used when checking single-quoted strings to
54             # see if they should stay single-quoted to avoid unintended interpolation.
55             #
56             # The challenge is that PPI gives us the decoded content of single-quoted
57             # strings. For example, for the source 'price: \\$5.00', PPI's string()
58             # method returns 'price: \$5.00' (with one backslash). But to test
59             # interpolation properly, we need to reconstruct what the original
60             # escaping would have been.
61             #
62             # In single quotes, only backslash (\) and apostrophe (') are escaped:
63             # - '\' in the source becomes '\\' in the content
64             # - '\'' in the source becomes ''' in the content
65             #
66             # So to reconstruct the original string for interpolation testing:
67             # - Each '\' in content represents '\\' in the original source
68             # - Each ''' in content represents '\'' in the original source
69              
70 126         146 my $reconstructed = $string;
71 126         352 $reconstructed =~ s/\\/\\\\/g; # \ → \\
72 126         255 $reconstructed =~ s/'/\\'/g; # ' → \'
73              
74 126         242 $self->would_interpolate($reconstructed)
75             }
76              
77 853     853 1 1480 sub delimiter_preference_order ($self, $delimiter_start) {
  853         801  
  853         807  
  853         770  
78 853 100       1274 return 0 if $delimiter_start eq "(";
79 649 100       974 return 1 if $delimiter_start eq "[";
80 443 100       702 return 2 if $delimiter_start eq "<";
81 127 100       234 return 3 if $delimiter_start eq "{";
82 1         8 99
83             }
84              
85 116     116 1 125 sub parse_quote_token ($self, $elem) {
  116         124  
  116         123  
  116         108  
86 116         238 my $content = $elem->content;
87              
88             # Handle all possible delimiters, not just bracket pairs
89             # Order matters: longer matches first
90 116 50       996 if ($content =~ /\A(?:(qw|qq|qx|q)\s*)?(.)(.*)(.)\z/s) {
91 116         625 my ($op, $start_delim, $str, $end_delim) = ($1, $2, $3, $4);
92 116         560 ($start_delim, $end_delim, $str, $op)
93             }
94             }
95              
96 125     125   134 sub _get_supported_delimiters ($self, $operator) {
  125         153  
  125         174  
  125         130  
97             return (
98             {
99 125         1395 start => "(",
100             end => ")",
101             display => "${operator}()",
102             chars => [ "(", ")" ],
103             }, {
104             start => "[",
105             end => "]",
106             display => "${operator}[]",
107             chars => [ "[", "]" ],
108             }, {
109             start => "<",
110             end => ">",
111             display => "${operator}<>",
112             chars => [ "<", ">" ],
113             }, {
114             start => "{",
115             end => "}",
116             display => "${operator}{}",
117             chars => [ "{", "}" ],
118             }
119             );
120             }
121              
122 125     125 1 1886 sub find_optimal_delimiter ($self, $content, $operator, $start, $end) {
  125         132  
  125         154  
  125         164  
  125         144  
  125         130  
  125         123  
123 125         253 my @delimiters = $self->_get_supported_delimiters($operator);
124              
125 125         237 for my $delim (@delimiters) {
126 500         510 my $count = 0;
127 500         631 for my $char ($delim->{chars}->@*) {
128 1000         6007 $count += () = $content =~ /\Q$char\E/g;
129             }
130 500         762 $delim->{count} = $count;
131             }
132              
133 125         652 my $min_count = (sort { $a <=> $b } map $_->{count}, @delimiters)[0];
  528         734  
134              
135             # Find optimal delimiter: handle unbalanced content, then preference order
136             my ($optimal) = sort {
137 125         229 $a->{count} <=> $b->{count} || # Handle unbalanced first
138             $self->delimiter_preference_order($a->{start}) <=> # Then prefer by order
139             $self->delimiter_preference_order($b->{start})
140 528 50       1135 } @delimiters;
141              
142 125         153 my $current_is_bracket = 0;
143 125         167 my $current_delim;
144 125         163 for my $delim (@delimiters) {
145 304 100 66     728 if ($delim->{start} eq $start && $delim->{end} eq $end) {
146 100         115 $current_delim = $delim;
147 100         108 $current_is_bracket = 1;
148 100         158 last;
149             }
150             }
151              
152 125         147 my $current_is_optimal = 0;
153 125 100 66     446 $current_is_optimal = ($current_delim eq $optimal)
154             if $current_is_bracket && $current_delim;
155              
156 125         696 ($optimal, $current_is_optimal)
157             }
158              
159 32     32 1 42 sub check_delimiter_optimisation ($self, $elem) {
  32         39  
  32         56  
  32         37  
160 32         78 my ($start, $end, $content, $operator) = $self->parse_quote_token($elem);
161 32 50       77 return unless defined $start;
162              
163 32 100 50     98 $operator //= "q" if $start eq "'";
164 32         73 my ($optimal_delim, $current_is_optimal)
165             = $self->find_optimal_delimiter($content, $operator, $start, $end);
166             return $self->violation($Desc,
167 32 100       119 sprintf($Expl_optimal, $optimal_delim->{display}), $elem)
168             unless $current_is_optimal;
169              
170             undef
171 20         80 }
172              
173 611     611 1 178567 sub violates ($self, $elem, $) {
  611         841  
  611         774  
  611         691  
174 611         891 state $dispatch = {
175             "PPI::Token::Quote::Single" => "check_single_quoted",
176             "PPI::Token::Quote::Double" => "check_double_quoted",
177             "PPI::Token::Quote::Literal" => "check_q_literal",
178             "PPI::Token::Quote::Interpolate" => "check_qq_interpolate",
179             "PPI::Token::QuoteLike::Words" => "check_quote_operators",
180             "PPI::Token::QuoteLike::Command" => "check_quote_operators",
181             "PPI::Statement::Include" => "check_use_statement",
182             };
183              
184 611         999 my $class = ref $elem;
185 611 100       1695 my $method = $dispatch->{$class} or return;
186 610         1846 my @violations = grep defined, $self->$method($elem);
187             @violations
188 610         102604 }
189              
190 94     94 1 136 sub check_single_quoted ($self, $elem) {
  94         125  
  94         98  
  94         105  
191 94 100       216 return if $self->_is_in_use_statement($elem);
192 84         272 my $string = $elem->string;
193              
194             # Special case: strings with newlines don't follow the rules
195 84 100       596 return if $self->_has_newlines($string);
196              
197 80         150 my $has_single_quotes = index($string, "'") != -1;
198 80         103 my $has_double_quotes = index($string, '"') != -1;
199              
200 80 100 100     197 return $self->check_delimiter_optimisation($elem)
201             if $has_single_quotes && $has_double_quotes;
202              
203             return if
204             # Keep single quotes if the string contains double quotes
205 78 100 100     210 $has_double_quotes ||
      100        
206             # Check if string contains escape sequences that would have different
207             # meanings between single vs double quotes. If so, preserve single quotes.
208             $self->_has_quote_sensitive_escapes($string) ||
209             # Keep single quotes if double would introduce interpolation
210             $self->would_interpolate_from_single_quotes($string);
211              
212 24         964 $self->violation($Desc, $Expl_double, $elem)
213             }
214              
215 193     193 1 245 sub check_double_quoted ($self, $elem) {
  193         249  
  193         228  
  193         210  
216 193 100       420 return if $self->_is_in_use_statement($elem);
217              
218 150         381 my $string = $elem->string;
219 150         908 my $content = $elem->content;
220              
221             # Special case: strings with newlines don't follow the rules
222 150 100       528 return if $self->_has_newlines($string);
223              
224             # Check for escaped dollar/at signs or double quotes, but only suggest single
225             # quotes if no other interpolation exists AND no dangerous escape sequences
226 146 100 100     552 return $self->violation($Desc, $Expl_single, $elem)
      100        
227             if $content =~ /\\[\$\@\"]/
228             && !$self->_has_quote_sensitive_escapes($string)
229             && !$self->would_interpolate($string);
230              
231             # If has escaped double quotes, suggest qq() — by this point, the ''
232             # suggestion was ruled out (escape sequences or interpolation present),
233             # so qq() eliminates the quote escaping while preserving both
234 134 100       454 if ($content =~ /\\"/) {
235 7         40 my ($optimal) = $self->find_optimal_delimiter($string, "qq", '"', '"');
236 7         41 return $self->violation($Desc, sprintf($Expl_optimal, $optimal->{display}),
237             $elem);
238             }
239              
240             return
241 127         252 }
242              
243 100     100 1 143 sub check_q_literal ($self, $elem) {
  100         133  
  100         140  
  100         120  
244 100 100       267 return if $self->_is_in_use_statement($elem);
245              
246 93         351 my $string = $elem->string;
247              
248             # Special case: strings with newlines don't follow the rules
249 93 100       1436 return if $self->_has_newlines($string);
250              
251 90         154 my $has_single_quotes = index($string, "'") != -1;
252 90         138 my $has_double_quotes = index($string, '"') != -1;
253              
254             # Has both quote types - q() handles this cleanly
255 90 100 100     254 return $self->check_delimiter_optimisation($elem)
256             if $has_single_quotes && $has_double_quotes;
257              
258 78         173 my $would_interpolate = $self->would_interpolate_from_single_quotes($string);
259              
260 78 100       2802 if ($has_single_quotes) {
261 6 100       30 return $would_interpolate
262             ? $self->check_delimiter_optimisation($elem)
263             : $self->violation($Desc, $Expl_double, $elem);
264             }
265              
266 72 100       135 if ($has_double_quotes) {
267 12 100       48 return $would_interpolate
268             ? $self->check_delimiter_optimisation($elem)
269             : $self->violation($Desc, $Expl_single, $elem);
270             }
271              
272 60 100       186 return $self->violation($Desc, $Expl_single, $elem) if $would_interpolate;
273              
274 43         138 $self->violation($Desc, $Expl_double, $elem)
275             }
276              
277 53     53 1 72 sub check_qq_interpolate ($self, $elem) {
  53         73  
  53         63  
  53         59  
278 53 100       130 return if $self->_is_in_use_statement($elem);
279              
280 46         148 my $string = $elem->string;
281              
282             # Special case: strings with newlines don't follow the rules
283 46 100       705 return if $self->_has_newlines($string);
284              
285             # Only preserve qq() if escape sequences are actually needed
286 42 100       126 return $self->check_delimiter_optimisation($elem)
287             if $self->_has_quote_sensitive_escapes($string);
288              
289 35         79 my $double_quote_suggestion
290             = $self->_what_would_double_quotes_suggest($string);
291              
292             # Rules 1,2: If double quotes would suggest single quotes, use single quotes
293 35 100 100     125 if ($double_quote_suggestion && $double_quote_suggestion eq "''") {
294             # qq() is only justified if it handles double quotes cleanly
295 7 100       27 return if index($string, '"') != -1;
296 4         17 return $self->violation($Desc, $Expl_single, $elem);
297             }
298              
299             # Rule 1: If double quotes would suggest qq(), qq() is appropriate
300 28 100 66     90 return $self->check_delimiter_optimisation($elem)
301             if $double_quote_suggestion && $double_quote_suggestion eq "qq()";
302              
303             # Rule 1: Otherwise prefer simple double quotes unless delimiter chars present
304 23   66     99 my $has_delimiter_chars
305             = index($string, '"') != -1 || index($string, "'") != -1;
306              
307 23 100       103 $has_delimiter_chars
308             ? $self->check_delimiter_optimisation($elem)
309             : $self->violation($Desc, $Expl_double, $elem)
310             }
311              
312 92     92 1 105 sub check_quote_operators ($self, $elem) {
  92         109  
  92         103  
  92         91  
313 92 100       197 return if $self->_is_in_use_statement($elem);
314              
315 84         170 my ($current_start, $current_end, $content, $operator)
316             = $self->parse_quote_token($elem);
317 84 50       217 return unless defined $current_start;
318              
319             # Don't skip empty content - () is preferred even for empty quotes
320 84         146 my ($optimal_delim, $current_is_optimal)
321             = $self->find_optimal_delimiter($content, $operator, $current_start,
322             $current_end);
323              
324             return $self->violation($Desc,
325 84 100       358 sprintf($Expl_optimal, $optimal_delim->{display}), $elem)
326             if !$current_is_optimal;
327              
328             return
329 31         86 }
330              
331 72     72   92 sub _analyse_argument_types ($self, $elem, @args) {
  72         79  
  72         80  
  72         101  
  72         77  
332              
333             my $fat_comma
334 72 100   118   385 = any { $_->isa("PPI::Token::Operator") && $_->content eq "=>" } @args;
  118         391  
335             my $complex_expr = any {
336 133 100 100 133   844 $_->isa("PPI::Token::Symbol")
337             || $_->isa("PPI::Structure")
338             || $_->isa("PPI::Statement")
339 72         332 } @args;
340             my $version = any {
341 159 100   159   753 $_->isa("PPI::Token::Number::Version")
342             || $_->isa("PPI::Token::Number::Float")
343 72         291 } @args;
344             my $simple_strings = any {
345 123 100   123   539 $_->isa("PPI::Token::Quote::Single")
346             || $_->isa("PPI::Token::Quote::Double")
347 72         216 } @args;
348             my $q_operators = any {
349 154 100   154   599 $_->isa("PPI::Token::Quote::Literal")
350             || $_->isa("PPI::Token::Quote::Interpolate")
351 72         226 } @args;
352              
353             # Check if the original use statement has parentheses
354 72         209 my @children = $elem->children;
355 72     517   477 my $parens = any { $_->isa("PPI::Structure::List") } @children;
  517         1000  
356              
357 72         433 ($fat_comma, $complex_expr, $version, $simple_strings, $q_operators, $parens)
358             }
359              
360 78     78 1 118 sub check_use_statement ($self, $elem) { ## no critic (complexity)
  78         137  
  78         112  
  78         88  
361             # Check "use" and "no" statements, but not "require"
362 78 100       226 return unless $elem->type =~ /^(use|no)$/;
363              
364 76 100       1859 my @args = $self->_extract_use_arguments($elem) or return;
365              
366 72         198 my ($string_count, $has_qw, $qw_uses_parens)
367             = $self->_summarise_use_arguments(@args);
368              
369             # Check for different types of arguments
370             my (
371 72         225 $has_fat_comma, $has_complex_expr, $has_version,
372             $has_simple_strings, $has_q_operators, $has_parens
373             ) = $self->_analyse_argument_types($elem, @args);
374              
375             # Rule 4: Special cases - no violation
376 72 100 66     195 return () if $has_version && @args == 1; # Single version number
377              
378             # Pragmas with a single argument allow quotes
379 70 100 100     211 return () if @args == 1 && $self->_is_pragma($elem);
380              
381             # Rule 1: qw() without parens should use qw()
382 58 100 100     152 return $self->violation($Desc, $Expl_use_qw, $elem)
383             if $has_qw && !$qw_uses_parens;
384              
385             # Rule 2: Any => operator anywhere → should have no parentheses
386 57 100       127 if ($has_fat_comma) {
387 4 100       11 if ($has_parens) {
388 2         5 state $expl_remove_parens = "remove parentheses";
389 2         10 return $self->violation($Desc, $expl_remove_parens, $elem);
390             }
391 2         9 return ();
392             }
393              
394             # Rule 3: Complex expressions → should have no parentheses
395 53 100       95 if ($has_complex_expr) {
396 6 100       12 if ($has_parens) {
397 3         4 state $expl_remove_parens_complex = "remove parentheses";
398 3         13 return $self->violation($Desc, $expl_remove_parens_complex, $elem);
399             }
400 3         9 return ();
401             }
402              
403             # Check if any string would interpolate (works for all quote types)
404 47         82 for my $arg (@args) {
405             # Skip qw() tokens as they never interpolate
406 67 100       755 next if $arg->isa("PPI::Token::QuoteLike::Words");
407              
408             # Only check tokens that have a string method (string-like tokens)
409 60 50       178 next unless $arg->can("string");
410              
411 60         148 my $content = $arg->string;
412 60 100       464 if ($self->would_interpolate($content)) {
413             # If interpolation is needed, don't suggest qw() - let normal rules apply
414 12         482 return ();
415             }
416             }
417              
418             # Rule 1: All simple strings or q() operators → use qw()
419 35 100 100     1255 if (($has_simple_strings || $has_q_operators) && !$has_qw) {
      100        
420 28         106 return $self->violation($Desc, $Expl_use_qw, $elem);
421             }
422              
423             # Mixed qw() and other things
424 7 100 66     33 if ($has_qw && ($string_count > 0 || $has_q_operators)) {
      33        
425 3         12 return $self->violation($Desc, $Expl_use_qw, $elem);
426             }
427              
428             ()
429 4         8 }
430              
431 187     187   250 sub _extract_use_arguments ($self, $elem) {
  187         229  
  187         267  
  187         190  
432 187         466 my @children = $elem->children;
433 187         1040 my $found_module = 0;
434 187         223 my @args;
435              
436 187         374 for my $child (@children) {
437 1537 100 100     4873 if ($child->isa("PPI::Token::Word") && !$found_module) {
438 374 100       619 next if $child->content =~ /^(use|no)$/;
439             # This is the module name
440 187         669 $found_module = 1;
441 187         330 next;
442             }
443              
444 1163 100       1819 if ($found_module) {
445 976 100       2161 next if $child->isa("PPI::Token::Whitespace");
446 544 100 66     1461 next if $child->isa("PPI::Token::Structure") && $child->content eq ";";
447             # Skip commas but keep fat comma (=>) and other significant operators
448 529 100 100     1408 next if $child->isa("PPI::Token::Operator") && $child->content eq ",";
449              
450             # If it's a list structure (parentheses), extract its contents
451 407 100       1272 if ($child->isa("PPI::Structure::List")) {
452 27         136 push @args, $self->_extract_list_arguments($child);
453             } else {
454 380         576 push @args, $child;
455             }
456             }
457             }
458              
459             @args
460 187         623 }
461              
462 27     27   32 sub _extract_list_arguments ($self, $list) {
  27         52  
  27         29  
  27         33  
463 27         29 my @args;
464 27         54 for my $child ($list->children) {
465 40 100 66     204 if ($child->isa("PPI::Statement::Expression")) {
    100          
466 23         60 for my $expr_child ($child->children) {
467 331 100       717 next if $expr_child->isa("PPI::Token::Whitespace");
468             # Skip commas but keep fat comma (=>) and other significant operators
469             next
470 179 100 100     344 if $expr_child->isa("PPI::Token::Operator")
471             && $expr_child->content eq ",";
472 150         319 push @args, $expr_child;
473             }
474             } elsif ($child->isa("PPI::Statement") || $child->isa("PPI::Structure")) {
475             # Handle other statements and structures (like hash constructors)
476 2         5 push @args, $child;
477             } else {
478 15 50       28 next if $child->isa("PPI::Token::Whitespace");
479 0         0 push @args, $child;
480             }
481             }
482             @args
483 27         102 }
484              
485 72     72   88 sub _summarise_use_arguments ($self, @args) {
  72         90  
  72         125  
  72         84  
486 72         98 my $string_count = 0;
487 72         81 my $has_qw = 0;
488 72         108 my $qw_uses_parens = 1;
489              
490 72         132 for my $arg (@args) {
491 159         348 $self->_count_use_arguments($arg, \$string_count, \$has_qw,
492             \$qw_uses_parens);
493             }
494              
495 72         201 ($string_count, $has_qw, $qw_uses_parens)
496             }
497              
498 244         279 sub _count_use_arguments ($self, $elem, $str_count_ref, $qw_ref, $qw_parens_ref)
  244         280  
  244         282  
  244         278  
499 244     244   314 {
  244         289  
  244         273  
500              
501 244 100 100     1636 $$str_count_ref++
      100        
      100        
502             if $elem->isa("PPI::Token::Quote::Single")
503             || $elem->isa("PPI::Token::Quote::Double")
504             || $elem->isa("PPI::Token::Quote::Literal")
505             || $elem->isa("PPI::Token::Quote::Interpolate");
506              
507 244 100       625 if ($elem->isa("PPI::Token::QuoteLike::Words")) {
508 11         18 $$qw_ref = 1;
509 11         33 my $content = $elem->content;
510 11 100       70 $$qw_parens_ref = 0 if $content !~ /\Aqw\s*\(/;
511             }
512              
513             # Recursively check children (for structures like lists)
514 244 100       916 if ($elem->can("children")) {
515 21         47 for my $child ($elem->children) {
516 85         226 $self->_count_use_arguments($child, $str_count_ref, $qw_ref,
517             $qw_parens_ref);
518             }
519             }
520             }
521              
522 66     66   79 sub _is_pragma ($self, $elem) {
  66         78  
  66         78  
  66         81  
523 66 50       171 my $module = $elem->module or return 0;
524 66         1804 $module =~ /^[a-z][a-z0-9_]*$/
525             }
526              
527 532     532   645 sub _is_in_use_statement ($self, $elem) {
  532         634  
  532         571  
  532         559  
528 532         620 my $current = $elem;
529 532         1492 while ($current) {
530 1539 100 100     6790 if ($current->isa("PPI::Statement::Include")
531             && ($current->type =~ /^(use|no)$/))
532             {
533 111         2758 my @args = $self->_extract_use_arguments($current);
534              
535             # Single-arg pragmas follow normal quoting rules
536 111 100 100     345 return 0 if @args == 1 && $self->_is_pragma($current);
537              
538             # Check if this use statement has any strings that would interpolate
539 99         178 for my $arg (@args) {
540             # Skip qw() tokens as they never interpolate
541 337 100       2836 next if $arg->isa("PPI::Token::QuoteLike::Words");
542              
543             # Only check tokens that have a string method (string-like tokens)
544 326 100       881 next unless $arg->can("string");
545              
546 134         368 my $content = $arg->string;
547 134 100       1067 if ($self->would_interpolate($content)) {
548             # If interpolation is needed, don't treat this as a use statement
549             # so individual strings get checked normally
550 24         910 return 0;
551             }
552             }
553 75         2374 return 1;
554             }
555 1428         2763 $current = $current->parent;
556             }
557             0
558 421         1588 }
559              
560 35     35   83 sub _what_would_double_quotes_suggest ($self, $string) {
  35         72  
  35         69  
  35         37  
561 35         137 my $would_interpolate = $self->would_interpolate($string);
562              
563             # Rules 1,2: If has escaped variables but no interpolation → suggest
564             # single quotes
565 35 100 100     1334 return "''" if !$would_interpolate && ($string =~ /\\[\$\@]/);
566              
567             # Rule 1: If has quotes that need handling → suggest qq()
568 31         66 my $has_single_quotes = index($string, "'") != -1;
569 31         50 my $has_double_quotes = index($string, '"') != -1;
570              
571 31 100       78 if ($has_double_quotes) {
572 8 100 100     42 return "qq()" if $would_interpolate || $has_single_quotes;
573 3         10 return "''"; # Only double quotes, no interpolation
574             }
575              
576             # Rules 1,2: Otherwise double quotes are fine
577             undef
578 23         62 }
579              
580 131     131   176 sub _has_quote_sensitive_escapes ($self, $string) {
  131         210  
  131         193  
  131         131  
581             # Check if string contains escape sequences that would have different meanings
582             # in single vs double quotes. These should be preserved in their current
583             # quote style to maintain their intended meaning.
584             #
585             # This only includes escape sequences where the conversion would change
586             # the actual output, not just the internal representation.
587 131         669 $string =~ /
588             \\(?:
589             [tnrfbae] | # Single char escapes: \t \n \r \f \b \a \e
590             x[0-9a-fA-F]* | # Hex escapes: \x1b \xff
591             x\{[^}]*\} | # Hex braces: \x{1b} \x{263A}
592             [0-7]{1,3} | # Octal: \033 \377
593             o\{[^}]*\} | # Octal braces: \o{033}
594             c. | # Control chars: \c[ \cA
595             N\{[^}]*\} | # Named chars: \N{name} \N{U+263A}
596             [luLUEQ] # String modification: \l \u \L \U \E \Q
597             )
598             /x
599             }
600              
601 373     373   440 sub _has_newlines ($self, $string) {
  373         409  
  373         415  
  373         358  
602             # Check if string contains literal newlines (not \n escape sequences)
603 373         1050 index($string, "\n") != -1
604             }
605              
606             "
607             I see the people working
608             And see it working for them
609             And so I want to join in
610             But then I find it hurt me
611             "
612              
613             __END__
614              
615             =pod
616              
617             =head1 NAME
618              
619             Perl::Critic::Policy::ValuesAndExpressions::RequireConsistentQuoting - Use
620             consistent and optimal quoting
621              
622             =head1 VERSION
623              
624             version v0.2.4
625              
626             =head1 SYNOPSIS
627              
628             # Bad examples:
629             my $greeting = 'hello'; # use double quotes for simple strings
630             my @words = qw{word(with)parens}; # use qw[] for unbalanced content
631             my $text = qq(simple); # use "" instead of qq()
632             my $file = q!path/to/file!; # use "" instead of q()
633             use Config 'arg1', 'arg2'; # simple strings should use qw()
634             use lib ( "$HOME/perl" ); # complex expressions need no
635             # parentheses
636              
637             # Good examples:
638             my $greeting = "hello"; # double quotes for simple strings
639             my @words = qw[ word(with)parens ]; # optimal delimiter choice
640             my $text = "simple"; # "" preferred over qq()
641             my $file = "path/to/file"; # "" reduces punctuation
642             use Config qw( arg1 arg2 ); # simple use arguments use qw()
643             use lib "$HOME/perl"; # interpolation uses normal rules
644              
645             =head1 DESCRIPTION
646              
647             This policy enforces consistent quoting to improve code readability and
648             maintainability. It applies three simple rules:
649              
650             =head2 Rule 1: Reduce punctuation
651              
652             Prefer fewer characters and simpler syntax. Prefer real quotes over quote-like
653             operators when possible.
654              
655             # Good
656             my $text = "hello world"; # "" preferred over qq()
657             my $literal = 'contains$literal'; # '' preferred over q()
658             my $path = "path/to/file"; # simple quotes reduce punctuation
659              
660             # Bad
661             my $text = qq(hello world); # unnecessary quote operator
662             my $literal = q(contains$literal); # unnecessary quote operator
663             my $path = q!path/to/file!; # unnecessary quote operator
664              
665             =head2 Rule 2: Prefer interpolated strings
666              
667             If it doesn't matter whether a string is interpolated or not, prefer the
668             interpolated version (double quotes).
669              
670             # Good
671             my $name = "John"; # simple string uses double quotes
672             my $email = 'user@domain.com'; # literal @ uses single quotes
673             my $var = 'Price: $10'; # literal $ uses single quotes
674              
675             # Bad
676             my $name = 'John'; # should use double quotes
677              
678             =head2 Rule 3: Use bracket delimiters in preference order
679              
680             If the best choice is a quote-like operator, prefer C<()>, C<[]>, C<< <> >>,
681             or C<{}> in that order.
682              
683             # Good
684             my @words = qw( simple list ); # () preferred when content is simple
685             my @data = qw[ has(parens) ]; # [] optimal - handles unbalanced ()
686             my $cmd = qx( has[brackets] ); # () optimal - handles unbalanced []
687             my $text = q( has<angles> ); # () optimal - handles unbalanced <>
688              
689             # Bad - exotic delimiters
690             my @words = qw/word word/; # should use qw()
691             my $path = q|some|path|; # should use ""
692             my $text = qq#some#text#; # should use ""
693              
694             =head2 Special Case: Use and No statements
695              
696             Use and no statements have special quoting requirements for their import lists.
697             Both C<use> and C<no> statements follow identical rules:
698              
699             =over 4
700              
701             =item * Modules with no arguments or empty parentheses are acceptable
702              
703             =item * Single version numbers (e.g., C<1.23>, C<v5.10.0>) are exempt from all
704             rules
705              
706             =item * Fat comma (C<=E<gt>>) arguments should have no parentheses for
707             readability
708              
709             =item * Complex expressions (variables, conditionals, structures) should have
710             no parentheses
711              
712             =item * Arguments requiring interpolation follow normal string quoting rules
713             individually
714              
715             =item * Simple string arguments without interpolation should use C<qw()>
716             with parentheses only
717              
718             =item * Pragmas (all-lowercase module names) with a single argument also allow
719             quoted strings, with normal quoting rules applied
720              
721             =back
722              
723             This design promotes readability whilst maintaining compatibility with
724             L<perlimports|https://metacpan.org/pod/perlimports>.
725              
726             # Good - basic cases
727             use Foo; # no arguments
728             use Bar (); # empty parentheses
729             use Baz 1.23; # version numbers exempt
730             no warnings; # no statements follow same rules
731              
732             # Good - fat comma arguments (no parentheses)
733             use Data::Printer
734             deparse => 0,
735             show_unicode => 1,
736             class => { expand => "all" };
737              
738             # Good - complex expressions (no parentheses)
739             use Module $VERSION;
740             use Config $DEBUG ? "verbose" : "quiet";
741             use Handler { config => "file.conf" };
742              
743             # Good - interpolation cases (normal string rules)
744             use lib "$HOME/perl", "/usr/lib"; # interpolation prevents qw()
745             no warnings "$category", "another"; # applies to no statements too
746              
747             # Good - simple strings use qw()
748             use Foo qw( arg1 arg2 arg3 ); # multiple simple arguments
749             no warnings qw( experimental uninitialized );
750              
751             # Good - pragmas with a single argument allow quotes
752             use feature "class"; # pragma, single arg, double quotes
753             use strict "refs"; # pragma, single arg, double quotes
754             no warnings "experimental"; # no pragma, single arg, double quotes
755             use feature qw( class ); # qw() is still fine too
756              
757             # Bad - incorrect quoting
758             use Foo 'single_arg'; # single quotes should use qw()
759             use Bar "arg1", "arg2"; # simple strings need qw()
760             use Baz qw[ arg1 arg2 ]; # qw() must use parentheses only
761             use Qux ( key => "value" ); # fat comma needs no parentheses
762             use Quux ( $VERSION ); # complex expressions need no
763             # parentheses
764             use feature 'class'; # pragma single arg prefers ""
765              
766             =head2 Special Case: Newlines
767              
768             Strings containing newlines do not follow the rules. But note that outside of a
769             few very special cases, strings with literal newlines are not a good idea.
770              
771             # Allowed
772             my $text = qq(
773             line 1
774             line 2
775             );
776              
777             =head2 Scope
778              
779             This policy covers string literals (C<"">, C<''>), quote operators (C<q()>,
780             C<qq()>), word lists (C<qw()>), command execution (C<qx()>), and use/no
781             statement import lists.
782              
783             The following quote-like constructs are B<not> checked, as they have
784             fundamentally different quoting semantics:
785              
786             =over 4
787              
788             =item * Regular expressions: C<m//>, C<qr//>
789              
790             =item * Substitutions: C<s///>
791              
792             =item * Transliterations: C<tr///>, C<y///>
793              
794             =item * Heredocs: C<< <<EOF >>
795              
796             =back
797              
798             =head2 RATIONALE
799              
800             =over 4
801              
802             =item * Minimising escape characters improves readability and reduces errors
803              
804             =item * Simple quotes are preferred over their C<q()> and C<qq()> equivalents
805             when possible
806              
807             =item * Double quotes are preferred for consistency and to allow potential
808             interpolation
809              
810             =item * Many years ago, Tom Christiansen wrote a lengthy article on how perl's
811             default quoting system is interpolation, and not interpolating means something
812             extraordinary is happening. I can't find the original article, but you can see
813             that double quotes are used by default in The Perl Cookbook, for example.
814              
815             =item * Only bracket delimiters should be used (no exotic delimiters like C</>,
816             C<|>, C<#>, etc.)
817              
818             =item * Optimal delimiter selection reduces visual noise in code
819              
820             =back
821              
822             =head1 AFFILIATION
823              
824             This Policy is part of the Perl::Critic::PJCJ distribution.
825              
826             =head1 CONFIGURATION
827              
828             This Policy is not configurable except for the standard options.
829              
830             =head1 EXAMPLES
831              
832             =head2 String Literals
833              
834             # Bad
835             my $greeting = 'hello'; # Rule 2: should use double quotes
836             my $email = "user@domain.com"; # Rule 2: should use single quotes
837             # (literal @)
838             my $path = 'C:\Program Files'; # Rule 2: should use double quotes
839              
840             # Good
841             my $greeting = "hello"; # double quotes for simple strings
842             my $email = 'user@domain.com'; # single quotes for literal @
843             my $path = "C:\\Program Files"; # double quotes handle backslashes
844              
845             =head2 Quote Operators
846              
847             # Bad
848             my $simple = q(hello); # Rule 1: should use ''
849             my $text = qq(hello); # Rule 1: should use ""
850             my @words = qw/one two/; # Rule 3: should use qw( )
851             my $cmd = qx|ls|; # Rule 3: should use qx( )
852              
853             # Good
854             my $simple = 'hello$literal'; # single quotes for literal content
855             my $text = "hello"; # double quotes preferred
856             my @words = qw( one two ); # bracket delimiters only
857             my $cmd = qx( ls ); # bracket delimiters only
858              
859             =head2 Optimal Delimiter Selection
860              
861             # Bad - unbalanced delimiters
862             my @list = qw(word(with)parens); # Rules 1, 3: unbalanced () in content
863             my $cmd = qx[command[with]brackets]; # Rules 1, 3: unbalanced [] in content
864             my $text = q{word{with}braces}; # Rules 1, 3: unbalanced {} in content
865              
866             # Good - balanced delimiters
867             my @list = qw[ word(with)parens ]; # [] handles parentheses in content
868             my $cmd = qx( command[with]brackets ); # () handles brackets in content
869              
870             =head2 Complex Content
871              
872             # When content has multiple quote types, quote-like operators may be needed
873             my $both = qq(has 'single' and "double" quotes); # qq() handles both
874             # quote types cleanly
875              
876             =head2 Use and No Statement Examples
877              
878             # Bad
879             use Foo 'single_arg'; # single quotes should use qw()
880             use Bar "arg1", "arg2"; # simple strings need qw()
881             use Baz qw[ arg1 arg2 ]; # qw() must use parentheses only
882             use Qux ( key => "value" ); # fat comma should have no parentheses
883             use Quux ( $VERSION ); # complex expressions need no
884             # parentheses
885             no warnings ( "experimental" ); # simple strings should use qw()
886             use feature 'class'; # pragma single arg prefers ""
887              
888             # Good
889             use Foo; # no arguments
890             use Bar (); # empty parentheses
891             use Baz 1.23; # version numbers exempt
892             use Qux qw( single_arg ); # simple string uses qw()
893             use Quux qw( arg1 arg2 arg3 ); # multiple simple arguments
894             no warnings qw( experimental uninitialized ); # no statements follow same
895             # rules
896              
897             # Pragma single-argument examples
898             use feature "class"; # pragma, single arg, double quotes
899             use strict "refs"; # pragma, single arg, double quotes
900             no warnings "experimental"; # no pragma, single arg, double quotes
901             use feature qw( class ); # qw() is still fine too
902              
903             # Fat comma examples (no parentheses)
904             use Data::Printer
905             deparse => 0,
906             show_unicode => 1;
907             use Config
908             key => "value",
909             another_key => { nested => "structure" };
910              
911             # Complex expression examples (no parentheses)
912             use Module $VERSION; # variable argument
913             use Config $DEBUG ? "verbose" : "quiet"; # conditional expression
914             use Handler { config => "file.conf" }; # hash reference
915              
916             # Interpolation examples (normal string rules apply)
917             use lib "$HOME/perl", "/usr/lib"; # interpolation prevents qw()
918             use lib "$x/d1", "$x/d2"; # both strings need interpolation
919             use lib "$HOME/perl", "static"; # mixed interpolation uses double
920             # quotes
921             no warnings "$category", "another"; # no statements handle
922             # interpolation too
923              
924             =head1 METHODS
925              
926             =head2 supported_parameters
927              
928             This policy has no configurable parameters.
929              
930             =head2 violates
931              
932             The main entry point for policy violation checking. Uses a dispatch table to
933             route different quote token types to their appropriate checking methods. This
934             design allows for efficient handling of the six different PPI token types that
935             represent quoted strings and quote-like operators.
936              
937             =head2 would_interpolate
938              
939             Determines whether a string would perform variable interpolation if placed in
940             double quotes. This is critical for deciding between single and double quotes -
941             strings that would interpolate variables should use single quotes to preserve
942             literal content, while non-interpolating strings should use double quotes for
943             consistency.
944              
945             Uses PPI's authoritative parsing to detect interpolation rather than regex
946             patterns, ensuring accurate detection of complex cases like literal variables.
947              
948             =head2 would_interpolate_from_single_quotes
949              
950             Tests whether a string from single quotes would interpolate if converted to
951             double quotes. This specialised version handles the challenge that PPI provides
952             decoded string content rather than the original source text.
953              
954             When checking single-quoted strings, PPI's C<string()> method returns the
955             decoded content. For example, the source C<'price: \\$5.00'> becomes
956             C<'price: \$5.00'> in the content (with one backslash). To test interpolation
957             properly, this method reconstructs what the original escaping would have been
958             by re-escaping backslashes and apostrophes according to single-quote rules.
959              
960             This ensures accurate detection of whether converting a single-quoted string to
961             double quotes would introduce unintended variable interpolation.
962              
963             =head2 delimiter_preference_order
964              
965             Establishes the preference hierarchy for bracket delimiters when multiple
966             options handle the content equally well. The policy prefers
967             delimiters in this order: C<()> > C<[]> > C<< <> >> > C<{}>.
968              
969             This ordering balances readability and convention - parentheses are most
970             familiar and commonly used, while braces are often reserved for hash
971             references and blocks.
972              
973             =head2 parse_quote_token
974              
975             Extracts delimiter and content information from quote-like operators such as
976             C<qw{}>, C<q{}>, C<qq{}>, and C<qx{}>. Handles both bracket pairs (where start
977             and end delimiters differ) and symmetric delimiters (where they're the same).
978              
979             This parsing is essential for delimiter optimisation, as it separates the
980             operator, delimiters, and content for independent analysis.
981              
982             =head2 find_optimal_delimiter
983              
984             Determines the best delimiter choice for a quote-like operator by analysing the
985             content for balanced delimiters. Implements the core logic for Rules 1 and 3:
986             choose delimiters that handle unbalanced content gracefully and prefer bracket
987             delimiters.
988              
989             Only considers bracket delimiters C<()>, C<[]>, C<< <> >>, C<{}> as valid
990             options, rejecting exotic delimiters like C</>, C<|>, C<#>. When multiple
991             delimiters work equally well, uses the preference order to break ties.
992              
993             =head2 check_delimiter_optimisation
994              
995             Validates that quote-like operators use optimal delimiters according to Rules 1
996             and 3. This method coordinates parsing the current token and finding the
997             optimal alternative, issuing violations when the current choice is suboptimal.
998              
999             Acts as a bridge between the parsing and optimisation logic, providing a
1000             clean interface for the quote-checking methods.
1001              
1002             =head2 check_single_quoted
1003              
1004             Enforces Rules 1 and 2 for single-quoted strings: prefer double quotes for
1005             simple strings unless the content contains literal C<$> or C<@> characters that
1006             shouldn't be interpolated, or the string contains double quotes that would
1007             require special handling.
1008              
1009             Also detects when C<q()> operators would be better than single quotes for
1010             complex content, promoting cleaner alternatives.
1011              
1012             =head2 check_double_quoted
1013              
1014             Validates double-quoted strings to ensure they genuinely need interpolation.
1015             Suggests single quotes when the content contains only literal C<$> or C<@>
1016             characters with no actual interpolation, as this indicates the developer
1017             intended literal content.
1018              
1019             This reduces unnecessary complexity and makes the code's intent clearer.
1020              
1021             =head2 check_q_literal
1022              
1023             Enforces Rules 1 and 3 for C<q()> operators. First ensures optimal
1024             delimiter choice, then evaluates whether simpler quote forms would be more
1025             appropriate.
1026              
1027             Allows C<q()> when the content has both single and double quotes (making it
1028             the cleanest option), but suggests simpler alternatives for basic content that
1029             could use C<''> or C<"">.
1030              
1031             =head2 check_qq_interpolate
1032              
1033             Enforces Rules 1 and 3 for C<qq()> operators. First ensures optimal
1034             delimiter choice, then determines whether simple double quotes would suffice.
1035              
1036             The policy prefers C<""> over C<qq()> when the content doesn't contain double
1037             quotes, as this reduces visual noise and follows common Perl conventions.
1038              
1039             =head2 check_quote_operators
1040              
1041             Handles C<qw()> and C<qx()> operators, focusing purely on delimiter
1042             optimisation according to Rules 1 and 3. These operators don't have simpler
1043             alternatives, so the policy only ensures they use the most appropriate
1044             delimiters to handle unbalanced content gracefully.
1045              
1046             =head2 check_use_statement
1047              
1048             Checks quoting consistency in C<use> and C<no> statements. Implements
1049             comprehensive argument analysis to enforce appropriate quoting based on
1050             argument types:
1051              
1052             =over 4
1053              
1054             =item * Version numbers are exempt from all quoting rules
1055              
1056             =item * Fat comma arguments should have no parentheses for readability
1057              
1058             =item * Complex expressions should have no parentheses to reduce visual noise
1059              
1060             =item * Arguments requiring interpolation follow normal string quoting rules
1061              
1062             =item * Simple string arguments should use C<qw()> with parentheses only
1063              
1064             =back
1065              
1066             This promotes consistency and clarity whilst supporting modern Perl idioms
1067             and maintaining compatibility with tools like perlimports.
1068              
1069             =head2 _analyse_argument_types
1070              
1071             Analyses use/no statement arguments to classify them into different types:
1072             fat comma operators, complex expressions, version numbers, simple strings,
1073             and quote operators. This classification drives the quoting rule enforcement
1074             in C<check_use_statement>.
1075              
1076             Also detects whether the original statement uses parentheses, which affects
1077             the violation messages for fat comma and complex expression cases.
1078              
1079             =head2 _extract_use_arguments
1080              
1081             Extracts and processes arguments from use/no statements, handling both bare
1082             arguments and those enclosed in parentheses. Skips whitespace, commas, and
1083             semicolons whilst preserving significant operators like fat comma (C<=E<gt>>).
1084              
1085             Handles nested list structures by recursively extracting their contents,
1086             ensuring all argument types are properly identified for rule enforcement.
1087              
1088             =head2 _extract_list_arguments
1089              
1090             Recursively processes parenthesised argument lists within use/no statements.
1091             Handles complex nested structures including expressions, statements, and
1092             hash constructors whilst filtering out structural tokens that don't affect
1093             quoting decisions.
1094              
1095             =head2 _summarise_use_arguments
1096              
1097             Provides summary statistics about use/no statement arguments: counts string
1098             tokens, detects C<qw()> usage, and verifies that C<qw()> operators use
1099             parentheses rather than other delimiters. This information drives the
1100             violation logic in C<check_use_statement>.
1101              
1102             =head1 AUTHOR
1103              
1104             Paul Johnson C<< <paul@pjcj.net> >>
1105              
1106             =head1 COPYRIGHT
1107              
1108             Copyright 2025 Paul Johnson.
1109              
1110             =head1 LICENCE
1111              
1112             This program is free software; you can redistribute it and/or modify it under
1113             the same terms as Perl itself.
1114              
1115             =cut