Build all packages removed dependencies of libtest-exception-perl libtest-warn-perl...
[dh-make-perl] / dev / i386 / libperl-critic-perl / libperl-critic-perl-1.088 / lib / Perl / Critic / Policy / Variables / RequireNegativeIndices.pm
diff --git a/dev/i386/libperl-critic-perl/libperl-critic-perl-1.088/lib/Perl/Critic/Policy/Variables/RequireNegativeIndices.pm b/dev/i386/libperl-critic-perl/libperl-critic-perl-1.088/lib/Perl/Critic/Policy/Variables/RequireNegativeIndices.pm
new file mode 100644 (file)
index 0000000..b8d36d0
--- /dev/null
@@ -0,0 +1,254 @@
+##############################################################################
+#      $URL: http://perlcritic.tigris.org/svn/perlcritic/trunk/Perl-Critic/lib/Perl/Critic/Policy/Variables/RequireNegativeIndices.pm $
+#     $Date: 2008-07-03 10:19:10 -0500 (Thu, 03 Jul 2008) $
+#   $Author: clonezone $
+# $Revision: 2489 $
+##############################################################################
+
+package Perl::Critic::Policy::Variables::RequireNegativeIndices;
+
+use 5.006001;
+use strict;
+use warnings;
+use Readonly;
+
+use Perl::Critic::Utils qw{ :severities };
+use base 'Perl::Critic::Policy';
+
+our $VERSION = '1.088';
+
+#-----------------------------------------------------------------------------
+
+Readonly::Scalar my $DESC => q{Negative array index should be used};
+Readonly::Scalar my $EXPL => [ 88 ];
+
+#-----------------------------------------------------------------------------
+
+sub supported_parameters { return ()                          }
+sub default_severity     { return $SEVERITY_HIGH              }
+sub default_themes       { return qw( core maintenance pbp )  }
+sub applies_to           { return 'PPI::Structure::Subscript' }
+
+#-----------------------------------------------------------------------------
+
+sub violates {
+    my ( $self, $elem, $doc ) = @_;
+
+    return if $elem->braces ne '[]';
+    my ($name, $isref) = _is_bad_index( $elem );
+    return if ( !$name );
+    return if !_is_array_name( $elem, $name, $isref );
+    return $self->violation( $DESC, $EXPL, $elem );
+}
+
+Readonly::Scalar my $MAX_EXPRESSION_COMPLEXETY => 4;
+
+sub _is_bad_index {
+    # return (varname, 0|1) if this could be a violation
+    my ( $elem ) = @_;
+
+    my @children = $elem->schildren();
+    return if @children != 1; # too complex
+    return if !$children[0]->isa( 'PPI::Statement::Expression'); # too complex
+
+    # This is the expression elements that compose the array indexing
+    my @expr = $children[0]->schildren();
+    return if !@expr || @expr > $MAX_EXPRESSION_COMPLEXETY;
+    my ($name, $isref, $isindex) = _is_bad_var_in_index(\@expr);
+    return if !$name;
+    return $name, $isref if !@expr && $isindex;
+    return if !_is_minus_number(@expr);
+    return $name, $isref;
+}
+
+sub _is_bad_var_in_index {
+    # return (varname, isref=0|1, isindex=0|1) if this could be a violation
+    my ( $expr ) = @_;
+
+    if ( $expr->[0]->isa('PPI::Token::ArrayIndex') ) {
+        # [$#arr]
+        return _arrayindex($expr);
+    }
+    elsif ( $expr->[0]->isa('PPI::Token::Cast') ) {
+        # [$#{$arr} ...] or [$#$arr ...] or [@{$arr} ...] or [@$arr ...]
+        return _cast($expr);
+    }
+    elsif ($expr->[0]->isa('PPI::Token::Symbol')) {
+        # [@arr ...]
+        return _symbol($expr);
+    }
+
+    return;
+}
+
+sub _arrayindex {
+    # return (varname, isref=0|1, isindex=0|1) if this could be a violation
+    my ( $expr ) = @_;
+    my $arrindex = shift @{$expr};
+    if ($arrindex->content =~ m/\A \$[#] (.*) \z /xms) { # What else could it be???
+       return $1, 0, 1;
+    }
+    return;
+}
+
+sub _cast {
+    # return (varname, isref=0|1, isindex=0|1) if this could be a violation
+    my ( $expr ) = @_;
+    my $cast = shift @{$expr};
+    if ( $cast eq q{$#} || $cast eq q{@} ) { ## no critic(RequireInterpolationOfMetachars)
+        my $isindex = $cast eq q{$#} ? 1 : 0;  ## no critic(RequireInterpolationOfMetachars)
+        my $arrvar = shift @{$expr};
+        if ($arrvar->isa('PPI::Structure::Block')) {
+            # look for [$#{$arr} ...] or [@{$arr} ...]
+            my @blockchildren = $arrvar->schildren();
+            return if @blockchildren != 1;
+            return if !$blockchildren[0]->isa('PPI::Statement');
+            my @ggg = $blockchildren[0]->schildren;
+            return if @ggg != 1;
+            return if !$ggg[0]->isa('PPI::Token::Symbol');
+            if ($ggg[0] =~ m/\A \$ (.*) \z/xms) {
+                return $1, 1, $isindex;
+            }
+        }
+        elsif ( $arrvar->isa('PPI::Token::Symbol') ) {
+           # look for [$#$arr ...] or [@$arr ...]
+           if ($arrvar =~ m/\A \$ (.*) \z/xms) {
+              return $1, 1, $isindex;
+           }
+        }
+    }
+    return;
+}
+
+sub _symbol {
+    # return (varname, isref=0|1, isindex=0|1) if this could be a violation
+    my ( $expr ) = @_;
+    my $arrvar = shift @{$expr};
+    if ($arrvar =~ m/\A \@ (.*) \z/xms) {
+       return $1, 0, 0;
+    }
+    return;
+}
+
+sub _is_minus_number {  # return true if @expr looks like "- n"
+    my @expr = @_;
+
+    return if !@expr;
+
+    return if @expr != 2;
+
+    my $op = shift @expr;
+    return if !$op->isa('PPI::Token::Operator');
+    return if $op ne q{-};
+
+    my $number = shift @expr;
+    return if !$number->isa('PPI::Token::Number');
+
+    return 1;
+}
+
+sub _is_array_name {  # return true if name and isref matches
+    my ( $elem, $name, $isref ) = @_;
+
+    my $sib = $elem->sprevious_sibling;
+    return if !$sib;
+
+    if ($sib->isa('PPI::Token::Operator') && $sib eq '->') {
+        return if ( !$isref );
+        $isref = 0;
+        $sib = $sib->sprevious_sibling;
+        return if !$sib;
+    }
+
+    return if !$sib->isa('PPI::Token::Symbol');
+    return if $sib !~ m/\A \$ \Q$name\E \z/xms;
+
+    my $cousin = $sib->sprevious_sibling;
+    return if $isref ^ _is_dereferencer( $cousin );
+    return if $isref && _is_dereferencer( $cousin->sprevious_sibling );
+
+    return $elem;
+}
+
+sub _is_dereferencer { # must return 0 or 1, not undef
+    my $elem = shift;
+
+    return 0 if !$elem;
+    return 1 if $elem->isa('PPI::Token::Operator') && $elem eq '->';
+    return 1 if $elem->isa('PPI::Token::Cast');
+    return 0;
+}
+
+1;
+
+#-----------------------------------------------------------------------------
+
+__END__
+
+=pod
+
+=for stopwords performant
+
+=head1 NAME
+
+Perl::Critic::Policy::Variables::RequireNegativeIndices - Negative array index should be used.
+
+=head1 AFFILIATION
+
+This Policy is part of the core L<Perl::Critic> distribution.
+
+
+=head1 DESCRIPTION
+
+Conway points out that
+
+  $arr[$#arr];
+  $arr[$#arr-1];
+  $arr[@arr-1];
+  $arr[@arr-2];
+
+are equivalent to
+
+  $arr[-1];
+  $arr[-2];
+  $arr[-1];
+  $arr[-2];
+
+and the latter are more readable, performant and maintainable.  The
+latter is because the programmer no longer needs to keep two variable
+names matched.
+
+This policy notices all of the simple forms of the above problem, but
+does not recognize any of these more complex examples:
+
+   $some->[$data_structure]->[$#{$some->[$data_structure]} -1];
+   my $ref = \@arr;
+   $ref->[$#arr];
+
+
+=head1 CONFIGURATION
+
+This Policy is not configurable except for the standard options.
+
+
+=head1 AUTHOR
+
+Chris Dolan <cdolan@cpan.org>
+
+=head1 COPYRIGHT
+
+Copyright (C) 2006 Chris Dolan.  All rights reserved.
+
+This program is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself.
+
+=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 :