From Code to Community: Sponsoring The Perl and Raku Conference 2025 Learn more

##############################################################################
# $Date: 2009-06-27 20:02:58 -0400 (Sat, 27 Jun 2009) $
# $Author: clonezone $
# $Revision: 3373 $
##############################################################################
use 5.006001;
use strict;
use Carp;
use English qw(-no_match_vars);
use Perl::Critic::Utils qw{ :severities :classification };
our $VERSION = '1.099_002';
#-----------------------------------------------------------------------------
Readonly::Hash my %COMMA => {
q<,> => 1,
q{=>} => 1,
};
Readonly::Scalar my $DOLLAR => q<$>;
Readonly::Scalar my $DESC => 'Subroutine "%s" called using indirect syntax';
Readonly::Scalar my $EXPL => [ 349 ];
#-----------------------------------------------------------------------------
sub supported_parameters {
return (
{
name => 'forbid',
description => 'Indirect method syntax is forbidden for these methods.',
behavior => 'string list',
list_always_present_values => [ qw{ new } ],
}
)
}
sub default_severity { return $SEVERITY_HIGH }
sub default_themes { return qw( core pbp maintenance ) }
sub applies_to { return 'PPI::Token::Word' }
#-----------------------------------------------------------------------------
sub violates {
my ( $self, $elem, $doc ) = @_;
# We are only interested in the functions we have been told to check.
# Do this before calling is_function_call() because we want to weed
# out as many candidate tokens as possible before calling it.
return if not $self->{_forbid}->{$elem->content()};
# Make sure it really is a function call.
return if not is_function_call($elem);
# Per perlobj, it is only an indirect object call if the next sibling
# is a word, a scalar symbol, or a block.
my $object = $elem->snext_sibling() or return;
return if not (
$object->isa( 'PPI::Token::Word' )
or $object->isa( 'PPI::Token::Symbol' )
and $DOLLAR eq $object->raw_type()
or $object->isa( 'PPI::Structure::Block' )
);
# Per perlobj, it is not an indirect object call if the operator after
# the possible indirect object is a comma.
if ( my $operator = $object->snext_sibling() ) {
return if
$operator->isa( 'PPI::Token::Operator' )
and $COMMA{ $operator->content() };
}
my $message = sprintf $DESC, $elem->content();
return $self->violation( $message, $EXPL, $elem );
}
1;
__END__
#-----------------------------------------------------------------------------
=pod
=head1 NAME
Perl::Critic::Policy::Objects::ProhibitIndirectSyntax - Prohibit indirect object call syntax.
=head1 AFFILIATION
This Policy is part of the core L<Perl::Critic|Perl::Critic>
distribution.
=head1 DESCRIPTION
Indirect object syntax is commonly used in other object-oriented languages for
instantiating objects. Perl allows this, but to say that it supports it may be
going too far. Instead of writing
my $foo = new Foo;
it is preferable to write
my $foo = Foo->new;
The problem is that Perl needs to make a number of assumptions at compile time
to disambiguate the first form, so it tends to be fragile and to produce
hard-to-track-down bugs.
=head1 CONFIGURATION
Indirect object syntax is also hard for Perl::Critic to disambiguate, so this
policy only checks certain subroutine calls. The names of the subroutines can
be configured using the C<forbid> configuration option:
[Objects::ProhibitIndirectSyntax]
forbid = create destroy
The C<new> subroutine is configured by default; any additional C<forbid>
values are in addition to C<new>.
=head1 CAVEATS
The general situation can not be handled.
=head1 AUTHOR
Thomas R. Wyant, III F<wyant at cpan dot org>
=head1 COPYRIGHT
Copyright (c) 2009 Tom Wyant.
This program is free software; you can redistribute it and/or modify
it under the same terms as Perl itself. The full text of this license
can be found in the LICENSE file included with this module.
=cut
# Local Variables:
# mode: cperl
# cperl-indent-level: 4
# fill-column: 78
# indent-tabs-mode: nil
# c-indentation-style: bsd
# End:
# ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :