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   70088 use strict;
  133         175  
  133         3254  
3 133     133   459 use warnings;
  133         150  
  133         2424  
4 133     133   782 use Perl::Lint::Constants::Type;
  133         144  
  133         60243  
5 133     133   537 use parent "Perl::Lint::Policy";
  133         161  
  133         631  
6              
7             use constant {
8 133         79248 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   6746 };
  133         165  
11              
12             sub evaluate {
13 6     6 0 10 my ($class, $file, $tokens, $src, $args) = @_;
14              
15 6         6 my $forbid_use_version;
16 6 100       12 if (my $this_policies_arg = $args->{prohibit_complex_version}) {
17 1         4 $forbid_use_version = $this_policies_arg->{forbid_use_version};
18             }
19              
20 6         6 my @violations;
21 6         17 for (my $i = 0, my $token_type, my $token_data; my $token = $tokens->[$i]; $i++) {
22 370         247 $token_type = $token->{type};
23 370         236 $token_data = $token->{data};
24              
25 370 100 100     872 if ($token_type == OUR_DECL) {
    100          
26 72         56 $token = $tokens->[++$i];
27 72         42 $token_type = $token->{type};
28 72         52 $token_data = $token->{data};
29              
30 72         50 my $is_version_assigned = 0;
31              
32 72 100 66     244 if ($token_type == LEFT_PAREN) {
    50 33        
33 1         1 my $left_paren_num = 1;
34 1         2 for ($i++; $token = $tokens->[$i]; $i++) {
35 2         3 $token_type = $token->{type};
36 2         2 $token_data = $token->{data};
37 2 50 33     11 if ($token_type == LEFT_PAREN) {
    100 33        
    50          
38 0         0 $left_paren_num++;
39             }
40             elsif ($token_type == RIGHT_PAREN) {
41 1 50       2 if (--$left_paren_num <= 0) {
42 1         2 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       77 if ($is_version_assigned) {
61 72         45 $i++; # skip assign symbol
62              
63 72         51 $token = $tokens->[++$i];
64 72         51 $token_type = $token->{type};
65 72         54 $token_data = $token->{data};
66 72 100 100     301 if (
    100 66        
    100 66        
    100          
    100          
    100          
67             $token_type == VAR || $token_type == GLOBAL_VAR
68             ) {
69 11         15 my $next_token = $tokens->[$i+1];
70 11 100 100     61 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         37 description => DESC,
78             explanation => EXPL,
79             policy => __PACKAGE__,
80             };
81             }
82             }
83             elsif ($token_type == STRING) {
84 16 100       38 if ($token_data =~ /\A\$(?:\S+::)+\S+\Z/) {
85             push @violations, {
86             filename => $file,
87             line => $token->{line},
88 1         5 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       8 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         6 $token = $tokens->[++$i];
109 5 50       8 if ($token->{type} == NAMESPACE_RESOLVER) {
110             push @violations, {
111             filename => $file,
112             line => $token->{line},
113 5         16 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         15 for ($i++; $token = $tokens->[$i]; $i++) {
122 1487         833 $token_type = $token->{type};
123 1487 100       3074 if ($token_type == LEFT_PAREN) {
    100          
    100          
124 79         95 $left_paren_num++;
125             }
126             elsif ($token_type == RIGHT_PAREN) {
127 83 100       142 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         40 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         4 $token = $tokens->[++$i];
144 3 50       5 if ($token->{type} == LEFT_BRACE) {
145 3         2 my $left_brace_num = 1;
146 3         7 for ($i++; $token = $tokens->[$i]; $i++) {
147 33         21 $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         5 last;
154             }
155             }
156             elsif ($token_type == NAMESPACE_RESOLVER) {
157             push @violations, {
158             filename => $file,
159             line => $token->{line},
160 3         10 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       4 if ($forbid_use_version) {
172             push @violations, {
173             filename => $file,
174             line => $token->{line},
175 1         6 description => DESC,
176             explanation => EXPL,
177             policy => __PACKAGE__,
178             };
179             }
180             }
181             }
182              
183 6         24 return \@violations;
184             }
185              
186             1;
187