File Coverage

blib/lib/Perl/Critic/Policy/CognitiveComplexity/ProhibitExcessCognitiveComplexity.pm
Criterion Covered Total %
statement 58 59 98.3
branch 19 20 95.0
condition 12 12 100.0
subroutine 17 18 94.4
pod 4 9 44.4
total 110 118 93.2


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::CognitiveComplexity::ProhibitExcessCognitiveComplexity;
2 8     8   1129244 use strict;
  8         10  
  8         186  
3 8     8   37 use warnings;
  8         11  
  8         165  
4              
5 8     8   550 use Readonly;
  8         2965  
  8         349  
6 8     8   34 use Readonly qw (Scalar);
  8         17  
  8         339  
7 8     8   691 use Perl::Critic::Utils qw{ :severities :classification :ppi };
  8         125059  
  8         492  
8 8     8   6660 use Perl::Critic::Violation;
  8         108165  
  8         268  
9 8     8   69 use base 'Perl::Critic::Policy';
  8         11  
  8         4429  
10              
11             our $VERSION = '0.02';
12              
13             Scalar my $EXPL => q{Avoid code that is nested, and thus difficult to grasp.};
14              
15             sub supported_parameters {
16             return ( {
17 7     7 0 50508 name => 'warn_level',
18             description => 'The complexity score allowed before warning starts.',
19             default_string => '10',
20             behavior => 'integer',
21             integer_minimum => 1,
22             },
23             {
24             name => 'info_level',
25             description => 'The complexity score allowed before informational reporting starts.',
26             default_string => '1',
27             behavior => 'integer',
28             integer_minimum => 1,
29             }
30             );
31             }
32              
33             sub default_severity {
34 1     1 1 12 return $SEVERITY_MEDIUM;
35             }
36              
37             sub default_themes {
38 0     0 1 0 return qw( complexity maintenance );
39             }
40              
41             sub applies_to {
42 7     7 1 64261 return 'PPI::Statement::Sub';
43             }
44              
45             sub violates {
46 7     7 1 127 my ( $self, $elem, undef ) = @_;
47              
48             # only report complexity for named subs.
49 7 50       33 my $name = $elem->name() or return;
50              
51             # start with complexity of 0
52 7         184 my $block = $elem->find_first('PPI::Structure::Block');
53 7         1883 my $score = $self->nested_complexity($block , 0);
54              
55 7 100       35 return if($score < $self->{'_info_level'});
56 5         14 return ($self->new_violation($elem, $score));
57             }
58              
59             sub new_violation {
60 5     5 0 8 my $self = shift;
61 5         9 my ($elem, $score) = @_;
62 5         17 my $name = $elem->name();
63 5         95 my $desc = qq<Subroutine '$name' with complexity score of '$score'>;
64              
65             return Perl::Critic::Violation->new( $desc, $EXPL, $elem,
66 5 100       72 ($score >= $self->{'_warn_level'} ? $self->get_severity() : $SEVERITY_LOWEST ));
67             }
68              
69             sub nested_complexity {
70 194     194 0 161 my $self = shift;
71 194         157 my ( $elem, $nesting ) = @_;
72              
73 194 100       735 return 0 unless ( $elem->can('schildren') );
74              
75 78         79 my $complexity = 0;
76              
77 78         112 for my $child ( $elem->schildren() ) {
78             #my $inc = 0;
79 187 100 100     2156 if ( $child->isa('PPI::Structure::Given')
    100 100        
      100        
80             || $child->isa('PPI::Structure::Condition')
81             || $child->isa('PPI::Structure::For')
82             )
83             {
84 11 100       92 if($self->nesting_increase($child->parent)) {
85 7         11 $complexity += $nesting;
86             } else {
87             # missing compound statement / increment on postfix operators
88 4         4 $complexity += $nesting + 1;
89             }
90             }
91             # 'return' is a break-statement, but does not count in terms of cognitive complexity.
92             elsif ( $child->isa('PPI::Statement::Break') && ! $self->is_return_statement($child)) {
93 1         11 $complexity++;
94             }
95 187         336 $complexity += $self->nested_complexity( $child, $nesting + $self->nesting_increase($child) );
96             }
97 78         112 return $complexity;
98             }
99              
100             sub is_return_statement {
101 6     6 0 9 my $self = shift;
102 6         8 my ($child) = @_;
103 6     22   27 scalar $child->find( sub { $_[1]->content eq 'return' });
  22         179  
104             }
105              
106             sub nesting_increase {
107 198     198 0 200 my $self = shift;
108 198         159 my ($child) = @_;
109              
110             # if/when/for...
111 198 100       493 return 1 if ($child->isa('PPI::Statement::Compound'));
112 186 100       401 return 1 if ($child->isa('PPI::Statement::Given'));
113             # anonymous sub
114 184 100 100 366   546 return 1 if ($child->isa('PPI::Statement') && $child->find( sub { $_[1]->content eq 'sub' }));
  366         3422  
115              
116 183         711 return 0;
117             }
118              
119             1;