Benchmark-Perl-Formance-Cargo
view release on metacpan or search on metacpan
share/PerlCritic/Critic/Policy/RegularExpressions/ProhibitCaptureWithoutTest.pm view on Meta::CPAN
##############################################################################
# $URL: http://perlcritic.tigris.org/svn/perlcritic/trunk/distributions/Perl-Critic/lib/Perl/Critic/Policy/RegularExpressions/ProhibitCaptureWithoutTest.pm $
# $Date: 2010-06-22 16:14:07 -0400 (Tue, 22 Jun 2010) $
# $Author: clonezone $
# $Revision: 3843 $
##############################################################################
package # hide from indexer
Perl::Critic::Policy::RegularExpressions::ProhibitCaptureWithoutTest;
use 5.006001;
use strict;
use warnings;
use Readonly;
use Perl::Critic::Utils qw{ :booleans :data_conversion :severities };
use base 'Perl::Critic::Policy';
our $VERSION = '1.108';
#-----------------------------------------------------------------------------
Readonly::Hash my %CONDITIONAL_OPERATOR => hashify( qw{ && || ? and or xor } );
Readonly::Hash my %UNAMBIGUOUS_CONTROL_TRANSFER => hashify(
qw< next last redo return > );
Readonly::Scalar my $DESC => q{Capture variable used outside conditional};
Readonly::Scalar my $EXPL => [ 253 ];
#-----------------------------------------------------------------------------
sub supported_parameters { return (
{
name => 'exception_source',
description => 'Names of ways to generate exceptions',
behavior => 'string list',
list_always_present_values => [ qw{ die croak confess } ],
}
);
}
sub default_severity { return $SEVERITY_MEDIUM }
sub default_themes { return qw(core pbp maintenance) }
sub applies_to { return 'PPI::Token::Magic' }
#-----------------------------------------------------------------------------
sub violates {
my ($self, $elem, $doc) = @_;
# TODO named capture variables
return if $elem !~ m/\A \$[1-9] \z/xms;
return if _is_in_conditional_expression($elem);
return if $self->_is_in_conditional_structure($elem);
return $self->violation( $DESC, $EXPL, $elem );
}
sub _is_in_conditional_expression {
my $elem = shift;
# simplistic check: is there a conditional operator between a match and
# the capture var?
my $psib = $elem->sprevious_sibling;
while ($psib) {
if ($psib->isa('PPI::Token::Operator')) {
my $op = $psib->content;
if ( $CONDITIONAL_OPERATOR{ $op } ) {
$psib = $psib->sprevious_sibling;
while ($psib) {
return 1 if ($psib->isa('PPI::Token::Regexp::Match'));
return 1 if ($psib->isa('PPI::Token::Regexp::Substitute'));
$psib = $psib->sprevious_sibling;
}
return; # false
}
}
$psib = $psib->sprevious_sibling;
}
return; # false
}
sub _is_in_conditional_structure {
my ( $self, $elem ) = @_;
my $stmt = $elem->statement();
while ($stmt && $elem->isa('PPI::Statement::Expression')) {
#return if _is_in_conditional_expression($stmt);
$stmt = $stmt->statement();
}
return if !$stmt;
# Check if any previous statements in the same scope have regexp matches
my $psib = $stmt->sprevious_sibling;
while ($psib) {
if ( $psib->isa( 'PPI::Node' ) and
my $match = _find_exposed_match_or_substitute( $psib ) ) {
return _is_control_transfer_to_left( $self, $match, $elem ) ||
_is_control_transfer_to_right( $self, $match, $elem );
}
$psib = $psib->sprevious_sibling;
}
# Check for an enclosing 'if', 'unless', 'elsif', 'else', or 'when'
my $parent = $stmt->parent;
while ($parent) { # never false as long as we're inside a PPI::Document
if ($parent->isa('PPI::Statement::Compound') ||
$parent->isa('PPI::Statement::When' )
) {
return 1;
}
elsif ($parent->isa('PPI::Structure')) {
( run in 4.311 seconds using v1.01-cache-2.11-cpan-5735350b133 )