File Coverage

blib/lib/Perl/Critic/Policy/Objects/ProhibitIndirectSyntax.pm
Criterion Covered Total %
statement 23 30 76.6
branch 1 12 8.3
condition 0 12 0.0
subroutine 11 11 100.0
pod 4 5 80.0
total 39 70 55.7


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::Objects::ProhibitIndirectSyntax;
2              
3 40     40   26823 use 5.010001;
  40         186  
4 40     40   261 use strict;
  40         103  
  40         835  
5 40     40   226 use warnings;
  40         114  
  40         1428  
6              
7 40     40   291 use Perl::Critic::Utils qw{ :severities :classification };
  40         146  
  40         2258  
8 40     40   13840 use Readonly;
  40         172  
  40         2217  
9              
10 40     40   309 use parent 'Perl::Critic::Policy';
  40         124  
  40         281  
11              
12             our $VERSION = '1.150';
13              
14             #-----------------------------------------------------------------------------
15              
16             Readonly::Hash my %COMMA => {
17             q<,> => 1,
18             q{=>} => 1,
19             };
20             Readonly::Scalar my $DOLLAR => q<$>;
21              
22             Readonly::Scalar my $DESC => 'Subroutine "%s" called using indirect syntax';
23             Readonly::Scalar my $EXPL => [ 349 ];
24              
25             #-----------------------------------------------------------------------------
26              
27             sub supported_parameters {
28             return (
29             {
30 90     90 0 2057 name => 'forbid',
31             description => 'Indirect method syntax is forbidden for these methods.',
32             behavior => 'string list',
33             list_always_present_values => [ qw{ new } ],
34             }
35             );
36             }
37              
38 74     74 1 343 sub default_severity { return $SEVERITY_HIGH }
39 86     86 1 388 sub default_themes { return qw( core pbp maintenance certrule ) }
40 32     32 1 93 sub applies_to { return 'PPI::Token::Word' }
41              
42             #-----------------------------------------------------------------------------
43              
44             sub violates {
45 346     346 1 545 my ( $self, $elem, $doc ) = @_;
46              
47             # We are only interested in the functions we have been told to check.
48             # Do this before calling is_function_call() because we want to weed
49             # out as many candidate tokens as possible before calling it.
50 346 50       578 return if not $self->{_forbid}->{$elem->content()};
51              
52             # Make sure it really is a function call.
53 0 0         return if not is_function_call($elem);
54              
55             # Per perlobj, it is only an indirect object call if the next sibling
56             # is a word, a scalar symbol, or a block.
57 0 0         my $object = $elem->snext_sibling() or return;
58             return if not (
59 0 0 0       $object->isa( 'PPI::Token::Word' )
      0        
      0        
60             or $object->isa( 'PPI::Token::Symbol' )
61             and $DOLLAR eq $object->raw_type()
62             or $object->isa( 'PPI::Structure::Block' )
63             );
64              
65             # Per perlobj, it is not an indirect object call if the operator after
66             # the possible indirect object is a comma.
67 0 0         if ( my $operator = $object->snext_sibling() ) {
68             return if
69             $operator->isa( 'PPI::Token::Operator' )
70 0 0 0       and $COMMA{ $operator->content() };
71             }
72              
73 0           my $message = sprintf $DESC, $elem->content();
74              
75 0           return $self->violation( $message, $EXPL, $elem );
76             }
77              
78             1;
79              
80             __END__
81              
82             #-----------------------------------------------------------------------------
83              
84             =pod
85              
86             =head1 NAME
87              
88             Perl::Critic::Policy::Objects::ProhibitIndirectSyntax - Prohibit indirect object call syntax.
89              
90              
91             =head1 AFFILIATION
92              
93             This Policy is part of the core L<Perl::Critic|Perl::Critic>
94             distribution.
95              
96              
97             =head1 DESCRIPTION
98              
99             Indirect object syntax is commonly used in other object-oriented languages for
100             instantiating objects. Perl allows this, but to say that it supports it may be
101             going too far. Instead of writing
102              
103             my $foo = new Foo;
104              
105             it is preferable to write
106              
107             my $foo = Foo->new;
108              
109             The problem is that Perl needs to make a number of assumptions at compile time
110             to disambiguate the first form, so it tends to be fragile and to produce
111             hard-to-track-down bugs.
112              
113              
114             =head1 CONFIGURATION
115              
116             Indirect object syntax is also hard for Perl::Critic to disambiguate, so this
117             policy only checks certain subroutine calls. The names of the subroutines can
118             be configured using the C<forbid> configuration option:
119              
120             [Objects::ProhibitIndirectSyntax]
121             forbid = create destroy
122              
123             The C<new> subroutine is configured by default; any additional C<forbid>
124             values are in addition to C<new>.
125              
126              
127             =head1 CAVEATS
128              
129             The general situation can not be handled via static analysis.
130              
131              
132             =head1 SEE ALSO
133              
134             L<Perl::Critic::Policy::Dynamic::NoIndirect|Perl::Critic::Policy::Dynamic::NoIndirect>
135             and L<indirect|indirect> both do a better job with this, but they require that you
136             compile/execute your code.
137              
138              
139             =head1 AUTHOR
140              
141             Thomas R. Wyant, III F<wyant at cpan dot org>
142              
143              
144             =head1 COPYRIGHT
145              
146             Copyright (c) 2009-2023 Tom Wyant
147              
148             This program is free software; you can redistribute it and/or modify
149             it under the same terms as Perl itself. The full text of this license
150             can be found in the LICENSE file included with this module.
151              
152             =cut
153              
154             # Local Variables:
155             # mode: cperl
156             # cperl-indent-level: 4
157             # fill-column: 78
158             # indent-tabs-mode: nil
159             # c-indentation-style: bsd
160             # End:
161             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :
162