File Coverage

blib/lib/indirect.pm
Criterion Covered Total %
statement 43 43 100.0
branch 20 20 100.0
condition n/a
subroutine 11 11 100.0
pod 1 1 100.0
total 75 75 100.0


line stmt bran cond sub pod time code
1             package indirect;
2              
3 15     15   174098 use 5.008_001;
  15         54  
4              
5 15     15   75 use strict;
  15         24  
  15         398  
6 15     15   73 use warnings;
  15         25  
  15         1046  
7              
8             =head1 NAME
9              
10             indirect - Lexically warn about using the indirect method call syntax.
11              
12             =head1 VERSION
13              
14             Version 0.36
15              
16             =cut
17              
18             our $VERSION;
19             BEGIN {
20 15     15   2264 $VERSION = '0.36';
21             }
22              
23             =head1 SYNOPSIS
24              
25             In a script :
26              
27             no indirect; # lexically enables the pragma
28             my $x = new Apple 1, 2, 3; # warns
29             {
30             use indirect; # lexically disables the pragma
31             my $y = new Pear; # legit, does not warn
32             {
33             # lexically specify an hook called for each indirect construct
34             no indirect hook => sub {
35             die "You really wanted $_[0]\->$_[1] at $_[2]:$_[3]"
36             };
37             my $z = new Pineapple 'fresh'; # croaks 'You really wanted...'
38             }
39             }
40             try { ... }; # warns if try() hasn't been declared in this package
41              
42             no indirect 'fatal'; # or ':fatal', 'FATAL', ':Fatal' ...
43             if (defied $foo) { ... } # croaks, note the typo
44              
45             Global uses :
46              
47             # Globally enable the pragma from the command-line
48             perl -M-indirect=global -e 'my $x = new Banana;' # warns
49              
50             # Globally enforce the pragma each time perl is executed
51             export PERL5OPT="-M-indirect=global,fatal"
52             perl -e 'my $y = new Coconut;' # croaks
53              
54             =head1 DESCRIPTION
55              
56             When enabled, this pragma warns about indirect method calls that are present in your code.
57              
58             The indirect syntax is now considered harmful, since its parsing has many quirks and its use is error prone : when the subroutine C<foo> has not been declared in the current package, C<foo $x> actually compiles to C<< $x->foo >>, and C<< foo { key => 1 } >> to C<< 'key'->foo(1) >>.
59             Please refer to the L</REFERENCES> section for a more complete list of reasons for avoiding this construct.
60              
61             This pragma currently does not warn for core functions (C<print>, C<say>, C<exec> or C<system>).
62             This may change in the future, or may be added as optional features that would be enabled by passing options to C<unimport>.
63              
64             This module is B<not> a source filter.
65              
66             =cut
67              
68             BEGIN {
69 15 100   15   81 if ($ENV{PERL_INDIRECT_PM_DISABLE}) {
70 1     1   7 *_tag = sub ($) { 1 };
  1         6  
71 1         2 *I_THREADSAFE = sub () { 1 };
72 1         866 *I_FORKSAFE = sub () { 1 };
73             } else {
74 14         76 require XSLoader;
75 14         15355 XSLoader::load(__PACKAGE__, $VERSION);
76             }
77             }
78              
79             =head1 METHODS
80              
81             =head2 C<unimport>
82              
83             no indirect;
84             no indirect 'fatal';
85             no indirect hook => sub { my ($obj, $name, $file, $line) = @_; ... };
86             no indirect 'global';
87             no indirect 'global, 'fatal';
88             no indirect 'global', hook => sub { ... };
89              
90             Magically called when C<no indirect @opts> is encountered.
91             Turns the module on.
92             The policy to apply depends on what is first found in C<@opts> :
93              
94             =over 4
95              
96             =item *
97              
98             If it is a string that matches C</^:?fatal$/i>, the compilation will croak when the first indirect method call is found.
99              
100             This option is mutually exclusive with the C<'hook'> option.
101              
102             =item *
103              
104             If the key/value pair C<< hook => $hook >> comes first, C<$hook> will be called for each error with a string representation of the object as C<$_[0]>, the method name as C<$_[1]>, the current file as C<$_[2]> and the line number as C<$_[3]>.
105             If and only if the object is actually a block, C<$_[0]> is assured to start by C<'{'>.
106              
107             This option is mutually exclusive with the C<'fatal'> option.
108              
109             =item *
110              
111             If none of C<fatal> and C<hook> are specified, a warning will be emitted for each indirect method call.
112              
113             =item *
114              
115             If C<@opts> contains a string that matches C</^:?global$/i>, the pragma will be globally enabled for B<all> code compiled after the current C<no indirect> statement, except for code that is in the lexical scope of C<use indirect>.
116             This option may come indifferently before or after the C<fatal> or C<hook> options, in the case they are also passed to L</unimport>.
117              
118             The global policy applied is the one resulting of the C<fatal> or C<hook> options, thus defaults to a warning when none of those are specified :
119              
120             no indirect 'global'; # warn for any indirect call
121             no indirect qw<global fatal>; # die on any indirect call
122             no indirect 'global', hook => \&hook # custom global action
123              
124             Note that if another policy is installed by a C<no indirect> statement further in the code, it will overrule the global policy :
125              
126             no indirect 'global'; # warn globally
127             {
128             no indirect 'fatal'; # throw exceptions for this lexical scope
129             ...
130             require Some::Module; # the global policy will apply for the
131             # compilation phase of this module
132             }
133              
134             =back
135              
136             =cut
137              
138             sub _no_hook_and_fatal {
139 2     2   15 require Carp;
140 2         404 Carp::croak("The 'fatal' and 'hook' options are mutually exclusive");
141             }
142              
143             sub unimport {
144 3070     3070   1022838 shift;
145              
146 3070         3590 my ($global, $fatal, $hook);
147              
148 3070         8139 while (@_) {
149 1047         1194 my $arg = shift;
150 1047 100       2314 if ($arg eq 'hook') {
    100          
    100          
151 1023 100       1593 _no_hook_and_fatal() if $fatal;
152 1022         2163 $hook = shift;
153             } elsif ($arg =~ /^:?fatal$/i) {
154 17 100       50 _no_hook_and_fatal() if defined $hook;
155 16         73 $fatal = 1;
156             } elsif ($arg =~ /^:?global$/i) {
157 5         12 $global = 1;
158             }
159             }
160              
161 3068 100       6042 unless (defined $hook) {
162 2047 100   7   10851 $hook = $fatal ? sub { die msg(@_) } : sub { warn msg(@_) };
  7         23  
  332         26730  
163             }
164              
165 3068         6640 $^H |= 0x00020000;
166 3068 100       4641 if ($global) {
167 5         26 delete $^H{+(__PACKAGE__)};
168 5         25 _global($hook);
169             } else {
170 3063         13796 $^H{+(__PACKAGE__)} = _tag($hook);
171             }
172              
173 3068         209384 return;
174             }
175              
176             =head2 C<import>
177              
178             use indirect;
179              
180             Magically called at each C<use indirect>. Turns the module off.
181              
182             As explained in L</unimport>'s description, an C<use indirect> statement will lexically override a global policy previously installed by C<no indirect 'global', ...> (if there's one).
183              
184             =cut
185              
186             sub import {
187 2023     2023   1016174 $^H |= 0x00020000;
188 2023         7677 $^H{+(__PACKAGE__)} = _tag(undef);
189              
190 2023         126041 return;
191             }
192              
193             =head1 FUNCTIONS
194              
195             =head2 C<msg>
196              
197             my $msg = msg($object, $method, $file, $line);
198              
199             Returns the default error message that C<indirect> generates when an indirect method call is reported.
200              
201             =cut
202              
203             sub msg {
204 340     340 1 523 my $obj = $_[0];
205              
206 340 100       5110 join ' ', "Indirect call of method \"$_[1]\" on",
207             ($obj =~ /^\s*\{/ ? "a block" : "object \"$obj\""),
208             "at $_[2] line $_[3].\n";
209             };
210              
211             =head1 CONSTANTS
212              
213             =head2 C<I_THREADSAFE>
214              
215             True iff the module could have been built with thread-safety features enabled.
216              
217             =head2 C<I_FORKSAFE>
218              
219             True iff this module could have been built with fork-safety features enabled.
220             This will always be true except on Windows where it's false for perl 5.10.0 and below .
221              
222             =head1 DIAGNOSTICS
223              
224             =head2 C<Indirect call of method "%s" on object "%s" at %s line %d.>
225              
226             The default warning/exception message thrown when an indirect method call on an object is found.
227              
228             =head2 C<Indirect call of method "%s" on a block at %s line %d.>
229              
230             The default warning/exception message thrown when an indirect method call on a block is found.
231              
232             =head1 ENVIRONMENT
233              
234             =head2 C<PERL_INDIRECT_PM_DISABLE>
235              
236             If this environment variable is set to true when the pragma is used for the first time, the XS code won't be loaded and, although the C<'indirect'> lexical hint will be set to true in the scope of use, the pragma itself won't do anything.
237             In this case, the pragma will always be considered to be thread-safe, and as such L</I_THREADSAFE> will be true.
238             This is useful for disabling C<indirect> in production environments.
239              
240             Note that clearing this variable after C<indirect> was loaded has no effect.
241             If you want to re-enable the pragma later, you also need to reload it by deleting the C<'indirect.pm'> entry from C<%INC>.
242              
243             =head1 CAVEATS
244              
245             The implementation was tweaked to work around several limitations of vanilla C<perl> pragmas : it's thread safe, and does not suffer from a C<perl 5.8.x-5.10.0> bug that causes all pragmas to propagate into C<require>d scopes.
246              
247             Before C<perl> 5.12, C<meth $obj> (no semicolon) at the end of a file is not seen as an indirect method call, although it is as soon as there is another token before the end (as in C<meth $obj;> or C<meth $obj 1>).
248             If you use C<perl> 5.12 or greater, those constructs are correctly reported.
249              
250             With 5.8 perls, the pragma does not propagate into C<eval STRING>.
251             This is due to a shortcoming in the way perl handles the hints hash, which is addressed in perl 5.10.
252              
253             The search for indirect method calls happens before constant folding.
254             Hence C<my $x = new Class if 0> will be caught.
255              
256             =head1 REFERENCES
257              
258             Numerous articles have been written about the quirks of the indirect object construct :
259              
260             =over 4
261              
262             =item *
263              
264             L<http://markmail.org/message/o7d5sxnydya7bwvv> : B<Far More Than Everything You've Ever Wanted to Know about the Indirect Object syntax>, Tom Christiansen, 1998-01-28.
265              
266             This historical post to the C<perl5-porters> mailing list raised awareness about the perils of this syntax.
267              
268             =item *
269              
270             L<http://www.shadowcat.co.uk/blog/matt-s-trout/indirect-but-still-fatal> : B<Indirect but still fatal>, Matt S. Trout, 2009-07-29.
271              
272             In this blog post, the author gives an example of an undesirable indirect method call on a block that causes a particularly bewildering error.
273              
274             =back
275              
276             =head1 DEPENDENCIES
277              
278             L<perl> 5.8.1.
279              
280             A C compiler.
281             This module may happen to build with a C++ compiler as well, but don't rely on it, as no guarantee is made in this regard.
282              
283             L<Carp> (standard since perl 5), L<XSLoader> (since perl 5.6.0).
284              
285             =head1 AUTHOR
286              
287             Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
288              
289             You can contact me by mail or on C<irc.perl.org> (vincent).
290              
291             =head1 BUGS
292              
293             Please report any bugs or feature requests to C<bug-indirect at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=indirect>.
294             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
295              
296             =head1 SUPPORT
297              
298             You can find documentation for this module with the perldoc command.
299              
300             perldoc indirect
301              
302             Tests code coverage report is available at L<http://www.profvince.com/perl/cover/indirect>.
303              
304             =head1 ACKNOWLEDGEMENTS
305              
306             Bram, for motivation and advices.
307              
308             Andrew Main and Florian Ragwitz, for testing on real-life code and reporting issues.
309              
310             =head1 COPYRIGHT & LICENSE
311              
312             Copyright 2008,2009,2010,2011,2012,2013,2014,2015 Vincent Pit, all rights reserved.
313              
314             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
315              
316             =cut
317              
318             1; # End of indirect