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   70802 use strict;
  133         186  
  133         3035  
3 133     133   409 use warnings;
  133         149  
  133         2337  
4 133     133   755 use Perl::Lint::Constants::Type;
  133         138  
  133         59100  
5 133     133   564 use parent "Perl::Lint::Policy";
  133         157  
  133         549  
6              
7             use constant {
8 133         79270 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   6892 };
  133         170  
11              
12             sub evaluate {
13 6     6 0 15 my ($class, $file, $tokens, $src, $args) = @_;
14              
15 6         6 my $forbid_use_version;
16 6 100       15 if (my $this_policies_arg = $args->{prohibit_complex_version}) {
17 1         3 $forbid_use_version = $this_policies_arg->{forbid_use_version};
18             }
19              
20 6         9 my @violations;
21 6         25 for (my $i = 0, my $token_type, my $token_data; my $token = $tokens->[$i]; $i++) {
22 370         241 $token_type = $token->{type};
23 370         265 $token_data = $token->{data};
24              
25 370 100 100     956 if ($token_type == OUR_DECL) {
    100          
26 72         57 $token = $tokens->[++$i];
27 72         47 $token_type = $token->{type};
28 72         61 $token_data = $token->{data};
29              
30 72         44 my $is_version_assigned = 0;
31              
32 72 100 66     277 if ($token_type == LEFT_PAREN) {
    50 33        
33 1         2 my $left_paren_num = 1;
34 1         5 for ($i++; $token = $tokens->[$i]; $i++) {
35 2         1 $token_type = $token->{type};
36 2         2 $token_data = $token->{data};
37 2 50 33     12 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         1 last;
43             }
44             }
45             elsif (
46             ($token_type == VAR || $token_type == GLOBAL_VAR) &&
47             $token_data eq '$VERSION'
48             ) {
49 1         3 $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         48 $is_version_assigned = 1;
58             }
59              
60 72 50       93 if ($is_version_assigned) {
61 72         43 $i++; # skip assign symbol
62              
63 72         61 $token = $tokens->[++$i];
64 72         54 $token_type = $token->{type};
65 72         61 $token_data = $token->{data};
66 72 100 100     349 if (
    100 66        
    100 66        
    100          
    100          
    100          
67             $token_type == VAR || $token_type == GLOBAL_VAR
68             ) {
69 11         16 my $next_token = $tokens->[$i+1];
70 11 100 100     72 if (
      100        
71             ($token_data ne '$VERSION' && $token_data =~ /\A\$[A-Z0-9_]+\Z/) ||
72             $next_token->{type} == NAMESPACE_RESOLVER
73             ) {
74             push @violations, {
75             filename => $file,
76             line => $token->{line},
77 9         52 description => DESC,
78             explanation => EXPL,
79             policy => __PACKAGE__,
80             };
81             }
82             }
83             elsif ($token_type == STRING) {
84 16 100       42 if ($token_data =~ /\A\$(?:\S+::)+\S+\Z/) {
85             push @violations, {
86             filename => $file,
87             line => $token->{line},
88 1         6 description => DESC,
89             explanation => EXPL,
90             policy => __PACKAGE__,
91             };
92             }
93             }
94             elsif ($token_type == REG_DOUBLE_QUOTE) {
95 2         2 $i++; # skip reg delimiter
96 2         2 $token = $tokens->[++$i];
97 2 100       10 if ($token->{data} =~ /\A\$(?:\S+::)+\S+\Z/) {
98             push @violations, {
99             filename => $file,
100             line => $token->{line},
101 1         5 description => DESC,
102             explanation => EXPL,
103             policy => __PACKAGE__,
104             };
105             }
106             }
107             elsif ($token_type == NAMESPACE) {
108 5         7 $token = $tokens->[++$i];
109 5 50       11 if ($token->{type} == NAMESPACE_RESOLVER) {
110             push @violations, {
111             filename => $file,
112             line => $token->{line},
113 5         21 description => DESC,
114             explanation => EXPL,
115             policy => __PACKAGE__,
116             };
117             }
118             }
119             elsif ($token_type == LEFT_PAREN) {
120 9         7 my $left_paren_num = 1;
121 9         18 for ($i++; $token = $tokens->[$i]; $i++) {
122 1487         896 $token_type = $token->{type};
123 1487 100       3147 if ($token_type == LEFT_PAREN) {
    100          
    100          
124 79         95 $left_paren_num++;
125             }
126             elsif ($token_type == RIGHT_PAREN) {
127 83 100       147 if (--$left_paren_num <= 0) {
128 8         16 last;
129             }
130             }
131             elsif ($token_type == NAMESPACE_RESOLVER) {
132             push @violations, {
133             filename => $file,
134             line => $token->{line},
135 2         13 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         5 $token = $tokens->[++$i];
144 3 50       6 if ($token->{type} == LEFT_BRACE) {
145 3         4 my $left_brace_num = 1;
146 3         9 for ($i++; $token = $tokens->[$i]; $i++) {
147 33         23 $token_type = $token->{type};
148 33 50       74 if ($token_type == LEFT_BRACE) {
    100          
    100          
149 0         0 $left_brace_num++;
150             }
151             elsif ($token_type == RIGHT_BRACE) {
152 3 50       6 if (--$left_brace_num <= 0) {
153 3         6 last;
154             }
155             }
156             elsif ($token_type == NAMESPACE_RESOLVER) {
157             push @violations, {
158             filename => $file,
159             line => $token->{line},
160 3         11 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       5 if ($forbid_use_version) {
172             push @violations, {
173             filename => $file,
174             line => $token->{line},
175 1         8 description => DESC,
176             explanation => EXPL,
177             policy => __PACKAGE__,
178             };
179             }
180             }
181             }
182              
183 6         26 return \@violations;
184             }
185              
186             1;
187