File Coverage

blib/lib/Perl/Critic/Policy/ErrorHandling/RequireCarping.pm
Criterion Covered Total %
statement 109 112 97.3
branch 61 70 87.1
condition 29 33 87.8
subroutine 21 21 100.0
pod 4 5 80.0
total 224 241 92.9


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::ErrorHandling::RequireCarping;
2              
3 40     40   31316 use 5.010001;
  40         183  
4 40     40   263 use strict;
  40         120  
  40         873  
5 40     40   206 use warnings;
  40         113  
  40         969  
6 40     40   260 use Readonly;
  40         107  
  40         2227  
7              
8 40         2240 use Perl::Critic::Utils qw{
9             :booleans :characters :severities :classification :data_conversion
10 40     40   292 };
  40         142  
11 40     40   23881 use Perl::Critic::Utils::PPI qw{ is_ppi_expression_or_generic_statement };
  40         122  
  40         2422  
12 40     40   3605 use parent 'Perl::Critic::Policy';
  40         127  
  40         254  
13              
14             our $VERSION = '1.146';
15              
16             #-----------------------------------------------------------------------------
17              
18             Readonly::Scalar my $EXPL => [ 283 ];
19              
20             #-----------------------------------------------------------------------------
21              
22             sub supported_parameters {
23             return (
24             {
25 119     119 0 2332 name => 'allow_messages_ending_with_newlines',
26             description => q{Don't complain about die or warn if the message ends in a newline.},
27             default_string => '1',
28             behavior => 'boolean',
29             },
30             {
31             name => 'allow_in_main_unless_in_subroutine',
32             description => q{Don't complain about die or warn in main::, unless in a subroutine.},
33             default_string => '0',
34             behavior => 'boolean',
35             },
36             );
37             }
38              
39 143     143 1 600 sub default_severity { return $SEVERITY_MEDIUM }
40 86     86 1 427 sub default_themes { return qw( core pbp maintenance certrule ) }
41 58     58 1 216 sub applies_to { return 'PPI::Token::Word' }
42              
43             #-----------------------------------------------------------------------------
44              
45             sub violates {
46 545     545 1 1087 my ( $self, $elem, undef ) = @_;
47              
48 545         828 my $alternative;
49 545 100       1203 if ( $elem eq 'warn' ) {
    100          
50 3         47 $alternative = 'carp';
51             }
52             elsif ( $elem eq 'die' ) {
53 123         2933 $alternative = 'croak';
54             }
55             else {
56 419         9128 return;
57             }
58              
59 126 50       402 return if ! is_function_call($elem);
60              
61 126 100       411 if ($self->{_allow_messages_ending_with_newlines}) {
62 125 100       282 return if _last_flattened_argument_list_element_ends_in_newline($elem);
63             }
64              
65             return if $self->{_allow_in_main_unless_in_subroutine}
66 71 100 100     242 && !$self->_is_element_contained_in_subroutine( $elem )
      66        
67             && $self->_is_element_in_namespace_main( $elem ); # RT #56619
68              
69 69         245 my $desc = qq{"$elem" used instead of "$alternative"};
70 69         500 return $self->violation( $desc, $EXPL, $elem );
71             }
72              
73             #-----------------------------------------------------------------------------
74              
75             sub _last_flattened_argument_list_element_ends_in_newline {
76 125     125   206 my $die_or_warn = shift;
77              
78 125 100       268 my $last_flattened_argument =
79             _find_last_flattened_argument_list_element($die_or_warn)
80             or return $FALSE;
81              
82 110 100       386 if ( $last_flattened_argument->isa('PPI::Token::Quote') ) {
    100          
83 94         321 my $last_flattened_argument_string =
84             $last_flattened_argument->string();
85 94 100 100     1424 if (
      100        
      100        
86             $last_flattened_argument_string =~ m{ \n \z }xms
87             or (
88             (
89             $last_flattened_argument->isa('PPI::Token::Quote::Double')
90             or $last_flattened_argument->isa('PPI::Token::Quote::Interpolate')
91             )
92             and $last_flattened_argument_string =~ m{ [\\] n \z }xms
93             )
94             ) {
95 53         292 return $TRUE;
96             }
97             }
98             elsif ( $last_flattened_argument->isa('PPI::Token::HereDoc') ) {
99 2         12 return $TRUE;
100             }
101              
102 55         171 return $FALSE
103             }
104              
105             #-----------------------------------------------------------------------------
106             # Here starts the fun. Explanation by example:
107             #
108             # Let's say we've got the following (contrived) statement:
109             #
110             # die q{Isn't }, ( $this, ( " fun?\n" ) , ) if "It isn't Monday.";
111             #
112             # This statement should pass because the last parameter that die is going to
113             # get is C<" fun?\n">.
114             #
115             # The approach is to first find the last non-flattened parameter. If this
116             # is a simple token, we're done. Else, it's some aggregate thing. We can't
117             # tell what C<some_function( "foo\n" )> is going to do, so we give up on
118             # anything other than a PPI::Structure::List.
119             #
120             # There are three possible scenarios for the children of a List:
121             #
122             # * No children of the List, i.e. the list looks like C< ( ) >.
123             # * One PPI::Statement::Expression element.
124             # * One PPI::Statement element. That's right, an instance of the base
125             # statement class and not some subclass. *sigh*
126             #
127             # In the first case, we're done. The latter two cases get treated
128             # identically. We get the last child of the Statement and start the search
129             # all over again.
130             #
131             # Back to our example. The PPI tree for this expression is
132             #
133             # PPI::Document
134             # PPI::Statement
135             # PPI::Token::Word 'die'
136             # PPI::Token::Quote::Literal 'q{Isn't }'
137             # PPI::Token::Operator ','
138             # PPI::Structure::List ( ... )
139             # PPI::Statement::Expression
140             # PPI::Token::Symbol '$this'
141             # PPI::Token::Operator ','
142             # PPI::Structure::List ( ... )
143             # PPI::Statement::Expression
144             # PPI::Token::Quote::Double '" fun?\n"'
145             # PPI::Token::Operator ','
146             # PPI::Token::Word 'if'
147             # PPI::Token::Quote::Double '"It isn't Monday.\n"'
148             # PPI::Token::Structure ';'
149             #
150             # We're starting with the Word containing 'die' (it could just as well be
151             # 'warn') because the earlier parts of validate() have taken care of any
152             # other possibility. We're going to scan forward through 'die's siblings
153             # until we reach what we think the end of its parameters are. So we get
154             #
155             # 1. A Literal. A perfectly good argument.
156             # 2. A comma operator. Looks like we've got more to go.
157             # 3. A List. Another argument.
158             # 4. The Word 'if'. Oops. That's a postfix operator.
159             #
160             # Thus, the last parameter is the List. So, we've got to scan backwards
161             # through the components of the List; again, the goal is to find the last
162             # value in the flattened list.
163             #
164             # Before decending into the List, we check that it isn't a subroutine call by
165             # looking at its prior sibling. In this case, the prior sibling is a comma
166             # operator, so it's fine.
167             #
168             # The List has one Expression element as we expect. We grab the Expression's
169             # last child and start all over again.
170             #
171             # 1. The last child is a comma operator, which Perl will ignore, so we
172             # skip it.
173             # 2. The comma's prior sibling is a List. This is the last significant
174             # part of the outer list.
175             # 3. The List's prior sibling isn't a Word, so we can continue because the
176             # List is not a parameter list.
177             # 4. We go through the child Expression and find that the last child of
178             # that is a PPI::Token::Quote::Double, which is a simple, non-compound
179             # token. We return that and we're done.
180              
181             sub _find_last_flattened_argument_list_element {
182 125     125   217 my $die_or_warn = shift;
183              
184             # Zoom forward...
185 125         254 my $current_candidate =
186             _find_last_element_in_subexpression($die_or_warn);
187              
188             # ... scan back.
189 125   100     578 while (
      66        
190             $current_candidate
191             and not _is_simple_list_element_token( $current_candidate )
192             and not _is_complex_expression_token( $current_candidate )
193             ) {
194 169 100       1136 if ( $current_candidate->isa('PPI::Structure::List') ) {
    100          
195 77         499 $current_candidate =
196             _determine_if_list_is_a_plain_list_and_get_last_child(
197             $current_candidate,
198             $die_or_warn
199             );
200             } elsif ( not $current_candidate->isa('PPI::Token') ) {
201 4         17 return;
202             } else {
203 88         255 $current_candidate = $current_candidate->sprevious_sibling();
204             }
205             }
206              
207 121 100       1243 return if not $current_candidate;
208 115 50       248 return if _is_complex_expression_token( $current_candidate );
209              
210 115         381 my $penultimate_element = $current_candidate->sprevious_sibling();
211 115 100       3039 if ($penultimate_element) {
212             # Bail if we've got a Word in front of the Element that isn't
213             # the original 'die' or 'warn' or anything else that isn't
214             # a comma or dot operator.
215 100 100       386 if ( $penultimate_element->isa('PPI::Token::Operator') ) {
    100          
216 52 50 66     171 if (
217             $penultimate_element ne $COMMA
218             and $penultimate_element ne $PERIOD
219             ) {
220 0         0 return;
221             }
222             } elsif ( $penultimate_element != $die_or_warn ) {
223             return
224 5         61 }
225             }
226              
227 110         1720 return $current_candidate;
228             }
229              
230             #-----------------------------------------------------------------------------
231             # This is the part where we scan forward from the 'die' or 'warn' to find
232             # the last argument.
233              
234             sub _find_last_element_in_subexpression {
235 125     125   203 my $die_or_warn = shift;
236              
237 125         182 my $last_following_sibling;
238 125         224 my $next_sibling = $die_or_warn;
239 125   100     298 while (
240             $next_sibling = $next_sibling->snext_sibling()
241             and not _is_postfix_operator( $next_sibling )
242             ) {
243 285         827 $last_following_sibling = $next_sibling;
244             }
245              
246 125         2079 return $last_following_sibling;
247             }
248              
249             #-----------------------------------------------------------------------------
250             # Ensure that the list isn't a parameter list. Find the last element of it.
251              
252             sub _determine_if_list_is_a_plain_list_and_get_last_child {
253 77     77   194 my ($list, $die_or_warn) = @_;
254              
255 77         212 my $prior_sibling = $list->sprevious_sibling();
256              
257 77 100       1921 if ( $prior_sibling ) {
258             # Bail if we've got a Word in front of the List that isn't
259             # the original 'die' or 'warn' or anything else that isn't
260             # a comma operator.
261 71 100       340 if ( $prior_sibling->isa('PPI::Token::Operator') ) {
    100          
262 24 50       63 if ( $prior_sibling ne $COMMA ) {
263 0         0 return;
264             }
265             } elsif ( $prior_sibling != $die_or_warn ) {
266             return
267 3         39 }
268             }
269              
270 74         854 my @list_children = $list->schildren();
271              
272             # If zero children, nothing to look for.
273             # If multiple children, then PPI is not giving us
274             # anything we understand.
275 74 100       870 return if scalar (@list_children) != 1;
276              
277 72         121 my $list_child = $list_children[0];
278              
279             # If the child isn't an Expression or it is some other subclass
280             # of Statement, we again don't understand PPI's output.
281 72 50       218 return if not is_ppi_expression_or_generic_statement($list_child);
282              
283 72         192 my @statement_children = $list_child->schildren();
284 72 50       901 return if scalar (@statement_children) < 1;
285              
286 72         332 return $statement_children[-1];
287             }
288              
289              
290             #-----------------------------------------------------------------------------
291             Readonly::Hash my %POSTFIX_OPERATORS =>
292             hashify qw{ if unless while until for foreach };
293              
294             sub _is_postfix_operator {
295 335     335   7605 my $element = shift;
296              
297 335 100 100     1129 if (
298             $element->isa('PPI::Token::Word')
299             and $POSTFIX_OPERATORS{$element}
300             ) {
301 50         900 return $TRUE;
302             }
303              
304 285         1480 return $FALSE;
305             }
306              
307              
308             Readonly::Array my @SIMPLE_LIST_ELEMENT_TOKEN_CLASSES =>
309             qw{
310             PPI::Token::Number
311             PPI::Token::Word
312             PPI::Token::DashedWord
313             PPI::Token::Symbol
314             PPI::Token::Quote
315             PPI::Token::HereDoc
316             };
317              
318             sub _is_simple_list_element_token {
319 284     284   3077 my $element = shift;
320              
321 284 100       784 return $FALSE if not $element->isa('PPI::Token');
322              
323 203         781 foreach my $class (@SIMPLE_LIST_ELEMENT_TOKEN_CLASSES) {
324 1086 100       11338 return $TRUE if $element->isa($class);
325             }
326              
327 88         1166 return $FALSE;
328             }
329              
330              
331             #-----------------------------------------------------------------------------
332             # Tokens that can't possibly be part of an expression simple
333             # enough for us to examine.
334              
335             Readonly::Array my @COMPLEX_EXPRESSION_TOKEN_CLASSES =>
336             qw{
337             PPI::Token::ArrayIndex
338             PPI::Token::QuoteLike
339             PPI::Token::Regexp
340             PPI::Token::Cast
341             PPI::Token::Label
342             PPI::Token::Separator
343             PPI::Token::Data
344             PPI::Token::End
345             PPI::Token::Prototype
346             PPI::Token::Attribute
347             PPI::Token::Unknown
348             };
349              
350             sub _is_complex_expression_token {
351 284     284   1129 my $element = shift;
352              
353 284 100       793 return $FALSE if not $element->isa('PPI::Token');
354              
355 203         478 foreach my $class (@COMPLEX_EXPRESSION_TOKEN_CLASSES) {
356 2233 50       23142 return $TRUE if $element->isa($class);
357             }
358              
359 203         2252 return $FALSE;
360             }
361              
362             #-----------------------------------------------------------------------------
363             # Check whether the given element is contained in a subroutine.
364              
365             sub _is_element_contained_in_subroutine {
366 4     4   12 my ( $self, $elem ) = @_;
367              
368 4         9 my $parent = $elem;
369 4         14 while ( $parent = $parent->parent() ) {
370 9 100       82 $parent->isa( 'PPI::Statement::Sub' ) and return $TRUE;
371 8 100       38 $parent->isa( 'PPI::Structure::Block' ) or next;
372 2 50       9 my $prior_elem = $parent->sprevious_sibling() or next;
373 2 100 66     74 $prior_elem->isa( 'PPI::Token::Word' )
374             and 'sub' eq $prior_elem->content()
375             and return $TRUE;
376             }
377              
378 2         19 return $FALSE;
379             }
380              
381             #-----------------------------------------------------------------------------
382             # Check whether the given element is in main::
383              
384             sub _is_element_in_namespace_main {
385 2     2   7 my ( $self, $elem ) = @_;
386 2         5 my $current_elem = $elem;
387 2         6 my $prior_elem;
388              
389 2         9 while ( $current_elem ) {
390 5         72 while ( $prior_elem = $current_elem->sprevious_sibling() ) {
391 1 50       31 if ( $prior_elem->isa( 'PPI::Statement::Package' ) ) {
392 1         5 return 'main' eq $prior_elem->namespace();
393             }
394             } continue {
395 0         0 $current_elem = $prior_elem;
396             }
397 4         71 $current_elem = $current_elem->parent();
398             }
399              
400 1         14 return $TRUE;
401             }
402              
403             1;
404              
405             __END__
406              
407             #-----------------------------------------------------------------------------
408              
409             =pod
410              
411             =head1 NAME
412              
413             Perl::Critic::Policy::ErrorHandling::RequireCarping - Use functions from L<Carp|Carp> instead of C<warn> or C<die>.
414              
415             =head1 AFFILIATION
416              
417             This Policy is part of the core L<Perl::Critic|Perl::Critic>
418             distribution.
419              
420              
421             =head1 DESCRIPTION
422              
423             The C<die> and C<warn> functions both report the file and line number
424             where the exception occurred. But if someone else is using your
425             subroutine, they usually don't care where B<your> code blew up.
426             Instead, they want to know where B<their> code invoked the subroutine.
427             The L<Carp|Carp> module provides alternative methods that report the
428             exception from the caller's file and line number.
429              
430             By default, this policy will not complain about C<die> or C<warn>, if
431             it can determine that the message will always result in a terminal
432             newline. Since perl suppresses file names and line numbers in this
433             situation, it is assumed that no stack traces are desired either and
434             none of the L<Carp|Carp> functions are necessary.
435              
436             die "oops" if $explosion; #not ok
437             warn "Where? Where?!" if $tiger; #not ok
438              
439             open my $mouth, '<', 'food'
440             or die 'of starvation'; #not ok
441              
442             if (! $dentist_appointment) {
443             warn "You have bad breath!\n"; #ok
444             }
445              
446             die "$clock not set.\n" if $no_time; #ok
447              
448             my $message = "$clock not set.\n";
449             die $message if $no_time; #not ok, not obvious
450              
451              
452             =head1 CONFIGURATION
453              
454             By default, this policy allows uses of C<die> and C<warn> ending in an
455             explicit newline. If you give this policy an
456             C<allow_messages_ending_with_newlines> option in your F<.perlcriticrc>
457             with a false value, then this policy will prohibit such uses.
458              
459             [ErrorHandling::RequireCarping]
460             allow_messages_ending_with_newlines = 0
461              
462             If you give this policy an C<allow_in_main_unless_in_subroutine> option
463             in your F<.perlcriticrc> with a true value, then this policy will allow
464             C<die> and C<warn> in name space main:: unless they appear in a
465             subroutine, even if they do not end in an explicit newline.
466              
467             [ErrorHandling::RequireCarping]
468             allow_in_main_unless_in_subroutine = 1
469              
470             =head1 BUGS
471              
472             Should allow C<die> when it is obvious that the "message" is a reference.
473              
474              
475             =head1 SEE ALSO
476              
477             L<Carp::Always|Carp::Always>
478              
479              
480             =head1 AUTHOR
481              
482             Jeffrey Ryan Thalhammer <jeff@imaginative-software.com>
483              
484              
485             =head1 COPYRIGHT
486              
487             Copyright (c) 2005-2011 Imaginative Software Systems. All rights reserved.
488              
489             This program is free software; you can redistribute it and/or modify
490             it under the same terms as Perl itself. The full text of this license
491             can be found in the LICENSE file included with this module.
492              
493             =cut
494              
495             # Local Variables:
496             # mode: cperl
497             # cperl-indent-level: 4
498             # fill-column: 78
499             # indent-tabs-mode: nil
500             # c-indentation-style: bsd
501             # End:
502             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :