File Coverage

blib/lib/Perl/Critic/Policy/ErrorHandling/RequireCarping.pm
Criterion Covered Total %
statement 109 112 97.3
branch 56 64 87.5
condition 28 33 84.8
subroutine 24 24 100.0
pod 4 5 80.0
total 221 238 92.8


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