File Coverage

blib/lib/Perl/Lint/Policy/Subroutines/ProtectPrivateSubs.pm
Criterion Covered Total %
statement 54 54 100.0
branch 22 22 100.0
condition 44 52 84.6
subroutine 6 6 100.0
pod 0 1 0.0
total 126 135 93.3


line stmt bran cond sub pod time code
1             package Perl::Lint::Policy::Subroutines::ProtectPrivateSubs;
2 133     133   93742 use strict;
  133         323  
  133         5017  
3 133     133   659 use warnings;
  133         228  
  133         3281  
4 133     133   1030 use Perl::Lint::Constants::Type;
  133         242  
  133         82553  
5 133     133   841 use parent "Perl::Lint::Policy";
  133         255  
  133         819  
6              
7             use constant {
8 133         74875 DESC => 'Private subroutine/method used',
9             EXPL => 'Use published APIs',
10 133     133   8767 };
  133         259  
11              
12             sub evaluate {
13 12     12 0 33 my ($class, $file, $tokens, $src, $args) = @_;
14              
15 12         29 my @allows = ();
16 12   100     115 for my $allow (split(/ /, $args->{protect_private_subs}->{allow} || '')) {
17 3         9 my @name_spaces = split /::/, $allow;
18 3         5 my $method_name = pop @name_spaces;
19 3         13 push @allows, +{
20             package_name => join('::', @name_spaces),
21             method_name => $method_name,
22             };
23             }
24 12   100     75 my $private_name_regex = $args->{protect_private_subs}->{private_name_regex} || '';
25              
26 12         20 my @violations;
27 12         29 my $module_name = '';
28 12         59 TOP: for (my $i = 0; my $token = $tokens->[$i]; $i++) {
29 380         328 my $token_type = $token->{type};
30 380         321 my $token_data = $token->{data};
31              
32 380 100 100     4659 if ($token_type == POINTER || $token_type == NAMESPACE_RESOLVER) {
    100 100        
    100 100        
    100 66        
    100 100        
    100 66        
      100        
      66        
      66        
      66        
      66        
33 54         52 my $delimiter = $token_data;
34              
35 54         52 $token = $tokens->[++$i];
36 54         63 $token_data = $token->{data};
37 54         67 my $next_token = $tokens->[$i+1];
38 54         54 my $next_token_type = $next_token->{type};
39 54 100 100     220 if (
      66        
40             substr($token_data, 0, 1) eq '_' &&
41             $next_token_type != POINTER &&
42             $next_token_type != NAMESPACE_RESOLVER
43             ) {
44 27         41 for my $allow (@allows) {
45 9 100 66     32 if (
46             $allow->{package_name} eq $module_name &&
47             $allow->{method_name} eq $token_data
48             ) {
49 5         12 next TOP;
50             }
51             }
52              
53 22 100 100     155 if ($private_name_regex && $token_data =~ /$private_name_regex/) {
54 5         12 next;
55             }
56              
57 17         77 push @violations, {
58             filename => $file,
59             line => $token->{line},
60             description => DESC,
61             explanation => EXPL,
62             policy => __PACKAGE__,
63             };
64 17         40 $module_name = '';
65             }
66             else {
67 27         66 $module_name .= $delimiter . $token_data;
68             }
69             }
70             elsif (
71             $token_type == USE_DECL ||
72             $token_type == REQUIRE_DECL ||
73             $token_type == PACKAGE
74             ) {
75 3         9 for ($i++; $token = $tokens->[$i]; $i++) {
76 18         16 $token_type = $token->{type};
77 18 100       37 if ($token_type == SEMI_COLON) {
78 3         9 last;
79             }
80             }
81             }
82             elsif (
83             ($token_type == SPECIFIC_KEYWORD && $token_data eq '__PACKAGE__') ||
84             ($token_type == BUILTIN_FUNC && $token_data eq 'shift') ||
85             ($token_type == NAMESPACE && $token_data eq 'POSIX')
86             ) {
87 43         74 $i++; # skip target func
88             }
89             elsif ($token_type == NAMESPACE) {
90 67         138 $module_name .= $token_data;
91             }
92             elsif (
93             (
94             $token_type == VAR ||
95             $token_type == GLOBAL_VAR ||
96             $token_type == LOCAL_VAR
97             ) && ($token_data eq '$pkg' || $token_data eq '$self')
98             ) {
99 8         13 $i++;
100 8         16 my $next_token = $tokens->[$i+1];
101 8 100 100     41 if ($next_token->{type} == NAMESPACE && $next_token->{data} eq 'SUPER') {
102 1         3 $i += 2;
103             }
104             }
105             elsif ($token_type == SEMI_COLON) {
106 74         145 $module_name = '';
107             }
108             }
109              
110 12         74 return \@violations;
111             }
112              
113             1;
114