File Coverage

blib/lib/Perl/Critic/Policy/CodeLayout/RequireParensWithBuiltins.pm
Criterion Covered Total %
statement 36 37 97.3
branch 14 14 100.0
condition 14 15 93.3
subroutine 10 11 90.9
pod 4 5 80.0
total 78 82 95.1


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::CodeLayout::RequireParensWithBuiltins;
2              
3 5     5   3675 use 5.010001;
  5         20  
4 5     5   24 use strict;
  5         9  
  5         112  
5 5     5   18 use warnings;
  5         8  
  5         270  
6 5     5   26 use Readonly;
  5         7  
  5         324  
7              
8 5     5   26 use Perl::Critic::Utils qw/ :severities :data_conversion :classification :language /;
  5         8  
  5         275  
9 5     5   1905 use base 'Perl::Critic::Policy';
  5         10  
  5         3309  
10              
11             our $VERSION = '0.0.7';
12              
13             Readonly::Scalar my $DESC => q{Builtin function called without parentheses};
14             Readonly::Scalar my $EXPL => [ 13 ];
15              
16             # In each section, the order follows that of perlfunc(1).
17             # Some keywords may be repeated if they appear in multiple perlfunc sections.
18              
19             Readonly::Array my @REQUIRED => qw/
20             chr crypt fc hex index lc lcfirst length oct ord pack rindex sprintf substr uc ucfirst
21             quotemeta split study
22             abs atan2 cos exp hex int log oct rand sin sqrt srand
23             splice
24             join unpack
25             delete exists
26             binmode close closedir fileno flock read readdir readline rewinddir seek seekdir select syscall sysread sysseek syswrite tell telldir truncate warn write
27             pack read syscall sysread sysseek syswrite unpack vec
28             chdir chmod chown chroot fcntl glob ioctl link lstat mkdir open opendir readlink rename rmdir select stat symlink sysopen umask unlink utime
29             caller
30             formline lock scalar
31             alarm exec getpriority kill pipe readpipe setpgrp setpriority sleep system waitpid
32             bless ref tie tied untie
33             accept bind connect getpeername getsockname getsockopt listen recv send setsockopt shutdown socket socketpair
34             /;
35              
36             Readonly::Array my @PERMITTED => qw/
37             chomp chop
38             pos
39             eof getc
40             exit
41             defined reset undef
42             getpgrp
43             gmtime localtime time
44             /;
45              
46             Readonly::Array my @ALLOWED => qw/
47             reverse
48             each keys pop push shift unshift values
49             each keys values
50             grep map reverse sort
51             die format print printf say
52             break continue die do dump eval evalbytes goto last next redo return wantarray
53             import local my our package state use
54             fork getppid times wait
55             do import no package require use
56             package use
57             /;
58              
59             ####-----------------------------------------------------------------------------
60              
61             sub supported_parameters {
62             return (
63             {
64 4     4 0 1799173 name => 'require',
65             description => 'Always require parentheses of these operators.',
66             default_string => join(' ',@REQUIRED),
67             behavior => 'string list',
68             },
69             {
70             name => 'permit',
71             description => 'Require parentheses when called with a parameter.',
72             default_string => join(' ',@PERMITTED),
73             behavior => 'string list',
74             },
75             {
76             name => 'allow',
77             description => 'Never require parentheses.',
78             default_string => join(' ', @ALLOWED),
79             behavior => 'string list',
80             },
81             );
82             }
83              
84 20     20 1 317 sub default_severity { return $SEVERITY_HIGH }
85 0     0 1 0 sub default_themes { return qw( core cosmetic ) }
86 53     53 1 316645 sub applies_to { return 'PPI::Token::Word' }
87              
88             #-----------------------------------------------------------------------------
89              
90             sub violates {
91 122     122 1 2386 my ($self,$elem,undef)=@_;
92 122 100       414 if(!is_function_call($elem)) { return }
  22         2701  
93 100 100       26819 if(exists($$self{_allow}{ $elem->content() })) { return }
  49         342  
94              
95 51         328 my $sibling=$elem->snext_sibling();
96 51 100       1100 if(exists($$self{_require}{ $elem->content() })) {
97 24 100 100     174 if(!$sibling||!$sibling->isa('PPI::Structure::List')) { return $self->violation(sprintf("$DESC (%s)",$elem->content()),$EXPL,$elem) }
  12         32  
98             }
99              
100 39 100 100     407 if(!$sibling||$sibling->isa('PPI::Structure::List')) { return }
  19         138  
101              
102 20 100       71 if(exists($$self{_permit}{ $elem->content() })) {
103 14 100 100     236 if( $sibling->isa('PPI::Token::Number')
      66        
      100        
104             || $sibling->isa('PPI::Token::Quote')
105             || $sibling->isa('PPI::Token::QuoteLike')
106             || $sibling->isa('PPI::Token::Symbol')
107             ) {
108 8         30 return $self->violation(sprintf("$DESC (%s)",$elem->content()),$EXPL,$elem);
109             }
110 6         22 return;
111             }
112              
113 6         47 return;
114             }
115              
116             #-----------------------------------------------------------------------------
117              
118             1;
119              
120             __END__
121              
122             =pod
123              
124             =head1 NAME
125              
126             Perl::Critic::Policy::CodeLayout::RequireParensWithBuiltins - Write C<lc($x // "Default")> instead of C<lc $x // "Default">.
127              
128             =head1 DESCRIPTION
129              
130             String folding is often used in map lookups where missing parentheses may not provide the expected behavior
131              
132             $LOOKUP{ lc $name // 'Default' }
133             $LOOKUP{ lc( $name // 'Default' ) }
134              
135             When C<$name> is undefined, the first form will lookup the value for C<""> (the empty string) and throw warnings from the C<lc> call. The second form will lookup the value for C<"default">. As an alternative approach
136              
137             $LOOKUP{ lc($name) || 'Default' }
138              
139             will lookup the value for C<"default"> when C<$name> is undefined, but will still throw warnings from C<lc>.
140              
141             =head1 CONFIGURATION
142              
143             The priority for configuration is Allow, Required, Permitted.
144              
145             =head2 Allow
146              
147             Functions in the C<allow> section can be called with or without parentheses, no restriction. This overrides all other configurations.
148              
149             [CodeLayout::RequireParensWithBuiltins]
150             allow = sqrt
151              
152             =head2 Required
153              
154             Names configured in the C<require> section always require parentheses, even when called without arguments or inside blocks. EG C<lc()> or C<grep {lc($_)}>. This overrides the C<permit> option.
155              
156             [CodeLayout::RequireParensWithBuiltins]
157             require = lc lcfirst uc ucfirst
158              
159             =head2 Required with arguments
160              
161             Some functions operate on C<$_> or other defaults and may be used without parameters. If configured in the C<permit> section, the functions will require parentheses when called with a parameter. EG both C<grep {defined} ...> and C<if(defined($x))> are valid, but C<if(defined $x)> is a violation.
162              
163             [CodeLayout::RequireParensWithBuiltins]
164             permit = defined
165              
166             =head1 NOTES
167              
168             While coding with parentheses can sometimes lead to verbose constructs, a single case without parentheses can lead to invalid data in processing and results. For these functions, the lack of parentheses causes ambiguity so they can be considered F<necessary>. Code maintainability must also support quick insert of defaults and handling of warnings for undefined values, so calls without those mechanisms are likely incorrect F<from the start>.
169              
170             =head1 BUGS
171              
172             It's possible that some mathematical functions are more natural without parentheses even when followed by lower-precedence operators. The current policy makes no special exemptions for different precedence interpretations for different functions.
173              
174             =cut