File Coverage

blib/lib/Perl/Critic/Policy/BuiltinFunctions/ProhibitStringyEval.pm
Criterion Covered Total %
statement 32 73 43.8
branch 6 54 11.1
condition 1 3 33.3
subroutine 12 16 75.0
pod 4 5 80.0
total 55 151 36.4


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval;
2              
3 40     40   26541 use 5.010001;
  40         196  
4 40     40   332 use strict;
  40         149  
  40         905  
5 40     40   271 use warnings;
  40         136  
  40         1143  
6              
7 40     40   274 use Readonly;
  40         162  
  40         2296  
8              
9 40     40   364 use PPI::Document;
  40         103  
  40         1541  
10              
11 40     40   328 use Perl::Critic::Utils qw{ :booleans :severities :classification :ppi $SCOLON };
  40         141  
  40         2301  
12 40     40   16847 use parent 'Perl::Critic::Policy';
  40         150  
  40         324  
13              
14             our $VERSION = '1.150';
15              
16             #-----------------------------------------------------------------------------
17              
18             Readonly::Scalar my $DESC => q{Expression form of "eval"};
19             Readonly::Scalar my $EXPL => [ 161 ];
20              
21             #-----------------------------------------------------------------------------
22              
23             # The maximum number of statements that may appear in an import-only eval
24             # string:
25             Readonly::Scalar my $MAX_STATEMENTS => 3;
26              
27             #-----------------------------------------------------------------------------
28              
29             sub supported_parameters {
30             return (
31             {
32 90     90 0 2043 name => 'allow_includes',
33             description => q<Allow eval of "use" and "require" strings.>,
34             default_string => '0',
35             behavior => 'boolean',
36             },
37             );
38             }
39 82     82 1 372 sub default_severity { return $SEVERITY_HIGHEST }
40 92     92 1 375 sub default_themes { return qw( core pbp bugs certrule ) }
41 36     36 1 105 sub applies_to { return 'PPI::Token::Word' }
42              
43             #-----------------------------------------------------------------------------
44              
45             sub violates {
46 358     358 1 576 my ( $self, $elem, undef ) = @_;
47              
48 358 100       601 return if $elem->content() ne 'eval';
49 8 50       73 return if not is_function_call($elem);
50              
51 8         27 my $argument = first_arg($elem);
52 8 50       27 return if not $argument;
53 8 50       43 return if $argument->isa('PPI::Structure::Block');
54             return if
55 8 50 33     41 $self->{_allow_includes} and _string_eval_is_an_include($argument);
56              
57 8         40 return $self->violation( $DESC, $EXPL, $elem );
58             }
59              
60             sub _string_eval_is_an_include {
61 0     0     my ($eval_argument) = @_;
62              
63 0 0         return if not $eval_argument->isa('PPI::Token::Quote');
64              
65 0           my $string = $eval_argument->string();
66 0           my $document;
67              
68 0 0         eval { $document = PPI::Document->new(\$string); 1 }
  0            
  0            
69             or return;
70              
71 0           my @statements = $document->schildren;
72              
73 0 0         return if @statements > $MAX_STATEMENTS;
74              
75 0           my $structure = join q{,}, map { $_->class } @statements;
  0            
76              
77 0           my $package_class = qr{PPI::Statement::Package}xms;
78 0           my $include_class = qr{PPI::Statement::Include}xms;
79 0           my $statement_class = qr{PPI::Statement}xms;
80              
81 0 0         return if $structure !~ m{
82             ^
83             (?:$package_class,)? # Optional "package"
84             $include_class
85             (?:,$statement_class)? # Optional follow-on number
86             $
87             }xms;
88              
89 0 0         my $is_q = $eval_argument->isa('PPI::Token::Quote::Single')
90             or $eval_argument->isa('PPI::Token::Quote::Literal');
91              
92 0           for my $statement (@statements) {
93 0 0         if ( $statement->isa('PPI::Statement::Package') ) {
    0          
94 0 0         _string_eval_accept_package($statement) or return;
95             } elsif ( $statement->isa('PPI::Statement::Include') ) {
96 0 0         _string_eval_accept_include( $statement, $is_q ) or return;
97             } else {
98 0 0         _string_eval_accept_follow_on($statement) or return;
99             }
100             }
101              
102 0           return $TRUE;
103             }
104              
105             sub _string_eval_accept_package {
106 0     0     my ($package) = @_;
107              
108 0 0         return if not defined $package; # RT 60179
109 0 0         return if not $package->isa('PPI::Statement::Package');
110 0 0         return if not $package->file_scoped;
111              
112 0           return $TRUE;
113             }
114              
115             sub _string_eval_accept_include {
116 0     0     my ( $include, $is_single_quoted ) = @_;
117              
118 0 0         return if not defined $include; # RT 60179
119 0 0         return if not $include->isa('PPI::Statement::Include');
120 0 0         return if $include->type() eq 'no';
121              
122 0 0         if ($is_single_quoted) {
123             # Don't allow funky inclusion of arbitrary code (note we do allow
124             # interpolated values in interpolating strings because they can't
125             # entirely screw with the syntax).
126 0 0         return if $include->find('PPI::Token::Symbol');
127             }
128              
129 0           return $TRUE;
130             }
131              
132             sub _string_eval_accept_follow_on {
133 0     0     my ($follow_on) = @_;
134              
135 0 0         return if not $follow_on->isa('PPI::Statement');
136              
137 0           my @follow_on_components = $follow_on->schildren();
138              
139 0 0         return if @follow_on_components > 2;
140 0 0         return if not $follow_on_components[0]->isa('PPI::Token::Number');
141 0 0         return $TRUE if @follow_on_components == 1;
142              
143 0           return $follow_on_components[1]->content() eq $SCOLON;
144             }
145              
146             1;
147              
148             __END__
149              
150             #-----------------------------------------------------------------------------
151              
152             =pod
153              
154             =for stopwords SIGNES
155              
156             =head1 NAME
157              
158             Perl::Critic::Policy::BuiltinFunctions::ProhibitStringyEval - Write C<eval { my $foo; bar($foo) }> instead of C<eval "my $foo; bar($foo);">.
159              
160              
161             =head1 AFFILIATION
162              
163             This Policy is part of the core L<Perl::Critic|Perl::Critic>
164             distribution.
165              
166              
167             =head1 DESCRIPTION
168              
169             The string form of C<eval> is recompiled every time it is executed,
170             whereas the block form is only compiled once. Also, the string form
171             doesn't give compile-time warnings.
172              
173             eval "print $foo"; # not ok
174             eval {print $foo}; # ok
175              
176              
177             =head1 CONFIGURATION
178              
179             There is an C<allow_includes> boolean option for this Policy. If set, then
180             strings that look like they only include an optional "package" statement
181             followed by a single "use" or "require" statement (with the possible following
182             statement that consists of a single number) are allowed. With this option
183             set, the following are flagged as indicated:
184              
185             eval 'use Foo'; # ok
186             eval 'require Foo'; # ok
187             eval "use $thingy;"; # ok
188             eval "require $thingy;"; # ok
189             eval 'package Pkg; use Foo'; # ok
190             eval 'package Pkg; require Foo'; # ok
191             eval "package $pkg; use $thingy;"; # ok
192             eval "package $pkg; require $thingy;"; # ok
193             eval "use $thingy; 1;"; # ok
194             eval "require $thingy; 1;"; # ok
195             eval "package $pkg; use $thingy; 1;"; # ok
196             eval "package $pkg; require $thingy; 1;"; # ok
197              
198             eval 'use Foo; blah;'; # still not ok
199             eval 'require Foo; 2; 1;'; # still not ok
200             eval 'use $thingy;'; # still not ok
201             eval 'no Foo'; # still not ok
202              
203             If you don't understand why the number is allowed, see
204             L<Perl::Critic::Policy::ErrorHandling::RequireCheckingReturnValueOfEval|Perl::Critic::Policy::ErrorHandling::RequireCheckingReturnValueOfEval>.
205              
206             This option inspired by Ricardo SIGNES'
207             L<Perl::Critic::Policy::Lax::ProhibitStringyEval::ExceptForRequire|Perl::Critic::Policy::Lax::ProhibitStringyEval::ExceptForRequire>.
208              
209              
210             =head1 SEE ALSO
211              
212             L<Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrep|Perl::Critic::Policy::BuiltinFunctions::RequireBlockGrep>
213              
214             L<Perl::Critic::Policy::BuiltinFunctions::RequireBlockMap|Perl::Critic::Policy::BuiltinFunctions::RequireBlockMap>
215              
216              
217             =head1 AUTHOR
218              
219             Jeffrey Ryan Thalhammer <jeff@imaginative-software.com>
220              
221              
222             =head1 COPYRIGHT
223              
224             Copyright (c) 2005-2011 Imaginative Software Systems. All rights reserved.
225              
226             This program is free software; you can redistribute it and/or modify
227             it under the same terms as Perl itself. The full text of this license
228             can be found in the LICENSE file included with this module.
229              
230             =cut
231              
232             # Local Variables:
233             # mode: cperl
234             # cperl-indent-level: 4
235             # fill-column: 78
236             # indent-tabs-mode: nil
237             # c-indentation-style: bsd
238             # End:
239             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :