File Coverage

blib/lib/Perl/Lint/Policy/Modules/RequireFilenameMatchesPackage.pm
Criterion Covered Total %
statement 69 69 100.0
branch 31 32 96.8
condition 12 17 70.5
subroutine 6 6 100.0
pod 0 1 0.0
total 118 125 94.4


line stmt bran cond sub pod time code
1             package Perl::Lint::Policy::Modules::RequireFilenameMatchesPackage;
2 134     134   105220 use strict;
  134         1865  
  134         8279  
3 134     134   753 use warnings;
  134         961  
  134         4494  
4 134     134   1000 use Perl::Lint::Constants::Type;
  134         208  
  134         88532  
5 134     134   3294 use parent "Perl::Lint::Policy";
  134         3696  
  134         3178  
6              
7             use constant {
8 134         100442 DESC => 'Package declaration must match filename',
9             EXPL => 'Correct the filename or package statement',
10 134     134   8879 };
  134         4043  
11              
12             sub evaluate {
13 26     26 0 17018 my ($class, $realfile, $tokens, $src, $args) = @_;
14              
15 26 100       72 if ($src =~ /\A#!/) { # for exempt
16 1         3 return [];
17             }
18              
19             # Determine the filename with considering directive
20 25         45 my $file;
21 25         178 my @src_rows = split /\r?\n/, $src;
22 25         35 my $row = 0;
23 25         19 my $directive_declared_row = 0;
24 25         35 for my $src_row (@src_rows) {
25 101         64 $row++;
26 101 100       222 if ($src_row =~ /\A#line\s\d+\s(.+)\Z/) {
27 9 100       15 if ($file) {
28             return [{
29 1         8 filename => $realfile,
30             line => $row,
31             description => DESC,
32             explanation => EXPL,
33             policy => __PACKAGE__,
34             }];
35             }
36 8         23 ($file = $1) =~ s/['"]//g;
37 8         9 $directive_declared_row = $row;
38             }
39             }
40 24   66     75 $file ||= $realfile;
41              
42 24         19 my @violations;
43             my @paths;
44 24         66 for (my $i = 0, my $next_token, my $token_type, my $token_data; my $token = $tokens->[$i]; $i++) {
45 100         93 $next_token = $tokens->[$i+1];
46 100         79 $token_type = $token->{type};
47 100         96 $token_data = $token->{data};
48 100 100       235 if ($token_type == PACKAGE) {
49 24 100       39 if ($next_token->{type} == CLASS) {
50 8         21 push @paths, {
51             path => "$next_token->{data}",
52             line => $token->{line},
53             };
54 8         17 next;
55             }
56              
57 16         18 my $path = '';
58 16         33 for ($i++; my $token = $tokens->[$i]; $i++) {
59 68         55 my $token_type = $token->{type};
60 68 100       93 if ($token_type == NAMESPACE) {
    100          
61 34         69 $path .= $token->{data};
62             }
63             elsif ($token_type == NAMESPACE_RESOLVER) {
64 18         32 $path .= '/';
65             }
66             else {
67 16         40 push @paths, {
68             path => $path,
69             line => $token->{line},
70             };
71 16         42 last;
72             }
73             }
74             }
75             }
76              
77 24         29 for my $p (@paths) {
78 23         18 my $is_directive_declared_after = 0;
79 23         13 my $should_be_no_error = 0;
80              
81 23         23 my $path = $p->{path};
82 23         23 my $package_declared_line = $p->{line};
83              
84 23 100 100     57 if ($directive_declared_row && $package_declared_line < $directive_declared_row) {
85 1         1 $is_directive_declared_after = 1;
86             }
87              
88 23         18 my $last_path = @{[split(/\//, $path)]}[-1];
  23         59  
89 23         56 (my $module_name = $path) =~ s!/!-!;
90              
91 23 100 66     74 if ($path eq 'main' && !$is_directive_declared_after) {
    50          
92 2         3 last;
93             }
94             elsif (defined $file) {
95 21 100       185 if ($file !~ m!/!) {
    100          
    100          
    100          
96 8   50     6 my $last_path = @{[split(/\//, $path)]}[-1] || '';
97 8 100       77 if ($file =~ /$last_path\.p[ml]/) {
98 5         8 $should_be_no_error = 1;
99             }
100             }
101             elsif ($file =~ /$path\.p[ml]/) {
102 6         7 $should_be_no_error = 1;
103             }
104             elsif ($file =~ m!$module_name(?:-\d[\d\.]*?\d)?/$last_path!) {
105 2         4 $should_be_no_error = 1;
106             }
107             elsif ($file =~ m![A-Z]\w*-\d[\d\.]*\d/$last_path!) {
108 1         2 $should_be_no_error = 1;
109             }
110             }
111              
112 21 100 66     95 if (
      66        
113             !$should_be_no_error ||
114             ($should_be_no_error && $is_directive_declared_after)
115             ) {
116 8         38 push @violations, {
117             filename => $realfile,
118             line => $package_declared_line,
119             description => DESC,
120             explanation => EXPL,
121             policy => __PACKAGE__,
122             };
123             }
124             }
125              
126 24         90 return \@violations;
127             }
128              
129             1;
130