File Coverage

blib/lib/Perl/Critic/Policy/ValuesAndExpressions/ProhibitLeadingZeros.pm
Criterion Covered Total %
statement 96 96 100.0
branch 47 68 69.1
condition 13 15 86.6
subroutine 18 18 100.0
pod 4 5 80.0
total 178 202 88.1


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::ValuesAndExpressions::ProhibitLeadingZeros;
2              
3 40     40   27705 use 5.010001;
  40         166  
4 40     40   229 use strict;
  40         105  
  40         864  
5 40     40   205 use warnings;
  40         86  
  40         1026  
6              
7 40     40   210 use Readonly;
  40         100  
  40         2167  
8              
9 40     40   263 use Perl::Critic::Utils qw{ :characters :severities };
  40         92  
  40         2056  
10 40     40   11656 use parent 'Perl::Critic::Policy';
  40         99  
  40         325  
11              
12             our $VERSION = '1.146';
13              
14             #-----------------------------------------------------------------------------
15              
16             Readonly::Scalar my $LEADING_RX => qr<\A [+-]? (?: 0+ _* )+ [1-9]>xms;
17             Readonly::Scalar my $EXPL => [ 58 ];
18              
19             #-----------------------------------------------------------------------------
20              
21             sub supported_parameters {
22             return (
23             {
24 105     105 0 2203 name => 'strict',
25             description =>
26             q<Don't allow any leading zeros at all. Otherwise builtins that deal with Unix permissions, e.g. chmod, don't get flagged.>,
27             default_string => '0',
28             behavior => 'boolean',
29             },
30             );
31             }
32              
33 117     117 1 511 sub default_severity { return $SEVERITY_HIGHEST }
34 92     92 1 431 sub default_themes { return qw< core pbp bugs certrec > }
35 51     51 1 224 sub applies_to { return 'PPI::Token::Number::Octal' }
36              
37             #-----------------------------------------------------------------------------
38              
39             sub violates {
40 63     63 1 208 my ( $self, $elem, undef ) = @_;
41              
42 63 100       390 return if $elem !~ $LEADING_RX;
43 61 100       752 return $self->_create_violation($elem) if $self->{_strict};
44 44 100       154 return if $self->_is_first_argument_of_chmod_or_umask($elem);
45 38 100       125 return if $self->_is_second_argument_of_mkdir($elem);
46 36 100       276 return if $self->_is_second_argument_of_mkfifo($elem);
47 32 100       267 return if $self->_is_third_argument_of_dbmopen($elem);
48 30 100       215 return if $self->_is_fourth_argument_of_sysopen($elem);
49 26         194 return $self->_create_violation($elem);
50             }
51              
52             sub _create_violation {
53 43     43   123 my ($self, $elem) = @_;
54              
55 43         164 return $self->violation(
56             qq<Integer with leading zeros: "$elem">,
57             $EXPL,
58             $elem
59             );
60             }
61              
62             sub _is_first_argument_of_chmod_or_umask {
63 44     44   121 my ($self, $elem) = @_;
64              
65 44         149 my $previous_token = _previous_token_that_isnt_a_parenthesis($elem);
66 44 50       162 return if not $previous_token;
67              
68 44         124 my $content = $previous_token->content();
69 44   100     363 return $content eq 'chmod' || $content eq 'umask';
70             }
71              
72             sub _is_second_argument_of_mkdir {
73 38     38   106 my ($self, $elem) = @_;
74              
75             # Preceding comma.
76 38         95 my $previous_token = _previous_token_that_isnt_a_parenthesis($elem);
77 38 50       144 return if not $previous_token;
78 38 100       116 return if $previous_token->content() ne $COMMA; # Don't know what it is.
79              
80             # Directory name.
81 12         65 $previous_token =
82             _previous_token_that_isnt_a_parenthesis($previous_token);
83 12 50       48 return if not $previous_token;
84              
85 12         36 $previous_token =
86             _previous_token_that_isnt_a_parenthesis($previous_token);
87 12 50       50 return if not $previous_token;
88              
89 12         38 return $previous_token->content() eq 'mkdir';
90             }
91              
92             sub _is_second_argument_of_mkfifo {
93 36     36   133 my ($self, $elem) = @_;
94              
95             # Preceding comma.
96 36         140 my $previous_token = _previous_token_that_isnt_a_parenthesis($elem);
97 36 50       139 return if not $previous_token;
98 36 100       109 return if $previous_token->content() ne $COMMA; # Don't know what it is.
99              
100             # FIFO name.
101 10         55 $previous_token =
102             _previous_token_that_isnt_a_parenthesis($previous_token);
103 10 50       39 return if not $previous_token;
104              
105 10         30 $previous_token =
106             _previous_token_that_isnt_a_parenthesis($previous_token);
107 10 50       41 return if not $previous_token;
108              
109 10   100     28 return $previous_token->content() eq 'mkfifo'
110             || $previous_token->content() eq 'POSIX::mkfifo';
111             }
112              
113             sub _is_third_argument_of_dbmopen {
114 32     32   79 my ($self, $elem) = @_;
115              
116             # Preceding comma.
117 32         75 my $previous_token = _previous_token_that_isnt_a_parenthesis($elem);
118 32 50       116 return if not $previous_token;
119 32 100       117 return if $previous_token->content() ne $COMMA; # Don't know what it is.
120              
121             # File path.
122 6         34 $previous_token =
123             _previous_token_that_isnt_a_parenthesis($previous_token);
124 6 50       26 return if not $previous_token;
125              
126             # Another comma.
127 6         21 $previous_token =
128             _previous_token_that_isnt_a_parenthesis($previous_token);
129 6 50       29 return if not $previous_token;
130 6 100       19 return if $previous_token->content() ne $COMMA; # Don't know what it is.
131              
132             # Variable name.
133 4         27 $previous_token =
134             _previous_token_that_isnt_a_parenthesis($previous_token);
135 4 50       19 return if not $previous_token;
136              
137 4         14 $previous_token =
138             _previous_token_that_isnt_a_parenthesis($previous_token);
139 4 50       21 return if not $previous_token;
140              
141 4         16 return $previous_token->content() eq 'dbmopen';
142             }
143              
144             sub _is_fourth_argument_of_sysopen {
145 30     30   84 my ($self, $elem) = @_;
146              
147             # Preceding comma.
148 30         67 my $previous_token = _previous_token_that_isnt_a_parenthesis($elem);
149 30 50       107 return if not $previous_token;
150 30 100       88 return if $previous_token->content() ne $COMMA; # Don't know what it is.
151              
152             # Mode.
153 4         23 $previous_token =
154             _previous_token_that_isnt_a_parenthesis($previous_token);
155 4   66     24 while ($previous_token and $previous_token->content() ne $COMMA) {
156 12         70 $previous_token =
157             _previous_token_that_isnt_a_parenthesis($previous_token);
158             }
159 4 50       31 return if not $previous_token;
160 4 50       15 return if $previous_token->content() ne $COMMA; # Don't know what it is.
161              
162             # File name.
163 4         26 $previous_token =
164             _previous_token_that_isnt_a_parenthesis($previous_token);
165 4 50       19 return if not $previous_token;
166              
167             # Yet another comma.
168 4         13 $previous_token =
169             _previous_token_that_isnt_a_parenthesis($previous_token);
170 4 50       18 return if not $previous_token;
171 4 50       13 return if $previous_token->content() ne $COMMA; # Don't know what it is.
172              
173             # File handle.
174 4         25 $previous_token =
175             _previous_token_that_isnt_a_parenthesis($previous_token);
176 4 50       17 return if not $previous_token;
177              
178 4         12 $previous_token =
179             _previous_token_that_isnt_a_parenthesis($previous_token);
180 4 50       19 return if not $previous_token;
181              
182             # GitHub #789
183 4 100       14 if ( $previous_token->content() eq 'my' ) {
184 1         7 $previous_token = _previous_token_that_isnt_a_parenthesis(
185             $previous_token );
186 1 50       6 return if not $previous_token;
187             }
188              
189 4         23 return $previous_token->content() eq 'sysopen';
190             }
191              
192             sub _previous_token_that_isnt_a_parenthesis {
193 277     277   547 my ($elem) = @_;
194              
195 277         767 my $previous_token = $elem->previous_token();
196 277   100     9649 while (
      66        
197             $previous_token
198             and (
199             not $previous_token->significant()
200             or $previous_token->content() eq $LEFT_PAREN
201             or $previous_token->content() eq $RIGHT_PAREN
202             )
203             ) {
204 240         1589 $previous_token = $previous_token->previous_token();
205             }
206              
207 277         8756 return $previous_token;
208             }
209              
210             1;
211              
212             __END__
213              
214             #-----------------------------------------------------------------------------
215              
216             =pod
217              
218             =head1 NAME
219              
220             Perl::Critic::Policy::ValuesAndExpressions::ProhibitLeadingZeros - Write C<oct(755)> instead of C<0755>.
221              
222              
223             =head1 AFFILIATION
224              
225             This Policy is part of the core L<Perl::Critic|Perl::Critic>
226             distribution.
227              
228              
229             =head1 DESCRIPTION
230              
231             Perl interprets numbers with leading zeros as octal. If that's what
232             you really want, its better to use C<oct> and make it obvious.
233              
234             $var = 041; # not ok, actually 33
235             $var = oct(41); # ok
236              
237             chmod 0644, $file; # ok by default
238             dbmopen %database, 'foo.db', 0600; # ok by default
239             mkdir $directory, 0755; # ok by default
240             sysopen $filehandle, $filename, O_RDWR, 0666; # ok by default
241             umask 0002; # ok by default
242              
243             use POSIX 'mkfifo';
244             mkfifo $fifo, 0600; # ok by default
245             POSIX::mkfifo $fifo, 0600; # ok by default
246              
247             =head1 CONFIGURATION
248              
249             If you want to ban all leading zeros, set C<strict> to a true value in
250             a F<.perlcriticrc> file.
251              
252             [ValuesAndExpressions::ProhibitLeadingZeros]
253             strict = 1
254              
255              
256             =head1 AUTHOR
257              
258             Jeffrey Ryan Thalhammer <jeff@imaginative-software.com>
259              
260             =head1 COPYRIGHT
261              
262             Copyright (c) 2005-2011 Imaginative Software Systems. All rights reserved.
263              
264             This program is free software; you can redistribute it and/or modify
265             it under the same terms as Perl itself. The full text of this license
266             can be found in the LICENSE file included with this module.
267              
268             =cut
269              
270             # Local Variables:
271             # mode: cperl
272             # cperl-indent-level: 4
273             # fill-column: 78
274             # indent-tabs-mode: nil
275             # c-indentation-style: bsd
276             # End:
277             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :