File Coverage

blib/lib/Perl/Critic/Policy/Modules/RequireExplicitInclusion.pm
Criterion Covered Total %
statement 117 125 93.6
branch 27 34 79.4
condition 21 26 80.7
subroutine 29 30 96.6
pod 4 5 80.0
total 198 220 90.0


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Modules::RequireExplicitInclusion;
2              
3 1     1   1015 use strict;
  1         2  
  1         43  
4 1     1   6 use warnings;
  1         1  
  1         88  
5 1     1   8 use base 'Perl::Critic::Policy';
  1         2  
  1         150  
6              
7 1     1   7 use List::MoreUtils qw( any );
  1         3  
  1         12  
8 1     1   979 use Readonly;
  1         3  
  1         101  
9              
10 1         72 use Perl::Critic::Utils qw(
11             :characters
12             :severities
13             &hashify
14             &is_class_name
15             &is_function_call
16             &is_perl_builtin
17             &is_qualified_name
18             &policy_short_name
19 1     1   8 );
  1         3  
20              
21 1         34 use Perl::Critic::Exception::Configuration::Option::Policy::ParameterValue qw(
22             throw_policy_value
23 1     1   479 );
  1         3  
24              
25 1         2561 use Perl::Critic::StricterSubs::Utils qw(
26             &get_package_names_from_include_statements
27             &get_package_names_from_package_statements
28 1     1   112 );
  1         3  
29              
30             #-----------------------------------------------------------------------------
31              
32             our $VERSION = '0.08';
33              
34             my $expl =
35             'Without importing a package, it is unlikely that references to things inside it even exist.';
36              
37             #-----------------------------------------------------------------------------
38              
39             sub supported_parameters {
40             return (
41             {
42 28     28 0 2038530 name => 'ignore_modules',
43             description => 'The names of modules to ignore if a violation is found',
44             default_string => q{},
45             parser => \&_parse_modules,
46             },
47             );
48             }
49 27     27 1 257 sub default_severity { return $SEVERITY_HIGH }
50 0     0 1 0 sub default_themes { return qw( strictersubs bugs ) }
51 28     28 1 341162 sub applies_to { return 'PPI::Document' }
52              
53             #-----------------------------------------------------------------------------
54              
55             Readonly my $MODULE_NAME_REGEX =>
56             qr{
57             \b
58             [[:alpha:]_]
59             (?:
60             (?: \w | :: )*
61             \w
62             )?
63             \b
64             }xms;
65             Readonly my $REGULAR_EXPRESSION_REGEX => qr{ [/] ( [^/]+ ) [/] }xms;
66              
67             # It's kind of unfortunate that I had to put capturing parentheses in the
68             # component regexes above, because they're not visible here and so make
69             # figuring out the positions of captures hard. Too bad we can't make the
70             # minimum perl version 5.10. :]
71             Readonly my $MODULES_REGEX =>
72             qr{
73             \A
74             \s*
75             (?:
76             ( $MODULE_NAME_REGEX )
77             | $REGULAR_EXPRESSION_REGEX
78             )
79             \s*
80             }xms;
81              
82             #-----------------------------------------------------------------------------
83              
84             sub _parse_modules {
85 28     28   29616 my ($self, $parameter, $config_string) = @_;
86              
87 28   66     233 my $module_specifications = $config_string // $parameter->get_default_string();
88              
89 28 100       244 return if not $module_specifications;
90 2 50       15 return if $module_specifications =~ m{ \A \s* \z }xms;
91              
92 2         21 while ( $module_specifications =~ s{ $MODULES_REGEX }{}xms ) {
93 2         307 my ($module, $regex_string) = ($1, $2);
94              
95 2         12 $self->_handle_module_specification(
96             module => $module,
97             regex_string => $regex_string,
98             option_name => 'ignore_modules',
99             option_value => $config_string,
100             );
101             }
102              
103 2 50       20 if ($module_specifications) {
104 0         0 throw_policy_value
105             policy => $self->get_short_name(),
106             option_name => 'ignore_modules',
107             option_value => $config_string,
108             message_suffix =>
109             qq{contains unparseable data: "$module_specifications"};
110             }
111              
112 2         9 return;
113             }
114              
115              
116             sub _handle_module_specification {
117 2     2   16 my ($self, %arguments) = @_;
118              
119 2 100       11 if ( my $regex_string = $arguments{regex_string} ) {
120             # These are module name patterns (e.g. /Acme/)
121 1         4 my $actual_regex;
122              
123 1         24 eval { $actual_regex = qr/$regex_string/; 1 } ## no critic (ExtendedFormatting, LineBoundaryMatching, DotMatchAnything)
  1         6  
124             or throw_policy_value
125             policy => $self->get_short_name(),
126             option_name => $arguments{option_name},
127             option_value => $arguments{option_value},
128 1 50       4 message_suffix =>
129             qq{contains an invalid regular expression: "$regex_string"};
130              
131             # Can't use a hash due to stringification, so this is an AoA.
132 1   50     12 $self->{_ignore_modules_regexes} ||= [];
133              
134             push
135 1         2 @{ $self->{_ignore_modules_regexes} },
  1         4  
136             $actual_regex;
137             }
138             else {
139             # These are literal module names (e.g. Acme::Foo)
140 1   50     8 $self->{_ignore_modules} ||= {};
141 1         5 $self->{_ignore_modules}{ $arguments{module} } = undef;
142             }
143              
144 2         14 return;
145             }
146              
147             #-----------------------------------------------------------------------------
148              
149             sub violates {
150 28     28 1 373 my ($self, undef, $doc) = @_;
151              
152 28         178 my @declared_packages = get_package_names_from_package_statements($doc);
153              
154 28 50       195 if ( @declared_packages > 1 ) {
155 0   0     0 my $fname = $doc->filename() || 'unknown';
156 0         0 my $pname = policy_short_name(__PACKAGE__);
157 0         0 warn qq{$pname: Cannot cope with multiple packages in file "$fname"\n};
158 0         0 return;
159             }
160              
161 28         118 my @included_packages = get_package_names_from_include_statements($doc);
162 28         502 my @builtin_packages = ( qw(main UNIVERSAL CORE CORE::GLOBAL utf8), $EMPTY );
163              
164 28         136 my %all_packages =
165             hashify( @declared_packages, @included_packages, @builtin_packages );
166              
167 28         653 my @violations = (
168             $self->_find_subroutine_call_violations( $doc, \%all_packages ),
169             $self->_find_class_method_call_violations( $doc, \%all_packages ),
170             $self->_find_symbol_violations( $doc, \%all_packages ),
171             );
172              
173 28         198 return @violations;
174             }
175              
176             #-----------------------------------------------------------------------------
177              
178             sub _find_qualified_subroutine_calls {
179 28     28   58 my $doc = shift;
180              
181             my $calls =
182             $doc->find(
183             sub {
184 1088     1088   15998 my (undef, $elem) = @_;
185              
186             return
187 1088   100     3669 $elem->isa('PPI::Token::Word')
188             && is_qualified_name( $elem->content() )
189             && is_function_call( $elem );
190              
191             }
192 28         191 );
193              
194 28 100       439 return @{$calls} if $calls;
  6         19  
195 22         70 return;
196             }
197              
198             #-----------------------------------------------------------------------------
199              
200             sub _find_class_method_calls {
201 28     28   50 my $doc = shift;
202              
203             my $calls =
204             $doc->find(
205             sub {
206 1088     1088   16580 my (undef, $elem) = @_;
207              
208             return
209 1088   100     3222 $elem->isa('PPI::Token::Word')
210             && is_class_name( $elem )
211             && !is_perl_builtin( $elem )
212             && '__PACKAGE__' ne $elem->content(); # RT 43314, 44609
213             # From a design standpoint we should filter later, but
214             # the violation code is generic. The patch included with
215             # 44609, or adding '__PACKAGE__ to @builtin_packages,
216             # would have also allowed, willy-nilly,
217             # __PACKAGE__::foo() or $__PACKAGE__::foo, neither of
218             # which is correct. So I just hid __PACKAGE__->foo() from
219             # the violation logic. Mea culpa! Tom Wyant
220             }
221 28         180 );
222              
223 28 100       449 return @{$calls} if $calls;
  7         28  
224 21         59 return;
225             }
226              
227             #-----------------------------------------------------------------------------
228              
229             sub _find_qualified_symbols {
230 28     28   48 my $doc = shift;
231              
232             my $symbols =
233             $doc->find(
234             sub {
235 1088     1088   11905 my (undef, $elem) = @_;
236              
237             return
238 1088   100     3292 $elem->isa('PPI::Token::Symbol')
239             && is_qualified_name( $elem->canonical() );
240             }
241 28         172 );
242              
243 28 100       404 return @{$symbols} if $symbols;
  18         62  
244 10         30 return;
245             }
246              
247             #-----------------------------------------------------------------------------
248              
249             sub _extract_package_from_class_method_call {
250              
251             # Class method calls look like "Foo::Bar->baz()"
252             # So the package name will be the entire word,
253             # which should be everything to the left of "->"
254              
255 21     21   33 my $word = shift;
256              
257             # Remove trailing double colon, which is allowed and can be used for
258             # disambiguation.
259 21         60 $word =~ s/::$//xms;
260              
261 21         101 return $word;
262             }
263              
264             #-----------------------------------------------------------------------------
265              
266             sub _extract_package_from_subroutine_call {
267              
268             # Subroutine calls look like "Foo::Bar::baz()"
269             # So the package name will be everything up
270             # to (but not including) the last "::".
271              
272 15     15   18 my $word = shift;
273 15 50       27 if ($word->content() =~ m/\A ( .* ) :: [^:]* \z/xms) {
274 15         110 return $1;
275             }
276              
277 0         0 return;
278             }
279              
280             #-----------------------------------------------------------------------------
281              
282             sub _extract_package_from_symbol {
283              
284             # Qualified symbols look like "$Foo::Bar::baz"
285             # So the package name will be everything between
286             # the sigil and the last "::".
287              
288 32     32   53 my $symbol = shift;
289 32 50       79 if ($symbol->canonical() =~ m/\A [\$*@%&] ( .* ) :: [^:]+ \z/xms) {
290 32         644 return $1;
291             }
292              
293 0         0 return;
294             }
295              
296             #-----------------------------------------------------------------------------
297              
298             sub _find_violations {
299              
300 84     84   223 my ($self, $doc, $included_packages, $finder, $package_extractor) = @_;
301 84         117 my @violations;
302              
303 84         250 for my $call ( $finder->( $doc ) ) {
304 68         3089 my $package = $package_extractor->( $call );
305 68 100       172 next if exists $included_packages->{ $package };
306 34 100       108 next if $self->_is_ignored_module( $package );
307              
308 32 100       98 next if exists $self->{_ignore_modules}->{ $package };
309              
310 30 100 100     113 if ( not ( $call eq 'STDIN' || $call eq 'STDOUT' || $call eq 'STDERR' ) ) {
      100        
311 27         875 my $desc = qq{Use of "$call" without including "$package"};
312 27         172 push @violations, $self->violation( $desc, $expl, $call );
313             }
314             }
315              
316 84         2265 return @violations;
317             }
318              
319              
320             sub _is_ignored_module {
321 34     34   69 my ($self, $package) = @_;
322              
323 34   100     127 my $ignore_hash = ($self->{_ignore_modules} //= {});
324 34 50       75 return if $ignore_hash->{ $package };
325              
326 34 100       100 if ( my $ignore_regex_list = $self->{_ignore_modules_regexes} ) {
327 2     2   5 return any { $package =~ /$_/smx } @{$ignore_regex_list};
  2         15  
  2         29  
328             }
329              
330 32         79 return 0;
331             }
332              
333             #-----------------------------------------------------------------------------
334              
335             sub _find_subroutine_call_violations {
336 28     28   75 my ($self, $doc, $packages) = @_;
337 28         76 my $finder = \&_find_qualified_subroutine_calls;
338 28         97 my $extractor = \&_extract_package_from_subroutine_call;
339 28         136 return $self->_find_violations( $doc, $packages, $finder, $extractor );
340             }
341              
342             #-----------------------------------------------------------------------------
343              
344             sub _find_class_method_call_violations {
345 28     28   71 my ($self, $doc, $packages) = @_;
346 28         63 my $finder = \&_find_class_method_calls;
347 28         67 my $extractor = \&_extract_package_from_class_method_call;
348 28         71 return $self->_find_violations( $doc, $packages, $finder, $extractor );
349             }
350              
351             #-----------------------------------------------------------------------------
352              
353             sub _find_symbol_violations {
354 28     28   73 my ($self, $doc, $packages) = @_;
355 28         81 my $finder = \&_find_qualified_symbols;
356 28         60 my $extractor = \&_extract_package_from_symbol;
357 28         70 return $self->_find_violations( $doc, $packages, $finder, $extractor );
358             }
359              
360             #-----------------------------------------------------------------------------
361              
362             1;
363              
364             __END__
365              
366             =pod
367              
368             =head1 NAME
369              
370             Perl::Critic::Policy::Modules::RequireExplicitInclusion
371              
372             =head1 AFFILIATION
373              
374             This policy is part of L<Perl::Critic::StricterSubs|Perl::Critic::StricterSubs>.
375              
376             =head1 DESCRIPTION
377              
378             Checks that, if a reference is made to something inside of another
379             package, that a module with the name of the package has been C<use>d
380             or C<require>d.
381              
382             Without importing a package, it is unlikely that references to things
383             inside it even exist. Due to the flexible nature of Perl, C<use
384             strict;> can not complain about references to things outside of the
385             current package and thus won't detect this situation.
386              
387             =head2 Explanation
388              
389             As an example, assume there is a third-party C<Foo> module with a
390             C<bar()> subroutine. You then create a module of your own.
391              
392             package My::Module;
393              
394             ...
395             $x = Foo::bar($y);
396             ...
397              
398             You don't have to worry about whether C<Foo> exports C<bar()> or not
399             because you're fully qualifying the name. Or do you? You then create
400             a program F<plugh> that uses your module that also needs to use C<Foo>
401             directly.
402              
403             #!/usr/bin/perl
404             ...
405             use Foo;
406             use My::Module qw{ &frob };
407             ...
408              
409             This works fine. At some later time, you use your module in a
410             F<xyzzy> program.
411              
412             #!/usr/bin/perl
413             ...
414             use My::Module qw{ &frob };
415             ...
416              
417             You now get compilation problems in the previously robust
418             C<My::Module>. What is going on is that F<plugh> loaded the C<Foo>
419             module prior to C<My::Module>, which means that, when C<My::Module>
420             refers to C<Foo::bar()>, the subroutine actually exists, even though
421             C<My::Module> didn't actually C<use Foo;>. When F<xyzzy> attempted to
422             use C<My::Module> without doing a C<use Foo;>, C<My::Module> fails
423             because C<Foo::bar()> doesn't exist.
424              
425             =head2 Enforcement
426              
427             Assuming that there are no C<use> or C<require> statements within the
428             current scope:
429              
430             @foo = localtime; #ok
431             @Bar::foo = localtime #not ok
432             @::foo = localtime; #ok
433             @main::foo = localtime; #ok
434              
435             baz(23, 'something', $x); #ok
436             Bar::baz(23, 'something', $x); #not ok
437             ::baz(23, 'something', $x); #ok
438             main::baz(23, 'something', $x); #ok
439              
440             Only modules that are symbolically referenced by a C<use> or
441             C<require> are considered valid. Loading a file does not count.
442              
443             use Foo;
444             require Bar;
445             require 'Baz.pm';
446              
447             $Foo:x = 57; #ok
448             $Bar:x = 57; #ok
449             $Baz:x = 57; #not ok
450              
451             Qualifying a name with the name of the current package is valid.
452              
453             package Xyzzy;
454              
455             my $ducks;
456              
457             sub increment_duck_count {
458             $Xyzzy::ducks++; #ok
459             }
460              
461             A C<use> or C<require> statement is taken into account only when it is
462             in the scope of a file or a C<BEGIN>, C<CHECK>, or C<INIT> block.
463              
464             use File::Scope;
465              
466             BEGIN {
467             require Begin::Block;
468             }
469              
470             CHECK {
471             require Check::Block;
472             }
473              
474             INIT {
475             require Init::Block;
476             }
477              
478             END {
479             require End::Block;
480             }
481              
482             push @File::Scope::numbers, 52, 93, 25; #ok
483             push @Begin::Block::numbers, 52, 93, 25; #ok
484             push @Check::Block::numbers, 52, 93, 25; #ok
485             push @Init::Block::numbers, 52, 93, 25; #ok
486             push @End::Block::numbers, 52, 93, 25; #not ok
487              
488             {
489             require Lexical::Block;
490              
491             push @Lexical::Block::numbers, 52, 93, 25; #not ok
492             }
493              
494             =head1 CONFIGURATION
495              
496             You can configure a list of modules that should be ignored by this policy.
497             For example, it's common to use Test::Builder's variables in functions
498             built on Test::More.
499              
500             use Test::More
501              
502             sub test_something {
503             local $Test::Builder::Level = $Test::Builder::Level + 1;
504              
505             return is( ... );
506             }
507              
508             Using Test::More also brings in Test::Builder, so you don't need to do
509             a call to C<use>. Unfortunately that trips this policy.
510              
511             So to ignore violations on Test::Builder, you can add to your perlcriticrc
512             file this section:
513              
514             [Modules::RequireExplicitInclusion]
515             ignore_modules = Test::Builder
516              
517             The C<ignore_modules> argument can take a space-delimited list of modules,
518             or of regexes, or both.
519              
520             [Modules::RequireExplicitInclusion]
521             ignore_modules = Test::Builder /MooseX::/
522              
523             =head1 CAVEATS
524              
525             1.) It is assumed that the code for a package exists in a module of
526             the same name.
527              
528              
529             2.) It is assumed that a module will contain no more than one package.
530             This Policy will not complain about any problems in a module
531             containing multiple C<package> statements. For example, a module
532             containing
533              
534             package Foo;
535              
536             sub frob {
537             $Xyzzy::factor = rand 100;
538             }
539              
540             package Bar;
541              
542             sub frob {
543             $Plugh::factor = rand 1000;
544             }
545              
546             will not result in any violations. There really shouldn't be more
547             than one package within a module anyway.
548              
549              
550             3.) No checks of whether the name actually exists in the referenced
551             package are done. E.g., if a call to a C<Foo::process_widgets()>
552             subroutine is made, this Policy does not check that a
553             C<process_widgets()> subroutine actually exists in the C<Foo> package.
554              
555              
556             =head1 DIAGNOSTICS
557              
558             =over
559              
560             =item C<Modules::RequireExplicitInclusion: Cannot cope with multiple packages in file>
561              
562             This warning happens when the file under analysis contains multiple packages,
563             which is not currently supported. This Policy will simply ignore any file
564             with multiple packages.
565              
566             L<Perl::Critic|Perl::Critic> advises putting multiple packages in one file, and has
567             additional Policies to help enforce that.
568              
569             =back
570              
571             =head1 SEE ALSO
572              
573             L<Perl::Critic::Policy::Modules::ProhibitMultiplePackages|Perl::Critic::Policy::Modules::ProhibitMultiplePackages>
574              
575             =head1 AUTHOR
576              
577             Jeffrey Ryan Thalhammer <thaljef@cpan.org>
578              
579             =head1 COPYRIGHT
580              
581             Copyright 2007-2024 Jeffrey Ryan Thalhammer and Andy Lester
582              
583             This program is free software; you can redistribute it and/or modify it under
584             the same terms as Perl itself. The full text of this license can be found in
585             the LICENSE file included with this module.
586              
587             =cut
588              
589              
590             ##############################################################################
591             # Local Variables:
592             # mode: cperl
593             # cperl-indent-level: 4
594             # fill-column: 78
595             # indent-tabs-mode: nil
596             # c-indentation-style: bsd
597             # End:
598             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab :