File Coverage

blib/lib/Perl/Critic/Policy/Variables/ProhibitNumericNamesWithLeadingZero.pm
Criterion Covered Total %
statement 88 89 98.8
branch 22 34 64.7
condition n/a
subroutine 20 21 95.2
pod 4 5 80.0
total 134 149 89.9


line stmt bran cond sub pod time code
1              
2             use 5.006001;
3 2     2   433815 use strict;
  2         16  
4 2     2   9 use warnings;
  2         4  
  2         45  
5 2     2   9  
  2         4  
  2         50  
6             use English qw{ -no_match_vars };
7 2     2   11  
  2         4  
  2         10  
8             use PPIx::QuoteLike 0.011;
9 2     2   1656 use PPIx::QuoteLike::Constant 0.011 qw{
  2         289269  
  2         83  
10 2         128 LOCATION_LINE
11             LOCATION_LOGICAL_LINE
12             LOCATION_CHARACTER
13             };
14 2     2   16  
  2         29  
15             use PPIx::QuoteLike 0.011;
16 2     2   15 use PPIx::Regexp 0.071;
  2         22  
  2         42  
17 2     2   10 use Readonly;
  2         38  
  2         44  
18 2     2   10 # use Scalar::Util qw{ refaddr };
  2         4  
  2         118  
19              
20             use Perl::Critic::Utils qw< :booleans :characters hashify :severities >;
21 2     2   17  
  2         4  
  2         129  
22             use base 'Perl::Critic::Policy';
23 2     2   655  
  2         5  
  2         1222  
24             our $VERSION = '0.002';
25              
26             #-----------------------------------------------------------------------------
27              
28             Readonly::Scalar my $DESC => q<Numeric variable name %s starts with 0>;
29             Readonly::Scalar my $EXPL =>
30             q<Numeric variable names may not start with 0, except for $0 itself>; ## no critic (RequireInterpolationOfMetachars)
31              
32             Readonly::Scalar my $PACKAGE => '_' . __PACKAGE__;
33              
34             Readonly::Scalar my $LEFT_BRACE => q<{>; # } Seems P::C::U should have
35              
36             Readonly::Hash my %IS_COMMA => hashify( $COMMA, $FATCOMMA );
37             Readonly::Hash my %LOW_PRECEDENCE_BOOLEAN => hashify( qw{ and or xor } );
38              
39             Readonly::Array my @DOUBLE_QUOTISH => qw{
40             PPI::Token::Quote::Double
41             PPI::Token::Quote::Interpolate
42             PPI::Token::QuoteLike::Backtick
43             PPI::Token::QuoteLike::Command
44             PPI::Token::QuoteLike::Readline
45             PPI::Token::HereDoc
46             };
47             Readonly::Array my @REGEXP_ISH => qw{
48             PPI::Token::Regexp::Match
49             PPI::Token::Regexp::Substitute
50             PPI::Token::QuoteLike::Regexp
51             };
52              
53             #-----------------------------------------------------------------------------
54              
55              
56 3     3 0 27330  
57             #-----------------------------------------------------------------------------
58 20     20 1 245  
59 0     0 1 0 # my ( $self, $elem, $document ) = @_;
60 2     2 1 36360 my ( $self, undef, $document ) = @_;
61              
62             return ( map { $_->[0] }
63             sort { $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] }
64             map { [ $_, $_->line_number(), $_->column_number() ] }
65             $self->_critique_element( $document )
66 2     2 1 58 );
67             }
68 20         38  
69 55 50       114 #-----------------------------------------------------------------------------
70 2         10  
  20         211  
71             my ( $self, $elem ) = @_;
72              
73             my @violations;
74              
75             # Find $0nnn
76             push @violations, $self->_find_bare_violations( $elem );
77              
78 26     26   18011 # Find ${0nnn}
79             push @violations, $self->_find_bracketed_violations( $elem );
80 26         53  
81             # Find "$0nnn" and "${0nnn}"
82             push @violations, $self->_find_string_violations( $elem );
83 26         64  
84             # Find m/$0nnn/ and m/${0nnn}/
85             push @violations, $self->_find_regex_violations( $elem );
86 26         73  
87             return @violations;
88             }
89 26         74  
90             #-----------------------------------------------------------------------------
91              
92 26         69 # Find $0nnn
93             my ( $self, $elem ) = @_;
94 26         241  
95             my @violations;
96              
97             # Find $0nnn
98             foreach my $sym ( @{ $elem->find( 'PPI::Token::Magic' ) || [] } ) {
99             my $name = $sym->symbol();
100             $name =~ m/ \W 0 [0-9]+ \z /smx ## no critic (ProhibitEnumeratedClasses)
101 26     26   49 or next;
102             push @violations, $self->violation(
103 26         40 sprintf( $DESC, $name ),
104             $EXPL,
105             $sym,
106 26 50       44 );
  26         66  
107 27         4324 }
108 27 100       985  
109             return @violations;
110 18         105 }
111              
112             #-----------------------------------------------------------------------------
113              
114             # Find ${0nnn}
115             my ( $self, $elem ) = @_;
116              
117 26         2183 my @violations;
118              
119             foreach my $cast ( @{ $elem->find( 'PPI::Token::Cast' ) || [] }) {
120             my $block = $cast->snext_sibling()
121             or next;
122             $block->isa( 'PPI::Structure::Block' )
123             or next;
124 26     26   50 my @tokens = @{ $block->find( 'PPI::Token' ) || [] }
125             or next;
126 26         42 @tokens > 1
127             and next;
128 26 100       51 $tokens[0]->isa( 'PPI::Token::Number' )
  26         68  
129 3 50       206 or next;
130             $tokens[0]->content() =~ m/ \A 0 [0-9]+ \z /smx ## no critic (ProhibitEnumeratedClasses)
131 3 50       71 or next;
132             push @violations, $self->violation(
133 3 50       6 sprintf( $DESC, join q<>, $cast->content(), $block->content() ),
  3 50       19  
134             $EXPL,
135 3 50       605 $cast,
136             );
137 3 50       12 }
138              
139 3 100       9 return @violations;
140             }
141 2         15  
142             #-----------------------------------------------------------------------------
143              
144             # Find "$0nnn" and "${0nnn}"
145             my ( $self, $elem ) = @_;
146              
147             my @violations;
148 26         3935  
149             foreach my $class ( @DOUBLE_QUOTISH ) {
150             foreach my $ppi_str ( @{ $elem->find( $class ) || [] } ) {
151             my $ppix_str = PPIx::QuoteLike->new( $ppi_str )
152             or next;
153             foreach my $interp (
154             @{ $ppix_str->find( 'PPIx::QuoteLike::Token::Interpolation' ) || [] }
155 26     26   53 ) {
156             # NOTE that policy Variables::ProhibitUnusedVarsStricter
157 26         39 # uses a wrapper for $elem->ppi() because it has to link
158             # the little PPI documents it makes out of strings to
159 26         101 # the parent PPI document. This is enforced by test
160 156 100       18436 # xt/author/require_wrapper.t. This policy has (so far)
  156         339  
161 18 50       524 # no need to link the two documents together. If it
162             # develops the need, copy this test in, fix all
163 18         12695 # violatioms, and be prepared to rewrite calls to
164 18 50       49 # parent() and top().
165             push @violations, $self->_critique_element( $interp->ppi() );
166             }
167             }
168             }
169              
170             return @violations;
171             }
172              
173             #-----------------------------------------------------------------------------
174              
175 18         1193 # Find m/$0nnn/ and m/${0nnn}/
176             my ( $self, $elem ) = @_;
177              
178             my @violations;
179              
180 26         3611 foreach my $class ( @REGEXP_ISH ) {
181             foreach my $ppi_re ( @{ $elem->find( $class ) || [] } ) {
182             my $ppix_re = PPIx::Regexp->new( $ppi_re )
183             or next;
184             foreach my $code (
185             @{ $ppix_re->find( 'PPIx::Regexp::Token::Code' ) || [] }
186             ) {
187 26     26   57 # NOTE see previous note.
188             push @violations, $self->_critique_element( $code->ppi() );
189 26         45 }
190             }
191 26         59 }
192 78 100       7414  
  78         189  
193 6 50       567 return @violations;
194             }
195 6         24841  
196 6 50       18 #-----------------------------------------------------------------------------
197              
198             1;
199 6         985  
200              
201             #-----------------------------------------------------------------------------
202              
203             =pod
204 26         3523  
205             =head1 NAME
206              
207             Perl::Critic::Policy::Variables::ProhibitNumericNamesWithLeadingZero - Don't use numeric variable names with leading zeroes.
208              
209              
210             =head1 AFFILIATION
211              
212             This Policy is stand-alone, and is not part of the core
213             L<Perl::Critic|Perl::Critic>.
214              
215              
216             =head1 DESCRIPTION
217              
218             Numeric variable names with leading zeroes are unsupported by Perl, and
219             can lead to obscure bugs. In particular, they are not (or not
220             straightforwardly) accessible as C<${0nnn}>.
221              
222             Starting with Perl 5.32, these variables represent a syntax error, so
223             this policy is useless with current Perls. On the other hand, it may be
224             useful for those with an older code base, especially if they are
225             preparing to upgrade it.
226              
227             =head1 CONFIGURATION
228              
229             This policy supports no configuration items above and beyond the
230             standard ones.
231              
232             =head1 SUPPORT
233              
234             Support is by the author. Please file bug reports at
235             L<https://rt.cpan.org/Public/Dist/Display.html?Name=Perl-Critic-Policy-Variables-ProhibitUnusedVarsStricter>,
236             L<https://github.com/trwyant/perl-Perl-Critic-Policy-Variables-ProhibitUnusedVarsStricter/issues>, or in
237             electronic mail to the author.
238              
239             =head1 AUTHOR
240              
241             Thomas R. Wyant, III F<wyant at cpan dot org>
242              
243             =head1 COPYRIGHT
244              
245             Copyright (C) 2022 Thomas R. Wyant, III
246              
247             =head1 LICENSE
248              
249             This program is free software; you can redistribute it and/or modify it
250             under the same terms as Perl 5.10.0. For more details, see the full text
251             of the licenses in the directory LICENSES.
252              
253             This program is distributed in the hope that it will be useful, but
254             without any warranty; without even the implied warranty of
255             merchantability or fitness for a particular purpose.
256              
257             =cut
258              
259             # Local Variables:
260             # mode: cperl
261             # cperl-indent-level: 4
262             # fill-column: 72
263             # indent-tabs-mode: nil
264             # c-indentation-style: bsd
265             # End:
266             # ex: set ts=8 sts=4 sw=4 tw=72 ft=perl expandtab shiftround :