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   74458 use strict;
  134         171  
  134         3018  
3 134     134   420 use warnings;
  134         150  
  134         2406  
4 134     134   772 use Perl::Lint::Constants::Type;
  134         143  
  134         59974  
5 134     134   533 use parent "Perl::Lint::Policy";
  134         199  
  134         546  
6              
7             use constant {
8 134         72251 DESC => 'Package declaration must match filename',
9             EXPL => 'Correct the filename or package statement',
10 134     134   6397 };
  134         164  
11              
12             sub evaluate {
13 26     26 0 17774 my ($class, $realfile, $tokens, $src, $args) = @_;
14              
15 26 100       70 if ($src =~ /\A#!/) { # for exempt
16 1         2 return [];
17             }
18              
19             # Determine the filename with considering directive
20 25         14 my $file;
21 25         154 my @src_rows = split /\r?\n/, $src;
22 25         26 my $row = 0;
23 25         19 my $directive_declared_row = 0;
24 25         31 for my $src_row (@src_rows) {
25 101         60 $row++;
26 101 100       185 if ($src_row =~ /\A#line\s\d+\s(.+)\Z/) {
27 9 100       11 if ($file) {
28             return [{
29 1         6 filename => $realfile,
30             line => $row,
31             description => DESC,
32             explanation => EXPL,
33             policy => __PACKAGE__,
34             }];
35             }
36 8         20 ($file = $1) =~ s/['"]//g;
37 8         9 $directive_declared_row = $row;
38             }
39             }
40 24   66     63 $file ||= $realfile;
41              
42 24         18 my @violations;
43             my @paths;
44 24         56 for (my $i = 0, my $next_token, my $token_type, my $token_data; my $token = $tokens->[$i]; $i++) {
45 100         91 $next_token = $tokens->[$i+1];
46 100         59 $token_type = $token->{type};
47 100         66 $token_data = $token->{data};
48 100 100       195 if ($token_type == PACKAGE) {
49 24 100       31 if ($next_token->{type} == CLASS) {
50             push @paths, {
51             path => "$next_token->{data}",
52             line => $token->{line},
53 8         18 };
54 8         17 next;
55             }
56              
57 16         14 my $path = '';
58 16         24 for ($i++; my $token = $tokens->[$i]; $i++) {
59 68         54 my $token_type = $token->{type};
60 68 100       79 if ($token_type == NAMESPACE) {
    100          
61 34         60 $path .= $token->{data};
62             }
63             elsif ($token_type == NAMESPACE_RESOLVER) {
64 18         27 $path .= '/';
65             }
66             else {
67             push @paths, {
68             path => $path,
69             line => $token->{line},
70 16         36 };
71 16         35 last;
72             }
73             }
74             }
75             }
76              
77 24         22 for my $p (@paths) {
78 23         24 my $is_directive_declared_after = 0;
79 23         17 my $should_be_no_error = 0;
80              
81 23         18 my $path = $p->{path};
82 23         17 my $package_declared_line = $p->{line};
83              
84 23 100 100     55 if ($directive_declared_row && $package_declared_line < $directive_declared_row) {
85 1         1 $is_directive_declared_after = 1;
86             }
87              
88 23         16 my $last_path = @{[split(/\//, $path)]}[-1];
  23         97  
89 23         53 (my $module_name = $path) =~ s!/!-!;
90              
91 23 100 66     68 if ($path eq 'main' && !$is_directive_declared_after) {
    50          
92 2         2 last;
93             }
94             elsif (defined $file) {
95 21 100       156 if ($file !~ m!/!) {
    100          
    100          
    100          
96 8   50     3 my $last_path = @{[split(/\//, $path)]}[-1] || '';
97 8 100       70 if ($file =~ /$last_path\.p[ml]/) {
98 5         6 $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         3 $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     84 if (
      66        
113             !$should_be_no_error ||
114             ($should_be_no_error && $is_directive_declared_after)
115             ) {
116 8         30 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         76 return \@violations;
127             }
128              
129             1;
130