File Coverage

blib/lib/Perl/Critic/Policy/BuiltinFunctions/ProhibitShiftRef.pm
Criterion Covered Total %
statement 38 38 100.0
branch 9 10 90.0
condition 8 12 66.6
subroutine 13 13 100.0
pod 5 6 83.3
total 73 79 92.4


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::BuiltinFunctions::ProhibitShiftRef;
2              
3 40     40   27219 use 5.010001;
  40         190  
4 40     40   264 use strict;
  40         127  
  40         845  
5 40     40   225 use warnings;
  40         126  
  40         1061  
6 40     40   272 use Readonly;
  40         98  
  40         2099  
7 40     40   277 use version 0.77 ();
  40         602  
  40         1091  
8              
9 40     40   283 use Perl::Critic::Utils qw{ :severities :classification :language };
  40         122  
  40         2185  
10 40     40   15309 use parent 'Perl::Critic::Policy';
  40         132  
  40         318  
11              
12             our $VERSION = '1.146';
13              
14             #-----------------------------------------------------------------------------
15              
16             Readonly::Scalar my $DESC => q{\shift used};
17             Readonly::Scalar my $EXPL => [165];
18              
19             Readonly::Scalar my $MINIMUM_PERL_VERSION => version->new(5.008008);
20              
21             #-----------------------------------------------------------------------------
22              
23 94     94 0 1724 sub supported_parameters { return () }
24 84     84 1 402 sub default_severity { return $SEVERITY_MEDIUM }
25 74     74 1 353 sub default_themes { return qw( core bugs tests ) }
26 35     35 1 127 sub applies_to { return 'PPI::Token::Word' }
27              
28             #-----------------------------------------------------------------------------
29              
30             sub prepare_to_scan_document {
31 35     35 1 136 my ( $self, $document ) = @_;
32              
33             # The earliest version tested was 5.8.8
34 35         122 my $version = $document->highest_explicit_perl_version();
35 35   33     267 return !$version || $version >= $MINIMUM_PERL_VERSION;
36             }
37              
38             #-----------------------------------------------------------------------------
39              
40             sub violates {
41 377     377 1 721 my ( $self, $elem, undef ) = @_;
42              
43 377 100       723 return if $elem->content() ne 'shift';
44              
45 26         132 my $prev = $elem->sprevious_sibling();
46 26 100       633 if ( !$prev ) {
47              
48             # If there is no previous token, we are probably nested in a block.
49             # Grab the statement and see if it's in a block. For simplicity, we
50             # assume the block only contains a 'shift' statement, which may not be
51             # reliable.
52 11 50       33 if ( my $stmt = $elem->statement ) {
53              
54 11         180 my $block = $stmt->parent();
55 11 100 66     78 if ( $block && $block->isa('PPI::Structure::Block') ) {
56 3         15 $prev = $block->sprevious_sibling();
57             }
58             }
59             }
60              
61 26 100 100     244 if ( $prev && $prev->isa('PPI::Token::Cast') && $prev->content() eq q{\\} ) {
      66        
62 10         75 return $self->violation( $DESC, $EXPL, $elem );
63             }
64              
65 16         50 return;
66             }
67              
68             1;
69              
70             #-----------------------------------------------------------------------------
71              
72             __END__
73              
74             =pod
75              
76             =encoding utf8
77              
78             =head1 NAME
79              
80             Perl::Critic::Policy::BuiltinFunctions::ProhibitShiftRef - Prohibit C<\shift> in code
81              
82              
83             =head1 AFFILIATION
84              
85             This Policy is part of the core L<Perl::Critic|Perl::Critic>
86             distribution.
87              
88              
89             =head1 DESCRIPTION
90              
91             Prohibit the use of C<\shift>, as it is associated with bugs in Perl and its
92             modules.
93              
94             =head2 Background
95              
96             Often, C<\shift> is used to create references that act much like an alias. By
97             creating an "alias" that is named, the code becomes more readable. For example,
98              
99             sub routine {
100             my $longstring = \shift;
101             print $$longstring;
102             }
103              
104             is more readable than
105              
106             sub routine {
107             print $_[0]; # longstring
108             }
109              
110             Unfortunately, this added readability brings with it new and exciting issues,
111             detailed in the next section.
112              
113             =head2 Problems with C<\shift>
114              
115             By avoiding C<\shift>, several issues in Perl can be averted, including:
116              
117             =over
118              
119             =item Memory leak since Perl 5.22
120              
121             Issue #126676 was introduced in Perl 5.21.4 and is triggered when C<\shift> is
122             used. The bug has not been resolved as of Perl 5.28.
123              
124             In short, the bug causes the ref counter for the aliased variable to be
125             incremented when running the subroutine, but it is not subsequently decremented
126             after the subroutine returns. In addition to leaking memory, this issue can
127             also delay the cleanup of objects until Global Destruction, which can cause
128             further issues.
129              
130             For more information, see L<https://rt.perl.org/Public/Bug/Display.html?id=126676>.
131              
132             =item Devel::Cover crashes
133              
134             A separate, longstanding issue in Devel::Cover (since at least 1.21), causes
135             test code to segfault occasionally. This prevents the coverage data from being
136             written out, resulting in bad metrics.
137              
138             The bug itself isn't actually caused by C<\shift>, instead it shows up in code
139             like the following:
140              
141             sub myopen {
142             open ${ \$_[0] }, ">test";
143             }
144              
145             However, this code would rarely be seen in production. It would more likely
146             manifest with C<\shift>, as it does below:
147              
148             sub myopen {
149             my $fh = \shift;
150             open $$fh, ">test";
151             }
152              
153             So while C<\shift> isn't the cause, it's often associated with the problem.
154              
155             For more information, see L<https://github.com/pjcj/Devel--Cover/issues/125>.
156              
157             =back
158              
159             =head1 CONFIGURATION
160              
161             This Policy is not configurable except for the standard options.
162              
163              
164             =head1 SEE ALSO
165              
166             L<https://rt.perl.org/Public/Bug/Display.html?id=126676>
167              
168             L<https://github.com/pjcj/Devel--Cover/issues/125>
169              
170              
171             =head1 AUTHOR
172              
173             =for stopwords Lindee
174              
175             Chris Lindee <chris.lindee@cpanel.net>
176              
177              
178             =head1 COPYRIGHT
179              
180             =for stopwords cPanel
181              
182             Copyright (c) 2018 cPanel, L.L.C.
183              
184             All rights reserved.
185              
186             This program is free software; you can redistribute it and/or modify
187             it under the same terms as Perl itself.
188              
189             =cut