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