File Coverage

blib/lib/Perl/Critic/Policy/TooMuchCode/ProhibitDuplicateSub.pm
Criterion Covered Total %
statement 32 33 96.9
branch 8 10 80.0
condition 3 5 60.0
subroutine 7 8 87.5
pod 4 4 100.0
total 54 60 90.0


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::TooMuchCode::ProhibitDuplicateSub;
2 4     4   848695 use strict;
  4         35  
  4         132  
3 4     4   24 use warnings;
  4         12  
  4         104  
4 4     4   20 use Perl::Critic::Utils;
  4         10  
  4         68  
5 4     4   3571 use parent 'Perl::Critic::Policy';
  4         43  
  4         57  
6              
7 0     0 1 0 sub default_themes { return qw( bugs maintenance ) }
8 5     5 1 54612 sub applies_to { return 'PPI::Document' }
9              
10             sub initialize_if_enabled {
11 5     5 1 44195 my ($self, $config) = @_;
12              
13             $self->{_allow_duplicates_for} = {
14 5         42 BEGIN => 1,
15             UNITCHECK => 1,
16             CHECK => 1,
17             INIT => 1,
18             END => 1,
19             };
20              
21 5         21 return $TRUE;
22             }
23              
24             sub violates {
25 5     5 1 57 my ($self, undef, $doc) = @_;
26 5   100     17 my $packages = $doc->find('PPI::Statement::Package') || [];
27 5 100       134 if (@$packages > 1) {
28 2         6 return ();
29             }
30              
31 3 50       14 my $subdefs = $doc->find('PPI::Statement::Sub') or return;
32              
33 3         43 my %seen;
34             my @duplicates;
35 3         10 for my $sub (@$subdefs) {
36 15 50 33     359 next if $sub->forward || (! $sub->name);
37 15 100       778 next if $self->{_allow_duplicates_for}{$sub->name};
38              
39 5 100       247 if (exists $seen{ $sub->name }) {
40 1         45 push @duplicates, $seen{ $sub->name };
41             }
42 5         225 $seen{ $sub->name } = $sub;
43             }
44              
45             my @violations = map {
46 3         109 my $last_sub = $seen{ $_->name };
  1         4  
47              
48 1         52 $self->violation(
49             "Duplicate subroutine definition. Redefined at line: " . $last_sub->line_number . ", column: " . $last_sub->column_number,
50             "Another subroutine definition latter in the same scope with identical name masks this one.",
51             $_,
52             );
53             } @duplicates;
54              
55 3         359 return @violations;
56             }
57              
58             1;
59              
60             =encoding utf-8
61              
62             =head1 NAME
63              
64             TooMuchCode::ProhibitDuplicateSub - When 2 subroutines are defined with the same name, report the first one.
65              
66             =head1 DESCRIPTION
67              
68             This policy checks if there are subroutine definitions with identical names
69             under the same namespace. If they exists, all but the last one are marked as
70             violation.
71              
72             perl runtime allows a named subroutine to be redefined in the same source file
73             and the latest definition wins. In the event that this is done by developers,
74             preferably unintentionally, perl runtime warns about a subroutine is
75             redefined with the position is for the one that wins. This policy does the
76             opposite.
77              
78             Although the last one is not marked as a violation, it's position is
79             reported together. Making it easier for developer to locate the subroutine.
80              
81             Should the developer decide to programmatically remove the duplicates,
82             simply go through all the violations and remove those statements.
83              
84             =cut