File Coverage

blib/lib/Perl/Critic/Policy/ValuesAndExpressions/ProhibitMagicNumbers.pm
Criterion Covered Total %
statement 158 165 95.7
branch 89 116 76.7
condition 21 26 80.7
subroutine 22 22 100.0
pod 6 7 85.7
total 296 336 88.1


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::ValuesAndExpressions::ProhibitMagicNumbers;
2              
3 40     40   30666 use 5.010001;
  40         166  
4 40     40   227 use strict;
  40         93  
  40         820  
5 40     40   200 use warnings;
  40         110  
  40         1139  
6              
7 40     40   229 use Readonly;
  40         83  
  40         2110  
8              
9 40     40   289 use Perl::Critic::Utils qw{ :booleans :characters :severities :data_conversion };
  40         170  
  40         2333  
10              
11 40     40   14492 use parent 'Perl::Critic::Policy';
  40         143  
  40         269  
12              
13             our $VERSION = '1.148';
14              
15             #----------------------------------------------------------------------------
16              
17             Readonly::Scalar my $EXPL =>
18             q{Unnamed numeric literals make code less maintainable};
19             Readonly::Scalar my $USE_READONLY_OR_CONSTANT =>
20             ' Use the Readonly or Const::Fast module or the "constant" pragma instead';
21             Readonly::Scalar my $TYPE_NOT_ALLOWED_SUFFIX =>
22             ") are not allowed.$USE_READONLY_OR_CONSTANT";
23              
24             Readonly::Scalar my $UNSIGNED_NUMBER =>
25             qr{
26             \d+ (?: [$PERIOD] \d+ )? # 1, 1.5, etc.
27             | [$PERIOD] \d+ # .3, .7, etc.
28             }xms;
29             Readonly::Scalar my $SIGNED_NUMBER => qr/ [-+]? $UNSIGNED_NUMBER /xms;
30              
31             Readonly::Scalar my $RANGE =>
32             qr{
33             \A
34             ($SIGNED_NUMBER)
35             [$PERIOD] [$PERIOD]
36             ($SIGNED_NUMBER)
37             (?:
38             [$COLON] by [$LEFT_PAREN]
39             ($UNSIGNED_NUMBER)
40             [$RIGHT_PAREN]
41             )?
42             \z
43             }xms;
44              
45             Readonly::Scalar my $SPECIAL_ARRAY_SUBSCRIPT_EXEMPTION => -1;
46              
47             #----------------------------------------------------------------------------
48              
49             sub supported_parameters {
50             return (
51             {
52 217     217 0 5354 name => 'allowed_values',
53             description => 'Individual and ranges of values to allow, and/or "all_integers".',
54             default_string => '0 1 2',
55             parser => \&_parse_allowed_values,
56             },
57             {
58             name => 'allowed_types',
59             description => 'Kind of literals to allow.',
60             default_string => 'Float',
61             behavior => 'enumeration',
62             enumeration_values => [ qw{ Binary Exp Float Hex Octal } ],
63             enumeration_allow_multiple_values => 1,
64             },
65             {
66             name => 'allow_to_the_right_of_a_fat_comma',
67             description =>
68             q[Should anything to the right of a "=>" be allowed?],
69             default_string => '1',
70             behavior => 'boolean',
71             },
72             {
73             name => 'constant_creator_subroutines',
74             description => q{Names of subroutines that create constants},
75             behavior => 'string list',
76             list_always_present_values => [
77             qw<
78             Readonly Readonly::Scalar Readonly::Array Readonly::Hash
79             const
80             >,
81             ],
82             },
83             );
84             }
85              
86 121     121 1 599 sub default_severity { return $SEVERITY_LOW }
87 74     74 1 378 sub default_themes { return qw( core maintenance certrec ) }
88 125     125 1 427 sub applies_to { return 'PPI::Token::Number' }
89              
90 129     129 1 463 sub default_maximum_violations_per_document { return 10; }
91              
92             #----------------------------------------------------------------------------
93              
94             sub initialize_if_enabled {
95 148     148 1 490 my ($self, $config) = @_;
96              
97 148         748 $self->_determine_checked_types();
98              
99 148         620 return $TRUE;
100             }
101              
102             sub _parse_allowed_values {
103 215     215   936 my ($self, $parameter, $config_string) = @_;
104              
105 215         956 my ( $all_integers_allowed, $allowed_values )
106             = _determine_allowed_values($config_string);
107              
108 215         596 my $allowed_string = ' is not one of the allowed literal values (';
109 215 100       833 if ($all_integers_allowed) {
110 7         24 $allowed_string .= 'all integers';
111              
112 7 100       13 if ( %{$allowed_values} ) {
  7         26  
113 2         7 $allowed_string .= ', ';
114             }
115             }
116             $allowed_string
117 215         676 .= ( join ', ', sort { $a <=> $b } keys %{$allowed_values} ) . ').'
  672         2772  
  215         1803  
118             . $USE_READONLY_OR_CONSTANT;
119              
120 215         821 $self->{_allowed_values} = $allowed_values;
121 215         644 $self->{_all_integers_allowed} = $all_integers_allowed;
122 215         653 $self->{_allowed_string} = $allowed_string;
123              
124 215         704 return;
125             }
126              
127             sub _determine_allowed_values {
128 215     215   653 my ($config_string) = @_;
129              
130 215         680 my @allowed_values;
131             my @potential_allowed_values;
132 215         587 my $all_integers_allowed = 0;
133              
134 215 100       953 if ( defined $config_string ) {
135             my @allowed_values_strings =
136 31         189 grep {$_} split m/\s+/xms, $config_string;
  42         150  
137              
138 31         109 foreach my $value_string (@allowed_values_strings) {
139 40 100       564 if ($value_string eq 'all_integers') {
    100          
    50          
140 7         19 $all_integers_allowed = 1;
141             } elsif ( $value_string =~ m/ \A $SIGNED_NUMBER \z /xms ) {
142 25         116 push @potential_allowed_values, $value_string + 0;
143             } elsif ( $value_string =~ m/$RANGE/xms ) {
144 8         43 my ( $minimum, $maximum, $increment ) = ($1, $2, $3);
145 8   100     43 $increment ||= 1;
146              
147 8         22 $minimum += 0;
148 8         20 $maximum += 0;
149 8         19 $increment += 0;
150              
151 8         31 for ( ## no critic (ProhibitCStyleForLoops)
152             my $value = $minimum;
153             $value <= $maximum;
154             $value += $increment
155             ) {
156 48         116 push @potential_allowed_values, $value;
157             }
158             } else {
159 0         0 die q{Invalid value for allowed_values: }, $value_string,
160             q{. Must be a number, a number range, or},
161             qq{ "all_integers".\n};
162             }
163             }
164              
165 31 100       114 if ($all_integers_allowed) {
166 7         19 @allowed_values = grep { $_ != int $_ } @potential_allowed_values; ## no critic ( BuiltinFunctions::ProhibitUselessTopic )
  7         21  
167             } else {
168 24         96 @allowed_values = @potential_allowed_values;
169             }
170             } else {
171 184         657 @allowed_values = (2);
172             }
173              
174 215 100       828 if ( not $all_integers_allowed ) {
175 208         617 push @allowed_values, 0, 1;
176             }
177 215         996 my %allowed_values = hashify(@allowed_values);
178              
179 215         1072 return ( $all_integers_allowed, \%allowed_values );
180             }
181              
182             sub _determine_checked_types {
183 148     148   486 my ($self) = @_;
184              
185 148         1199 my %checked_types = (
186             'PPI::Token::Number::Binary' => 'Binary literals (',
187             'PPI::Token::Number::Float' => 'Floating-point literals (',
188             'PPI::Token::Number::Exp' => 'Exponential literals (',
189             'PPI::Token::Number::Hex' => 'Hexadecimal literals (',
190             'PPI::Token::Number::Octal' => 'Octal literals (',
191             'PPI::Token::Number::Version' => 'Version literals (',
192             );
193              
194             # This will be set by the enumeration behavior specified in
195             # supported_parameters() above.
196 148         448 my $allowed_types = $self->{_allowed_types};
197              
198 148         366 foreach my $allowed_type ( keys %{$allowed_types} ) {
  148         762  
199 144         686 delete $checked_types{"PPI::Token::Number::$allowed_type"};
200              
201 144 100       731 if ( $allowed_type eq 'Exp' ) {
202              
203             # because an Exp isa(Float).
204 2         9 delete $checked_types{'PPI::Token::Number::Float'};
205             }
206             }
207              
208 148         562 $self->{_checked_types} = \%checked_types;
209              
210 148         412 return;
211             }
212              
213              
214             sub violates {
215 294     294 1 764 my ( $self, $elem, undef ) = @_;
216              
217 294 100       939 if ( $self->{_allow_to_the_right_of_a_fat_comma} ) {
218 276 100       700 return if _element_is_to_the_right_of_a_fat_comma($elem);
219             }
220              
221 271 100       3312 return if _element_is_in_an_include_readonly_or_version_statement(
222             $self, $elem,
223             );
224 176 50       586 return if _element_is_in_a_plan_statement($elem);
225 176 100       613 return if _element_is_in_a_constant_subroutine($elem);
226 174 100       551 return if _element_is_a_package_statement_version_number($elem);
227              
228 172         718 my $literal = $elem->literal();
229 172 100 100     5277 if (
      66        
      100        
      100        
      100        
230             defined $literal
231             and not (
232             $self->{_all_integers_allowed}
233             and int $literal == $literal
234             )
235             and not defined $self->{_allowed_values}{$literal}
236             and not (
237             _element_is_sole_component_of_a_subscript($elem)
238             and $literal == $SPECIAL_ARRAY_SUBSCRIPT_EXEMPTION
239             )
240             ) {
241             return
242             $self->violation(
243             $elem->content() . $self->{_allowed_string},
244 37         129 $EXPL,
245             $elem,
246             );
247             }
248              
249              
250 135         342 my ( $number_type, $type_string );
251              
252 135         311 while (
253 777         2479 ( $number_type, $type_string ) = ( each %{ $self->{_checked_types} } )
254             ) {
255 652 100       2388 if ( $elem->isa($number_type) ) {
256             return
257 10         43 $self->violation(
258             $type_string . $elem->content() . $TYPE_NOT_ALLOWED_SUFFIX,
259             $EXPL,
260             $elem,
261             );
262             }
263             }
264              
265 125         558 return;
266             }
267              
268             sub _element_is_to_the_right_of_a_fat_comma {
269 276     276   671 my ($elem) = @_;
270              
271 276 100       1069 my $previous = $elem->sprevious_sibling() or return;
272              
273 213 100       8512 $previous->isa('PPI::Token::Operator') or return;
274              
275 204         677 return $previous->content() eq q[=>];
276             }
277              
278             sub _element_is_sole_component_of_a_subscript {
279 38     38   115 my ($elem) = @_;
280              
281 38         144 my $parent = $elem->parent();
282 38 100 66     431 if ( $parent and $parent->isa('PPI::Statement::Expression') ) {
283 13 100       47 if ( $parent->schildren() > 1 ) {
284 11         310 return 0;
285             }
286              
287 2         38 my $grandparent = $parent->parent();
288 2 50 33     23 if (
289             $grandparent
290             and $grandparent->isa('PPI::Structure::Subscript')
291             ) {
292 2         21 return 1;
293             }
294             }
295              
296 25         145 return 0;
297             }
298              
299             sub _element_is_in_an_include_readonly_or_version_statement {
300 271     271   714 my ($self, $elem) = @_;
301              
302 271         967 my $parent = $elem->parent();
303 271         1777 while ($parent) {
304 888 100       5217 if ( $parent->isa('PPI::Statement') ) {
305 492 100       1978 return 1 if $parent->isa('PPI::Statement::Include');
306              
307 470 100       1682 if ( $parent->isa('PPI::Statement::Variable') ) {
308 58 50       171 if ( $parent->type() eq 'our' ) {
309 58         2839 my @variables = $parent->variables();
310 58 100 66     3293 if (
311             scalar @variables == 1
312             and $variables[0] eq '$VERSION' ## no critic (RequireInterpolationOfMetachars)
313             ) {
314 57         299 return 1;
315             }
316             }
317              
318 1         5 return 0;
319             }
320              
321 412         1257 my $first_token = $parent->first_token();
322 412 100       7022 if ( $first_token->isa('PPI::Token::Word') ) {
    50          
323 48 100       163 if ( $self->{_constant_creator_subroutines}{
324             $first_token->content() } ) {
325 16         149 return 1;
326             }
327             } elsif ($parent->isa('PPI::Structure::Block')) {
328 0         0 return 0;
329             }
330             }
331              
332 792         2423 $parent = $parent->parent();
333             }
334              
335 175         1110 return 0;
336             }
337              
338             # Allow "plan tests => 39;".
339              
340             Readonly::Scalar my $PLAN_STATEMENT_MINIMUM_TOKENS => 4;
341              
342             sub _element_is_in_a_plan_statement {
343 176     176   535 my ($elem) = @_;
344              
345 176         543 my $parent = $elem->parent();
346 176 50       1034 return 0 if not $parent;
347              
348 176 50       693 return 0 if not $parent->isa('PPI::Statement');
349              
350 176         660 my @children = $parent->schildren();
351 176 100       4191 return 0 if @children < $PLAN_STATEMENT_MINIMUM_TOKENS;
352              
353 139 100       955 return 0 if not $children[0]->isa('PPI::Token::Word');
354 7 50       28 return 0 if $children[0]->content() ne 'plan';
355              
356 0 0       0 return 0 if not $children[1]->isa('PPI::Token::Word');
357 0 0       0 return 0 if $children[1]->content() ne 'tests';
358              
359 0 0       0 return 0 if not $children[2]->isa('PPI::Token::Operator');
360 0 0       0 return 0 if $children[2]->content() ne '=>';
361              
362 0         0 return 1;
363             }
364              
365             sub _element_is_in_a_constant_subroutine {
366 176     176   442 my ($elem) = @_;
367              
368 176         484 my $parent = $elem->parent();
369 176 50       1045 return 0 if not $parent;
370              
371 176 50       718 return 0 if not $parent->isa('PPI::Statement');
372              
373 176         631 my $following = $elem->snext_sibling();
374 176 100       5416 if ($following) {
375 148 100       801 return 0 if not $following->isa('PPI::Token::Structure');
376 68 50       219 return 0 if $following->content() ne $SCOLON;
377 68 50       573 return 0 if $following->snext_sibling();
378             }
379              
380 96         2151 my $preceding = $elem->sprevious_sibling();
381 96 100       2581 if ($preceding) {
382 92 100       639 return 0 if not $preceding->isa('PPI::Token::Word');
383 4 100       14 return 0 if $preceding->content() ne 'return';
384 2 50       15 return 0 if $preceding->sprevious_sibling();
385             }
386              
387 6 50       56 return 0 if $parent->snext_sibling();
388 6 100       135 return 0 if $parent->sprevious_sibling();
389              
390 5         104 my $grandparent = $parent->parent();
391 5 50       38 return 0 if not $grandparent;
392              
393 5 100       37 return 0 if not $grandparent->isa('PPI::Structure::Block');
394              
395 2         7 my $greatgrandparent = $grandparent->parent();
396 2 50       13 return 0 if not $greatgrandparent;
397 2 50       14 return 0 if not $greatgrandparent->isa('PPI::Statement::Sub');
398              
399 2         13 return 1;
400             }
401              
402             sub _element_is_a_package_statement_version_number {
403 174     174   476 my ($elem) = @_;
404              
405 174 50       605 my $parent = $elem->statement()
406             or return 0;
407              
408 174 100       3893 $parent->isa( 'PPI::Statement::Package' )
409             or return 0;
410              
411 4 50       13 my $version = $parent->schild( 2 )
412             or return 0;
413              
414 4         86 return $version == $elem;
415             }
416              
417             1;
418              
419             __END__
420              
421             #----------------------------------------------------------------------------
422              
423             =pod
424              
425             =for stopwords
426              
427             =head1 NAME
428              
429             Perl::Critic::Policy::ValuesAndExpressions::ProhibitMagicNumbers - Don't use values that don't explain themselves.
430              
431              
432             =head1 AFFILIATION
433              
434             This Policy is part of the core L<Perl::Critic|Perl::Critic>
435             distribution.
436              
437              
438             =head1 DESCRIPTION
439              
440             What is a "magic number"? A magic number is a number that appears in
441             code without any explanation; e.g. C<$bank_account_balance *=
442             57.492;>. You look at that number and have to wonder where that
443             number came from. Since you don't understand the significance of the
444             number, you don't understand the code.
445              
446             In general, numeric literals other than C<0> or C<1> in should not be used.
447             Use the L<constant|constant> pragma or the L<Readonly|Readonly> or
448             L<Const::Fast|Const::Fast> modules to give a descriptive name to the number.
449              
450             There are, of course, exceptions to when this rule should be applied.
451             One good example is positioning of objects in some container like
452             shapes on a blueprint or widgets in a user interface. In these cases,
453             the significance of a number can readily be determined by context.
454              
455             The maximum number of violations per document for this policy defaults
456             to 10.
457              
458              
459             =head2 Ways in which this module applies this rule.
460              
461             By default, this rule is relaxed in that C<2> is permitted to allow
462             for common things like alternation, the STDERR file handle, etc..
463              
464             Numeric literals are allowed in C<use> and C<require> statements to
465             allow for things like Perl version restrictions and
466             L<Test::More|Test::More> plans. Declarations of C<$VERSION> package
467             variables are permitted. Use of C<Readonly>, C<Readonly::Scalar>,
468             C<Readonly::Array>, and C<Readonly::Hash> from the
469             L<Readonly|Readonly> module are obviously valid, but use of
470             C<Readonly::Scalar1>, C<Readonly::Array1>, and C<Readonly::Hash1> are
471             specifically not supported.
472              
473             Use of binary, exponential, hexadecimal, octal, and version numbers,
474             even for C<0> and C<1>, outside of C<use>/C<require>/C<Readonly>
475             statements aren't permitted (but you can change this).
476              
477             There is a special exemption for accessing the last element of an
478             array, i.e. C<$x[-1]>.
479              
480              
481             $x = 0; # ok
482             $x = 0.0; # ok
483             $x = 1; # ok
484             $x = 1.0; # ok
485             $x = 1.5; # not ok
486             $x = 0b0 # not ok
487             $x = 0b1 # not ok
488             $x = 0x00 # not ok
489             $x = 0x01 # not ok
490             $x = 000 # not ok
491             $x = 001 # not ok
492             $x = 0e1 # not ok
493             $x = 1e1 # not ok
494              
495             $frobnication_factor = 42; # not ok
496             use constant FROBNICATION_FACTOR => 42; # ok
497              
498              
499             use 5.6.1; # ok
500             use Test::More plan => 57; # ok
501             plan tests => 39; # ok
502             our $VERSION = 0.22; # ok
503              
504              
505             $x = $y[-1] # ok
506             $x = $y[-2] # not ok
507              
508              
509              
510             foreach my $solid (1..5) { # not ok
511             ...
512             }
513              
514              
515             use Readonly;
516              
517             Readonly my $REGULAR_GEOMETRIC_SOLIDS => 5;
518              
519             foreach my $solid (1..$REGULAR_GEOMETRIC_SOLIDS) { #ok
520             ...
521             }
522              
523              
524             =head1 CONFIGURATION
525              
526             This policy has four options: C<allowed_values>, C<allowed_types>,
527             C<allow_to_the_right_of_a_fat_comma>, and C<constant_creator_subroutines>.
528              
529              
530             =head2 C<allowed_values>
531              
532             The C<allowed_values> parameter is a whitespace delimited set of
533             permitted number I<values>; this does not affect the permitted formats
534             for numbers. The defaults are equivalent to having the following in
535             your F<.perlcriticrc>:
536              
537             [ValuesAndExpressions::ProhibitMagicNumbers]
538             allowed_values = 0 1 2
539              
540             Note that this policy forces the values C<0> and C<1> into the
541             permitted values. Thus, specifying no values,
542              
543             allowed_values =
544              
545             is the same as simply listing C<0> and C<1>:
546              
547             allowed_values = 0 1
548              
549             The special C<all_integers> value, not surprisingly, allows all
550             integral values to pass, subject to the restrictions on number types.
551              
552             Ranges can be specified as two (possibly fractional) numbers separated
553             by two periods, optionally suffixed with an increment using the Perl 6
554             C<:by()> syntax. E.g.
555              
556             allowed_values = 7..10
557              
558             will allow 0, 1, 7, 8, 9, and 10 as literal values. Using fractional
559             values like so
560              
561             allowed_values = -3.5..-0.5:by(0.5)
562              
563             will permit -3.5, -3, -2.5, -2, -2.5, -1, -0.5, 0, and 1.
564             Unsurprisingly, the increment defaults to 1, which means that
565              
566             allowed_values = -3.5..-0.5
567              
568             will make -3.5, -2.5, -2.5, -0.5, 0, and 1 valid.
569              
570             Ranges are not lazy, i.e. you'd better have a lot of memory available
571             if you use a range of C<1..1000:by(0.01)>. Also remember that all of
572             this is done using floating-point math, which means that
573             C<1..10:by(0.3333)> is probably not going to be very useful.
574              
575             Specifying an upper limit that is less than the lower limit will
576             result in no values being produced by that range. Negative increments
577             are not permitted.
578              
579             Multiple ranges are permitted.
580              
581             To put this all together, the following is a valid, though not likely
582             to be used, F<.perlcriticrc> entry:
583              
584             [ValuesAndExpressions::ProhibitMagicNumbers]
585             allowed_values = 3.1415269 82..103 -507.4..57.8:by(0.2) all_integers
586              
587              
588             =head2 C<allowed_types>
589              
590             The C<allowed_types> parameter is a whitespace delimited set of
591             subclasses of L<PPI::Token::Number|PPI::Token::Number>.
592              
593             Decimal integers are always allowed. By default, floating-point
594             numbers are also allowed.
595              
596             For example, to allow hexadecimal literals, you could configure this
597             policy like
598              
599             [ValuesAndExpressions::ProhibitMagicNumbers]
600             allowed_types = Hex
601              
602             but without specifying anything for C<allowed_values>, the allowed
603             hexadecimal literals will be C<0x00>, C<0x01>, and C<0x02>. Note,
604             also, as soon as you specify a value for this parameter, you must
605             include C<Float> in the list to continue to be able to use floating
606             point literals. This effect can be used to restrict literals to only
607             decimal integers:
608              
609             [ValuesAndExpressions::ProhibitMagicNumbers]
610             allowed_types =
611              
612             If you permit exponential notation, you automatically also allow
613             floating point values because an exponential is a subclass of
614             floating-point in L<PPI|PPI>.
615              
616              
617             =head2 C<allow_to_the_right_of_a_fat_comma>
618              
619             If this is set, you can put any number to the right of a fat comma.
620              
621             my %hash = ( a => 4512, b => 293 ); # ok
622             my $hash_ref = { a => 4512, b => 293 }; # ok
623             some_subroutine( a => 4512, b => 293 ); # ok
624              
625             Currently, this only means I<directly> to the right of the fat comma. By
626             default, this value is I<true>.
627              
628              
629             =head2 C<constant_creator_subroutines>
630              
631             This parameter allows you to specify the names of subroutines that create
632             constants, in addition to C<Readonly>, C<Const::Fast>, and friends. For
633             example, if you use a custom C<Const::Fast>-like module that supports a
634             C<create_constant> subroutine to create constants, you could add something
635             like the following to your F<.perlcriticrc>:
636              
637             [ValuesAndExpressions::ProhibitMagicNumbers]
638             constant_creator_subroutines = create_constant
639              
640             If you have more than one name to add, separate them by whitespace.
641              
642             The subroutine name should appear exactly as it is in your code. For example,
643             if your code does not import the creating subroutine
644             subroutine, you would need to configure this policy as something like
645              
646             [ValuesAndExpressions::ProhibitMagicNumbers]
647             constant_creator_subroutines = create_constant Constant::Create::create_constant
648              
649              
650             =head1 BUGS
651              
652             There is currently no way to permit version numbers in regular code,
653             even if you include them in the C<allowed_types>. Some may actually
654             consider this a feature.
655              
656              
657             =head1 AUTHOR
658              
659             Elliot Shank C<< <perl@galumph.com> >>
660              
661              
662             =head1 COPYRIGHT
663              
664             Copyright (c) 2006-2011 Elliot Shank.
665              
666             This program is free software; you can redistribute it and/or modify
667             it under the same terms as Perl itself. The full text of this license
668             can be found in the LICENSE file included with this module.
669              
670             =cut
671              
672             # Local Variables:
673             # mode: cperl
674             # cperl-indent-level: 4
675             # fill-column: 78
676             # indent-tabs-mode: nil
677             # c-indentation-style: bsd
678             # End:
679             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :