File Coverage

blib/lib/Perl/Lint/Policy/ValuesAndExpressions/ProhibitComplexVersion.pm
Criterion Covered Total %
statement 76 78 97.4
branch 51 60 85.0
condition 21 30 70.0
subroutine 6 6 100.0
pod 0 1 0.0
total 154 175 88.0


line stmt bran cond sub pod time code
1             package Perl::Lint::Policy::ValuesAndExpressions::ProhibitComplexVersion;
2 133     133   92810 use strict;
  133         251  
  133         4593  
3 133     133   587 use warnings;
  133         207  
  133         3083  
4 133     133   949 use Perl::Lint::Constants::Type;
  133         203  
  133         82370  
5 133     133   778 use parent "Perl::Lint::Policy";
  133         235  
  133         781  
6              
7             use constant {
8 133         113661 DESC => '$VERSION value should not come from outside module',
9             EXPL => 'If the version comes from outside the module, you can get everything from unexpected version changes to denial-of-service attacks.',
10 133     133   8655 };
  133         227  
11              
12             sub evaluate {
13 6     6 0 23 my ($class, $file, $tokens, $src, $args) = @_;
14              
15 6         11 my $forbid_use_version;
16 6 100       24 if (my $this_policies_arg = $args->{prohibit_complex_version}) {
17 1         5 $forbid_use_version = $this_policies_arg->{forbid_use_version};
18             }
19              
20 6         10 my @violations;
21 6         38 for (my $i = 0, my $token_type, my $token_data; my $token = $tokens->[$i]; $i++) {
22 370         602 $token_type = $token->{type};
23 370         517 $token_data = $token->{data};
24              
25 370 100 100     2017 if ($token_type == OUR_DECL) {
    100          
26 72         146 $token = $tokens->[++$i];
27 72         93 $token_type = $token->{type};
28 72         158 $token_data = $token->{data};
29              
30 72         110 my $is_version_assigned = 0;
31              
32 72 100 66     742 if ($token_type == LEFT_PAREN) {
    50 33        
33 1         3 my $left_paren_num = 1;
34 1         4 for ($i++; $token = $tokens->[$i]; $i++) {
35 2         4 $token_type = $token->{type};
36 2         4 $token_data = $token->{data};
37 2 50 33     19 if ($token_type == LEFT_PAREN) {
    100 33        
    50          
38 0         0 $left_paren_num++;
39             }
40             elsif ($token_type == RIGHT_PAREN) {
41 1 50       3 if (--$left_paren_num <= 0) {
42 1         3 last;
43             }
44             }
45             elsif (
46             ($token_type == VAR || $token_type == GLOBAL_VAR) &&
47             $token_data eq '$VERSION'
48             ) {
49 1         4 $is_version_assigned = 1;
50             }
51             }
52             }
53             elsif (
54             ($token_type == VAR || $token_type == GLOBAL_VAR) &&
55             $token_data eq '$VERSION'
56             ) {
57 71         117 $is_version_assigned = 1;
58             }
59              
60 72 50       146 if ($is_version_assigned) {
61 72         124 $i++; # skip assign symbol
62              
63 72         119 $token = $tokens->[++$i];
64 72         138 $token_type = $token->{type};
65 72         138 $token_data = $token->{data};
66 72 100 100     597 if (
    100 66        
    100 66        
    100          
    100          
    100          
67             $token_type == VAR || $token_type == GLOBAL_VAR
68             ) {
69 11         21 my $next_token = $tokens->[$i+1];
70 11 100 100     117 if (
      100        
71             ($token_data ne '$VERSION' && $token_data =~ /\A\$[A-Z0-9_]+\Z/) ||
72             $next_token->{type} == NAMESPACE_RESOLVER
73             ) {
74 9         75 push @violations, {
75             filename => $file,
76             line => $token->{line},
77             description => DESC,
78             explanation => EXPL,
79             policy => __PACKAGE__,
80             };
81             }
82             }
83             elsif ($token_type == STRING) {
84 16 100       112 if ($token_data =~ /\A\$(?:\S+::)+\S+\Z/) {
85 1         12 push @violations, {
86             filename => $file,
87             line => $token->{line},
88             description => DESC,
89             explanation => EXPL,
90             policy => __PACKAGE__,
91             };
92             }
93             }
94             elsif ($token_type == REG_DOUBLE_QUOTE) {
95 2         4 $i++; # skip reg delimiter
96 2         4 $token = $tokens->[++$i];
97 2 100       16 if ($token->{data} =~ /\A\$(?:\S+::)+\S+\Z/) {
98 1         9 push @violations, {
99             filename => $file,
100             line => $token->{line},
101             description => DESC,
102             explanation => EXPL,
103             policy => __PACKAGE__,
104             };
105             }
106             }
107             elsif ($token_type == NAMESPACE) {
108 5         9 $token = $tokens->[++$i];
109 5 50       15 if ($token->{type} == NAMESPACE_RESOLVER) {
110 5         39 push @violations, {
111             filename => $file,
112             line => $token->{line},
113             description => DESC,
114             explanation => EXPL,
115             policy => __PACKAGE__,
116             };
117             }
118             }
119             elsif ($token_type == LEFT_PAREN) {
120 9         13 my $left_paren_num = 1;
121 9         30 for ($i++; $token = $tokens->[$i]; $i++) {
122 1487         2389 $token_type = $token->{type};
123 1487 100       6736 if ($token_type == LEFT_PAREN) {
    100          
    100          
124 79         211 $left_paren_num++;
125             }
126             elsif ($token_type == RIGHT_PAREN) {
127 83 100       256 if (--$left_paren_num <= 0) {
128 8         29 last;
129             }
130             }
131             elsif ($token_type == NAMESPACE_RESOLVER) {
132 2         15 push @violations, {
133             filename => $file,
134             line => $token->{line},
135             description => DESC,
136             explanation => EXPL,
137             policy => __PACKAGE__,
138             };
139             }
140             }
141             }
142             elsif ($token_type == DO || ($token_type == BUILTIN_FUNC && $token_data eq 'eval')) {
143 3         8 $token = $tokens->[++$i];
144 3 50       9 if ($token->{type} == LEFT_BRACE) {
145 3         7 my $left_brace_num = 1;
146 3         12 for ($i++; $token = $tokens->[$i]; $i++) {
147 33         39 $token_type = $token->{type};
148 33 50       134 if ($token_type == LEFT_BRACE) {
    100          
    100          
149 0         0 $left_brace_num++;
150             }
151             elsif ($token_type == RIGHT_BRACE) {
152 3 50       10 if (--$left_brace_num <= 0) {
153 3         13 last;
154             }
155             }
156             elsif ($token_type == NAMESPACE_RESOLVER) {
157 3         22 push @violations, {
158             filename => $file,
159             line => $token->{line},
160             description => DESC,
161             explanation => EXPL,
162             policy => __PACKAGE__,
163             };
164             }
165             }
166             }
167             }
168             }
169             }
170             elsif ($token_type == USED_NAME && $token_data eq 'version') {
171 2 100       11 if ($forbid_use_version) {
172 1         14 push @violations, {
173             filename => $file,
174             line => $token->{line},
175             description => DESC,
176             explanation => EXPL,
177             policy => __PACKAGE__,
178             };
179             }
180             }
181             }
182              
183 6         62 return \@violations;
184             }
185              
186             1;
187