File Coverage

blib/lib/Perl/Critic/Policy/Community/OverloadOptions.pm
Criterion Covered Total %
statement 41 42 97.6
branch 17 18 94.4
condition 18 22 81.8
subroutine 10 11 90.9
pod 4 5 80.0
total 90 98 91.8


line stmt bran cond sub pod time code
1              
2             use strict;
3 1     1   394 use warnings;
  1         2  
  1         25  
4 1     1   4  
  1         2  
  1         27  
5             use Perl::Critic::Utils qw(:severities :classification :ppi);
6 1     1   6 use parent 'Perl::Critic::Policy';
  1         2  
  1         40  
7 1     1   307  
  1         1  
  1         5  
8             our $VERSION = 'v1.0.3';
9              
10             use constant DESC => 'Using overload.pm without a boolean overload or fallback';
11 1     1   65 use constant EXPL => 'When using overload.pm to define overloads for an object class, always define an overload on "bool" explicitly and set the fallback option. This prevents objects from autogenerating a potentially surprising boolean overload, and causes operators for which overloads can\'t be autogenerated to act on the object as they normally would.';
  1         2  
  1         54  
12 1     1   5  
  1         2  
  1         325  
13              
14 6     6 0 19586 my ($self, $elem) = @_;
15 8     8 1 71 return () unless ($elem->type // '') eq 'use' and ($elem->module // '') eq 'overload';
16 0     0 1 0 my @args = $elem->arguments;
17 6     6 1 68450 my ($has_bool, $has_fallback);
18             my @options;
19             while (@args) {
20 13     13 1 1110 my $arg = shift @args;
21 13 50 50     37 # use overload qw(...);
      50        
      33        
22 13         561 if ($arg->isa('PPI::Token::QuoteLike::Words')) {
23 13         466 push @options, $arg->literal;
24 13         0 # use overload 'foo', 1;
25 13         26 } elsif ($arg->isa('PPI::Token::Quote')) {
26 90         444 push @options, $arg->string;
27             # use overload foo => 1;
28 90 100 100     529 } elsif ($arg->isa('PPI::Token::Word') or $arg->isa('PPI::Token::Number')) {
    100 100        
    100          
    100          
29 3         13 push @options, $arg->literal;
30             # unpack lists and expressions
31             } elsif ($arg->isa('PPI::Structure::List') or $arg->isa('PPI::Statement::Expression')) {
32 11         49 unshift @args, $arg->schildren;
33             }
34             }
35 24         63 # use overload; or use overload ();
36             return () unless @options;
37             foreach my $i (0..$#options) {
38 11         150 my $item = $options[$i];
39             if ($item eq 'fallback' and defined $options[$i+1] and $options[$i+1] ne 'undef') {
40             $has_fallback = 1;
41             } elsif ($item eq 'bool') {
42 13 100       188 $has_bool = 1;
43 10         24 }
44 39         56 }
45 39 100 100     114 return $self->violation(DESC, EXPL, $elem) unless $has_bool and $has_fallback;
    100 100        
46 4         6 return ();
47             }
48 6         11  
49             1;
50              
51 10 100 100     50 =head1 NAME
52 2         7  
53             Perl::Critic::Policy::Community::OverloadOptions - Don't use overload without
54             specifying a bool overload and enabling fallback
55              
56             =head1 DESCRIPTION
57              
58             The L<overload> module allows an object class to specify behavior for an object
59             used in various operations. However, when activated it enables additional
60             behavior by default: it L<autogenerates|overload/"Magic Autogeneration">
61             overload behavior for operators that are not specified, and if it cannot
62             autogenerate an overload for an operator, using that operator on the object
63             will throw an exception.
64              
65             An autogenerated boolean overload can lead to surprising behavior where an
66             object is considered "false" because of another overloaded value. For example,
67             if a class overloads stringification to return the object's name, but the
68             object's name is C<0>, then the object will be considered false due to an
69             autogenerated overload using the boolean value of the string. This is rarely
70             desired behavior, and if needed, it can be set as an explicit boolean overload.
71              
72             Without setting the C<fallback> option, any operators that cannot be
73             autogenerated from defined overloads will result in an exception when used.
74             By setting C<fallback> to C<1>, the operator will instead fall back to standard
75             behavior as if no overload was defined, which is generally the expected
76             behavior when only overloading a few operations.
77              
78             use overload '""' => sub { $_[0]->name }; # not ok
79             use overload '""' => sub { $_[0]->name }, bool => sub { 1 }; # not ok
80             use overload '""' => sub { $_[0]->name }, fallback => 1; # not ok
81             use overload '""' => sub { $_[0]->name }, bool => sub { 1 }, fallback => 1; # ok
82              
83             =head1 AFFILIATION
84              
85             This policy is part of L<Perl::Critic::Community>.
86              
87             =head1 CONFIGURATION
88              
89             This policy is not configurable except for the standard options.
90              
91             =head1 AUTHOR
92              
93             Dan Book, C<dbook@cpan.org>
94              
95             =head1 COPYRIGHT AND LICENSE
96              
97             Copyright 2015, Dan Book.
98              
99             This library is free software; you may redistribute it and/or modify it under
100             the terms of the Artistic License version 2.0.
101              
102             =head1 SEE ALSO
103              
104             L<Perl::Critic>