Filename | /Users/timbo/perl5/perlbrew/perls/perl-5.18.2/lib/site_perl/5.18.2/Perl/Critic/Policy/Subroutines/RequireFinalReturn.pm |
Statements | Executed 20 statements in 1.02ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 16µs | 16µs | BEGIN@10 | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
1 | 1 | 1 | 14µs | 16µs | supported_parameters | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
1 | 1 | 1 | 8µs | 28µs | BEGIN@15 | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
1 | 1 | 1 | 8µs | 12µs | BEGIN@12 | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
1 | 1 | 1 | 8µs | 61µs | BEGIN@17 | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
1 | 1 | 1 | 8µs | 28µs | BEGIN@13 | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
1 | 1 | 1 | 7µs | 425µs | BEGIN@16 | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
1 | 1 | 1 | 7µs | 18µs | BEGIN@11 | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
1 | 1 | 1 | 6µs | 7µs | default_severity | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | _block_has_return | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | _block_is_empty | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | _is_compound_return | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | _is_conditional_stmnt | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | _is_explicit_return | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | _is_given_when_return | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | _is_return_or_goto_stmnt | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | _is_suffix_when_with_return | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | _is_terminal_stmnt | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | _is_when_stmnt_with_return | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | applies_to | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | default_themes | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
0 | 0 | 0 | 0s | 0s | violates | Perl::Critic::Policy::Subroutines::RequireFinalReturn::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | ############################################################################## | ||||
2 | # $URL$ | ||||
3 | # $Date$ | ||||
4 | # $Author$ | ||||
5 | # $Revision$ | ||||
6 | ############################################################################## | ||||
7 | |||||
8 | package Perl::Critic::Policy::Subroutines::RequireFinalReturn; | ||||
9 | |||||
10 | 2 | 43µs | 1 | 16µs | # spent 16µs within Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@10 which was called:
# once (16µs+0s) by Module::Pluggable::Object::_require at line 10 # spent 16µs making 1 call to Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@10 |
11 | 2 | 20µs | 2 | 30µs | # spent 18µs (7+11) within Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@11 which was called:
# once (7µs+11µs) by Module::Pluggable::Object::_require at line 11 # spent 18µs making 1 call to Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@11
# spent 11µs making 1 call to strict::import |
12 | 2 | 18µs | 2 | 15µs | # spent 12µs (8+4) within Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@12 which was called:
# once (8µs+4µs) by Module::Pluggable::Object::_require at line 12 # spent 12µs making 1 call to Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@12
# spent 4µs making 1 call to warnings::import |
13 | 2 | 22µs | 2 | 48µs | # spent 28µs (8+20) within Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@13 which was called:
# once (8µs+20µs) by Module::Pluggable::Object::_require at line 13 # spent 28µs making 1 call to Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@13
# spent 20µs making 1 call to Exporter::import |
14 | |||||
15 | 2 | 22µs | 2 | 49µs | # spent 28µs (8+20) within Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@15 which was called:
# once (8µs+20µs) by Module::Pluggable::Object::_require at line 15 # spent 28µs making 1 call to Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@15
# spent 20µs making 1 call to Exporter::import |
16 | 2 | 24µs | 2 | 843µs | # spent 425µs (7+418) within Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@16 which was called:
# once (7µs+418µs) by Module::Pluggable::Object::_require at line 16 # spent 425µs making 1 call to Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@16
# spent 418µs making 1 call to Exporter::import |
17 | 2 | 844µs | 2 | 114µs | # spent 61µs (8+53) within Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@17 which was called:
# once (8µs+53µs) by Module::Pluggable::Object::_require at line 17 # spent 61µs making 1 call to Perl::Critic::Policy::Subroutines::RequireFinalReturn::BEGIN@17
# spent 53µs making 1 call to base::import |
18 | |||||
19 | 1 | 600ns | our $VERSION = '1.121'; | ||
20 | |||||
21 | #----------------------------------------------------------------------------- | ||||
22 | |||||
23 | 1 | 2µs | 1 | 50µs | Readonly::Scalar my $EXPL => [ 197 ]; # spent 50µs making 1 call to Readonly::Scalar |
24 | |||||
25 | 1 | 3µs | 2 | 27µs | Readonly::Hash my %CONDITIONALS => hashify( qw(if unless for foreach) ); # spent 24µs making 1 call to Readonly::Hash
# spent 3µs making 1 call to Perl::Critic::Utils::hashify |
26 | |||||
27 | #----------------------------------------------------------------------------- | ||||
28 | |||||
29 | # spent 16µs (14+2) within Perl::Critic::Policy::Subroutines::RequireFinalReturn::supported_parameters which was called:
# once (14µs+2µs) by Perl::Critic::Policy::new at line 88 of Perl/Critic/Policy.pm | ||||
30 | return ( | ||||
31 | { | ||||
32 | 1 | 12µs | 2 | 2µs | name => 'terminal_funcs', # spent 2µs making 2 calls to Readonly::Scalar::FETCH, avg 1µs/call |
33 | description => 'The additional subroutines to treat as terminal.', | ||||
34 | default_string => $EMPTY, | ||||
35 | behavior => 'string list', | ||||
36 | list_always_present_values => | ||||
37 | [ qw< croak confess die exec exit throw Carp::confess Carp::croak > ], | ||||
38 | }, | ||||
39 | ); | ||||
40 | } | ||||
41 | |||||
42 | 1 | 2µs | # spent 7µs (6+1) within Perl::Critic::Policy::Subroutines::RequireFinalReturn::default_severity which was called:
# once (6µs+1µs) by Perl::Critic::Policy::get_severity at line 331 of Perl/Critic/Policy.pm | ||
43 | sub default_themes { return qw( core bugs pbp certrec ) } | ||||
44 | sub applies_to { return 'PPI::Statement::Sub' } | ||||
45 | |||||
46 | #----------------------------------------------------------------------------- | ||||
47 | |||||
48 | sub violates { | ||||
49 | my ( $self, $elem, undef ) = @_; | ||||
50 | |||||
51 | # skip BEGIN{} and INIT{} and END{} etc | ||||
52 | return if $elem->isa('PPI::Statement::Scheduled'); | ||||
53 | |||||
54 | my @blocks = grep {$_->isa('PPI::Structure::Block')} $elem->schildren(); | ||||
55 | if (@blocks > 1) { | ||||
56 | # sanity check | ||||
57 | throw_internal 'Subroutine should have no more than one block'; | ||||
58 | } | ||||
59 | elsif (@blocks == 0) { | ||||
60 | #Technically, subroutines don't have to have a block at all. In | ||||
61 | # that case, its just a declaration so this policy doesn't really apply | ||||
62 | return; # ok! | ||||
63 | } | ||||
64 | |||||
65 | |||||
66 | my ($block) = @blocks; | ||||
67 | if ($self->_block_is_empty($block) || $self->_block_has_return($block)) { | ||||
68 | return; # OK | ||||
69 | } | ||||
70 | |||||
71 | # Must be a violation | ||||
72 | my $desc; | ||||
73 | if ( my $name = $elem->name() ) { | ||||
74 | $desc = qq<Subroutine "$name" does not end with "return">; | ||||
75 | } | ||||
76 | else { | ||||
77 | $desc = q<Subroutine does not end with "return">; | ||||
78 | } | ||||
79 | |||||
80 | return $self->violation( $desc, $EXPL, $elem ); | ||||
81 | } | ||||
82 | |||||
83 | #----------------------------------------------------------------------------- | ||||
84 | |||||
85 | sub _block_is_empty { | ||||
86 | my ( $self, $block ) = @_; | ||||
87 | return $block->schildren() == 0; | ||||
88 | } | ||||
89 | |||||
90 | #----------------------------------------------------------------------------- | ||||
91 | |||||
92 | sub _block_has_return { | ||||
93 | my ( $self, $block ) = @_; | ||||
94 | my @blockparts = $block->schildren(); | ||||
95 | my $final = $blockparts[-1]; # always defined because we call _block_is_empty first | ||||
96 | return if !$final; | ||||
97 | return $self->_is_explicit_return($final) | ||||
98 | || $self->_is_given_when_return($final) | ||||
99 | || $self->_is_compound_return($final); | ||||
100 | } | ||||
101 | |||||
102 | #----------------------------------------------------------------------------- | ||||
103 | |||||
104 | sub _is_explicit_return { | ||||
105 | my ( $self, $final ) = @_; | ||||
106 | |||||
107 | return if $self->_is_conditional_stmnt( $final ); | ||||
108 | return $self->_is_return_or_goto_stmnt( $final ) | ||||
109 | || $self->_is_terminal_stmnt( $final ); | ||||
110 | } | ||||
111 | |||||
112 | #----------------------------------------------------------------------------- | ||||
113 | |||||
114 | sub _is_compound_return { | ||||
115 | my ( $self, $final ) = @_; | ||||
116 | |||||
117 | if (!$final->isa('PPI::Statement::Compound')) { | ||||
118 | return; #fail | ||||
119 | } | ||||
120 | |||||
121 | my $begin = $final->schild(0); | ||||
122 | return if !$begin; #fail | ||||
123 | if (!($begin->isa('PPI::Token::Word') && | ||||
124 | ($begin eq 'if' || $begin eq 'unless'))) { | ||||
125 | return; #fail | ||||
126 | } | ||||
127 | |||||
128 | my @blocks = grep {!$_->isa('PPI::Structure::Condition') && | ||||
129 | !$_->isa('PPI::Token')} $final->schildren(); | ||||
130 | # Sanity check: | ||||
131 | if (scalar grep {!$_->isa('PPI::Structure::Block')} @blocks) { | ||||
132 | throw_internal | ||||
133 | 'Expected only conditions, blocks and tokens in the if statement'; | ||||
134 | } | ||||
135 | |||||
136 | for my $block (@blocks) { | ||||
137 | if (! $self->_block_has_return($block)) { | ||||
138 | return; #fail | ||||
139 | } | ||||
140 | } | ||||
141 | |||||
142 | return 1; | ||||
143 | } | ||||
144 | |||||
145 | #----------------------------------------------------------------------------- | ||||
146 | |||||
147 | sub _is_given_when_return { | ||||
148 | my ( $self, $final ) = @_; | ||||
149 | |||||
150 | if ( ! $final->isa( 'PPI::Statement::Given' ) ) { | ||||
151 | return; #fail | ||||
152 | } | ||||
153 | |||||
154 | my $begin = $final->schild(0); | ||||
155 | return if !$begin; #fail | ||||
156 | if ( ! ( $begin->isa( 'PPI::Token::Word' ) && | ||||
157 | $begin->content() eq 'given' ) ) { | ||||
158 | return; #fail | ||||
159 | } | ||||
160 | |||||
161 | my @blocks = grep {!$_->isa( 'PPI::Structure::Given' ) && | ||||
162 | !$_->isa( 'PPI::Token' )} $final->schildren(); | ||||
163 | # Sanity check: | ||||
164 | if (scalar grep {!$_->isa('PPI::Structure::Block')} @blocks) { | ||||
165 | throw_internal | ||||
166 | 'Expected only givens, blocks and tokens in the given statement'; | ||||
167 | } | ||||
168 | if (@blocks > 1) { | ||||
169 | # sanity check | ||||
170 | throw_internal 'Given statement should have no more than one block'; | ||||
171 | } | ||||
172 | @blocks or return; #fail | ||||
173 | |||||
174 | my $have_default; # We have to fail unless a default block is present | ||||
175 | |||||
176 | foreach my $stmnt ( $blocks[0]->schildren() ) { | ||||
177 | |||||
178 | if ( $stmnt->isa( 'PPI::Statement::When' ) ) { | ||||
179 | |||||
180 | # Check for the default block. | ||||
181 | my $first_token; | ||||
182 | $first_token = $stmnt->schild( 0 ) | ||||
183 | and 'default' eq $first_token->content() | ||||
184 | and $have_default = 1; | ||||
185 | |||||
186 | $self->_is_when_stmnt_with_return( $stmnt ) | ||||
187 | or return; #fail | ||||
188 | |||||
189 | } else { | ||||
190 | |||||
191 | $self->_is_suffix_when_with_return( $stmnt ) | ||||
192 | or return; #fail | ||||
193 | |||||
194 | } | ||||
195 | |||||
196 | } | ||||
197 | |||||
198 | return $have_default; | ||||
199 | } | ||||
200 | |||||
201 | #----------------------------------------------------------------------------- | ||||
202 | |||||
203 | sub _is_return_or_goto_stmnt { | ||||
204 | my ( $self, $stmnt ) = @_; | ||||
205 | return if not $stmnt->isa('PPI::Statement::Break'); | ||||
206 | my $first_token = $stmnt->schild(0) || return; | ||||
207 | return $first_token eq 'return' || $first_token eq 'goto'; | ||||
208 | } | ||||
209 | |||||
210 | #----------------------------------------------------------------------------- | ||||
211 | |||||
212 | sub _is_terminal_stmnt { | ||||
213 | my ( $self, $stmnt ) = @_; | ||||
214 | return if not $stmnt->isa('PPI::Statement'); | ||||
215 | my $first_token = $stmnt->schild(0) || return; | ||||
216 | return exists $self->{_terminal_funcs}->{$first_token}; | ||||
217 | } | ||||
218 | |||||
219 | #----------------------------------------------------------------------------- | ||||
220 | |||||
221 | sub _is_conditional_stmnt { | ||||
222 | my ( $self, $stmnt ) = @_; | ||||
223 | return if not $stmnt->isa('PPI::Statement'); | ||||
224 | for my $elem ( $stmnt->schildren() ) { | ||||
225 | return 1 if $elem->isa('PPI::Token::Word') | ||||
226 | && exists $CONDITIONALS{$elem}; | ||||
227 | } | ||||
228 | return; | ||||
229 | } | ||||
230 | |||||
231 | #----------------------------------------------------------------------------- | ||||
232 | |||||
233 | sub _is_when_stmnt_with_return { | ||||
234 | my ( $self, $stmnt ) = @_; | ||||
235 | |||||
236 | my @inner = grep { ! $_->isa( 'PPI::Token' ) && | ||||
237 | ! $_->isa( 'PPI::Structure::When' ) } | ||||
238 | $stmnt->schildren(); | ||||
239 | if ( scalar grep { ! $_->isa( 'PPI::Structure::Block' ) } @inner ) { | ||||
240 | throw_internal 'When statement should contain only tokens, conditions, and blocks'; | ||||
241 | } | ||||
242 | @inner > 1 | ||||
243 | and throw_internal 'When statement should have no more than one block'; | ||||
244 | @inner or return; #fail | ||||
245 | |||||
246 | foreach my $block ( @inner ) { | ||||
247 | if ( ! $self->_block_has_return( $block ) ) { | ||||
248 | return; #fail | ||||
249 | } | ||||
250 | } | ||||
251 | |||||
252 | return 1; #succeed | ||||
253 | } | ||||
254 | |||||
255 | #----------------------------------------------------------------------------- | ||||
256 | |||||
257 | sub _is_suffix_when_with_return { | ||||
258 | my ( $self, $stmnt ) = @_; | ||||
259 | return if not $stmnt->isa('PPI::Statement'); | ||||
260 | foreach my $elem ( $stmnt->schildren() ) { | ||||
261 | return ( $self->_is_return_or_goto_stmnt( $stmnt ) || | ||||
262 | $self->_is_terminal_stmnt( $stmnt ) ) | ||||
263 | if $elem->isa( 'PPI::Token::Word' ) | ||||
264 | && 'when' eq $elem->content(); | ||||
265 | } | ||||
266 | return; | ||||
267 | } | ||||
268 | |||||
269 | 1 | 4µs | 1; | ||
270 | |||||
271 | __END__ |