File Coverage

blib/lib/Perl/Critic/Policy/ValuesAndExpressions/UnexpandedSpecialLiteral.pm
Criterion Covered Total %
statement 51 52 98.0
branch 13 14 92.8
condition 10 12 83.3
subroutine 13 13 100.0
pod 1 3 33.3
total 88 94 93.6


line stmt bran cond sub pod time code
1             # Copyright 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Kevin Ryde
2              
3             # This file is part of Perl-Critic-Pulp.
4              
5             # Perl-Critic-Pulp is free software; you can redistribute it and/or modify
6             # it under the terms of the GNU General Public License as published by the
7             # Free Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Perl-Critic-Pulp is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Perl-Critic-Pulp. If not, see <http://www.gnu.org/licenses/>.
17              
18              
19             # Change "12 Jul 2013 23:37:26 -0700" making __PACKAGE__ etc quoted by =>
20             # across newline.
21             #
22             # http://perl5.git.perl.org/perl.git/commit/21791330af556dc082f3ef837d772ba9a4d0b197
23             # http://perl5.git.perl.org/perl.git/patch/21791330af556dc082f3ef837d772ba9a4d0b197
24              
25              
26             package Perl::Critic::Policy::ValuesAndExpressions::UnexpandedSpecialLiteral;
27 40     40   25265 use 5.006;
  40         129  
28 40     40   180 use strict;
  40         71  
  40         664  
29 40     40   152 use warnings;
  40         69  
  40         888  
30 40     40   194 use List::Util qw(min max);
  40         72  
  40         2177  
31              
32 40     40   212 use base 'Perl::Critic::Policy';
  40         75  
  40         3938  
33 40         2482 use Perl::Critic::Utils qw(is_perl_builtin
34             is_perl_builtin_with_no_arguments
35 40     40   145762 precedence_of);
  40         74  
36              
37             our $VERSION = 97;
38              
39 40     40   242 use constant supported_parameters => ();
  40         71  
  40         2219  
40 40     40   213 use constant default_severity => $Perl::Critic::Utils::SEVERITY_MEDIUM;
  40         73  
  40         2104  
41 40     40   209 use constant default_themes => qw(pulp bugs);
  40         80  
  40         2011  
42 40     40   286 use constant applies_to => ('PPI::Token::Word');
  40         93  
  40         13839  
43              
44             my %specials = ('__FILE__' => 1,
45             '__LINE__' => 1,
46             '__PACKAGE__' => 1);
47              
48             sub violates {
49 34     34 1 587651 my ($self, $elem, $document) = @_;
50 34 100       97 $specials{$elem} or return;
51              
52 24 100       126 if (elem_is_quoted_by_big_comma ($elem)) {
53 11         72 return $self->violation
54             ("$elem is the literal string '$elem' on the left of a =>",
55             '', $elem);
56             }
57 13 100       219 if (elem_is_solo_subscript ($elem)) {
58 5         17 return $self->violation
59             ("$elem is the literal string '$elem' in a hash subscript",
60             '', $elem);
61             }
62 8         25 return;
63             }
64              
65             # Perl::Critic::Utils::is_hash_key() does a similar thing to the following
66             # tests, identifying something on the left of "=>", or in a "{}" subscript.
67             # But here want those two cases separately since the subscript is only a
68             # violation if $elem also has no siblings. (Separate cases allow a custom
69             # error message too.)
70             #
71             # { __FILE__ => 123 }
72             # ( __FILE__ => 123 )
73             #
74             sub elem_is_quoted_by_big_comma {
75 24     24 0 47 my ($elem) = @_;
76              
77 24         39 my $next = $elem;
78 24         35 for (;;) {
79 35   100     89 $next = $next->next_sibling
80             || return 0; # nothing following
81 27 100 100     569 if ($next->isa('PPI::Token::Whitespace')
82             && $next->content !~ /\n/) {
83 11         69 next;
84             }
85 16   100     69 return ($next->isa('PPI::Token::Operator') && $next->content eq '=>');
86             }
87             }
88              
89             # $hash{__FILE__}
90             #
91             # PPI::Structure::Subscript { ... }
92             # PPI::Statement::Expression
93             # PPI::Token::Word '__PACKAGE__'
94             #
95             # and not multi subscript like $hash{__FILE__,123}
96             #
97             # PPI::Structure::Subscript { ... }
98             # PPI::Statement::Expression
99             # PPI::Token::Word '__PACKAGE__'
100             # PPI::Token::Operator ','
101             # PPI::Token::Number '123'
102             #
103             sub elem_is_solo_subscript {
104 13     13 0 30 my ($elem) = @_;
105              
106             # must be sole elem
107 13 100       38 if ($elem->snext_sibling) { return 0; }
  5         97  
108 8 50       147 if ($elem->sprevious_sibling) { return 0; }
  0         0  
109              
110 8   50     139 my $parent = $elem->parent || return 0;
111 8 100       63 $parent->isa('PPI::Statement::Expression') || return 0;
112              
113 6   50     19 my $grandparent = $parent->parent || return 0;
114 6         39 return $grandparent->isa('PPI::Structure::Subscript');
115             }
116              
117             1;
118             __END__
119              
120             =for stopwords filename parens Subhash Concated HashRef OOP Ryde bareword Unexpanded
121              
122             =head1 NAME
123              
124             Perl::Critic::Policy::ValuesAndExpressions::UnexpandedSpecialLiteral - specials like __PACKAGE__ used literally
125              
126             =head1 DESCRIPTION
127              
128             This policy is part of the L<C<Perl::Critic::Pulp>|Perl::Critic::Pulp>
129             add-on. It picks up some cases where the special literals C<__FILE__>,
130             C<__LINE__> and C<__PACKAGE__> (see L<perldata/Special Literals>) are used
131             with C<< => >> or as a hash subscript and so don't expand to the respective
132             filename, line number or package name.
133              
134             my $seen = { __FILE__ => 1 }; # bad
135             return ('At:'.__LINE__ => 123); # bad
136             $obj->{__PACKAGE__}->{myextra} = 123; # bad
137              
138             In each case you get a string C<"__FILE__">, C<"__LINE__"> or
139             C<"__PACKAGE__">, as if
140              
141             my $seen = { '__FILE__' => 1 };
142             return ('At:__LINE__' => 123);
143             $obj->{'__PACKAGE__'}->{'myextra'} = 123;
144              
145             where almost certainly it was meant to expand to the filename etc. On that
146             basis this policy is under the "bugs" theme (see L<Perl::Critic/POLICY
147             THEMES>).
148              
149             Expression forms like
150              
151             'MyExtra::'.__PACKAGE__ => 123 # bad
152              
153             are still bad because the word immediately to the left of a C<< => >> is
154             quoted even when that word is part of an expression.
155              
156             If you really do want a string C<"__FILE__"> etc then the suggestion is to
157             write the quotes, even if you're not in the habit of using quotes in hash
158             constructors etc. It'll pass this policy and make it clear to everyone that
159             you really did want the literal string.
160              
161             The C<__PACKAGE__> literal is new in Perl 5.004 but this policy is applied
162             to all code. Even if you're targeting an earlier Perl extra quotes will
163             make it clear to users of later Perl that a literal string C<"__PACKAGE__">
164             is indeed intended.
165              
166             =head2 Fat Comma After Newline
167              
168             A C<< => >> fat comma only quotes when it's on the same line as the
169             preceding bareword, so in the following C<__PACKAGE__> is not quoted and is
170             therefore not reported by this policy,
171              
172             my %hash = (__PACKAGE__ # ok, expands
173             =>
174             'blah');
175              
176             Of course whether or not writing this is a good idea is another matter. It
177             might be a bit subtle to depend on the newline. Probably a plain C<,> comma
178             would make the intention clearer than C<< => >>.
179              
180             =head2 Class Data
181              
182             A bad C<< $obj->{__PACKAGE__} >> can arise when you're trying to hang extra
183             data on an object using your package name to hopefully not clash with the
184             object's native fields. Unexpanded C<__PACKAGE__> like that is a mistake
185             you'll probably only make once; after that the irritation of writing extra
186             parens or similar will keep it fresh in your mind!
187              
188             As usual there's more than one way to do it when associating extra data to
189             an object. As a crib here are some ways,
190              
191             =over 4
192              
193             =item Subhash C<< $obj->{(__PACKAGE__)}->{myfield} >>
194              
195             The extra parens ensure expansion, and you get a sub-hash (or sub-array or
196             whatever) to yourself. It's easy to delete the single entry from C<$obj>
197             if/when you later want to cleanup.
198              
199             =item Subscript C<< $obj->{__PACKAGE__,'myfield'} >>
200              
201             This makes entries in C<$obj>, with the C<$;> separator emulating
202             multidimensional arrays/hashes (see L<perlvar/$;>).
203              
204             =item Concated key C<< $obj->{__PACKAGE__.'--myfield'} >>
205              
206             Again entries in C<$obj>, but key formed by concatenation and an explicit
207             unlikely separator. The advantage over C<,> is that the key is a constant
208             (after constant folding), instead of a C<join> on every access because C<$;>
209             could change.
210              
211             =item Separate C<Tie::HashRef::Weak>
212              
213             Use the object as a hash key and the value whatever data you want to
214             associate. Keeps completely out of the object's hair and also works with
215             objects which use a "restricted hash" (see L<Hash::Util>) to prevent extra
216             keys.
217              
218             =item Inside-Out C<Hash::Util::FieldHash>
219              
220             Similar to HashRef with object as key and any value you want as the data
221             outside the object, hence the jargon "inside out". The docs are very hard
222             to follow (as of its version 1.04), especially if you're not into OOP, but
223             it's actually fairly simple.
224              
225             =item C<Scalar::Footnote>
226              
227             Key/value pairs attached to an object using its "magic" list. Doesn't touch
228             the object's contents but separate footnote users must be careful not to let
229             their keys clash.
230              
231             =back
232              
233             =head1 SEE ALSO
234              
235             L<Perl::Critic::Pulp>,
236             L<Perl::Critic>,
237             L<perldata/"Special Literals">
238              
239             =head1 HOME PAGE
240              
241             http://user42.tuxfamily.org/perl-critic-pulp/index.html
242              
243             =head1 COPYRIGHT
244              
245             Copyright 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017 Kevin Ryde
246              
247             Perl-Critic-Pulp is free software; you can redistribute it and/or modify it
248             under the terms of the GNU General Public License as published by the Free
249             Software Foundation; either version 3, or (at your option) any later
250             version.
251              
252             Perl-Critic-Pulp is distributed in the hope that it will be useful, but
253             WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
254             or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
255             more details.
256              
257             You should have received a copy of the GNU General Public License along with
258             Perl-Critic-Pulp. If not, see <http://www.gnu.org/licenses/>.
259              
260             =cut