File Coverage

blib/lib/Perl/Critic/Policy/ControlStructures/ProhibitReturnInMappingBlock.pm
Criterion Covered Total %
statement 42 43 97.6
branch 8 10 80.0
condition n/a
subroutine 15 16 93.7
pod 4 5 80.0
total 69 74 93.2


line stmt bran cond sub pod time code
1             package Perl::Critic::Policy::ControlStructures::ProhibitReturnInMappingBlock;
2 2     2   737211 use 5.008001;
  2         8  
3 2     2   13 use strict;
  2         6  
  2         82  
4 2     2   10 use warnings;
  2         7  
  2         124  
5 2     2   11 use parent 'Perl::Critic::Policy';
  2         6  
  2         17  
6 2     2   366002 use List::Util qw(any);
  2         7  
  2         157  
7 2     2   12 use Perl::Critic::Utils qw(:severities);
  2         6  
  2         135  
8 2     2   291 use constant EXPL => 'A "return" in a mapping block causes confusing behavior.';
  2         6  
  2         977  
9              
10             my @MAPPING_BLOCK_KEYWORDS = qw(map grep sort);
11              
12             our $VERSION = "0.01";
13              
14 9     9 0 3774595 sub supported_parameters { return (); }
15 7     7 1 158 sub default_severity { return $SEVERITY_HIGHEST; }
16 0     0 1 0 sub default_themes { return qw(bugs complexity); }
17 9     9 1 4808434 sub applies_to { return 'PPI::Structure::Block'; }
18              
19             sub violates {
20 20     20 1 373 my ($self, $elem, undef) = @_;
21              
22 20         68 my $keyword = _mapping_block_keyword($elem);
23 20 100       94 return if !$keyword;
24              
25 6         17 my $desc = sprintf('"return" statement in "%s" block.', $keyword);
26 6         33 my @stmts = $elem->schildren;
27 6 50       159 return if !@stmts;
28              
29 6         18 my @violations;
30              
31 6         22 for my $stmt (@stmts) {
32 13 100       1963 push @violations, $self->violation($desc, EXPL, $stmt) if _is_return($stmt);
33             }
34              
35 6         66 return @violations;
36             }
37              
38             sub _mapping_block_keyword {
39 20     20   54 my ($elem) = @_;
40              
41 20 50       114 return if !$elem->sprevious_sibling;
42 20         763 my $keyword = $elem->sprevious_sibling->content;
43 20 100   51   762 return $keyword if any { $keyword eq $_ } @MAPPING_BLOCK_KEYWORDS;
  51         174  
44 14         62 return;
45             }
46              
47             sub _is_return {
48 13     13   36 my ($stmt) = @_;
49              
50 13     31   77 return any { $_->content eq 'return' } $stmt->schildren;
  31         368  
51             }
52              
53             1;
54             __END__
55              
56             =encoding utf-8
57              
58             =head1 NAME
59              
60             Perl::Critic::Policy::ControlStructures::ProhibitReturnInMappingBlock - Do not "return" in mapping blocks (map, grep, sort)
61              
62             =head1 AFFILIATION
63              
64             This policy is part of the L<Perl::Critic::Policy::ControlStructures::ProhibitReturnInMappingBlock> distribution.
65              
66             =head1 DESCRIPTION
67              
68             Using C<return> in a mapping block (C<map>, C<grep>, or C<sort>) causes unexpected behavior.
69             A C<return> exits the entire enclosing subroutine, not just the block.
70              
71             sub func {
72             my @list = (1, 2, 3);
73             my @result = map {
74             return 0 unless $_; # not ok
75             $_ + 5;
76             } @list;
77             return @result;
78             }
79              
80             If you want to skip an element, use C<next> instead:
81              
82             sub func {
83             my @list = (1, 2, 3);
84             my @result = map {
85             next unless $_;
86             $_ + 5;
87             } @list;
88             return @result;
89             }
90              
91             This applies equally to C<grep> and C<sort> blocks.
92              
93             =head1 CONFIGURATION
94              
95             This Policy is not configurable except for the standard options.
96              
97             =head1 SEE ALSO
98              
99             L<Perl::Critic::Policy::ControlStructures::ProhibitReturnInDoBlock> by utgwkk, which inspired this policy.
100              
101             =head1 LICENSE
102              
103             Copyright (C) 2026 hogashi. Portions copyright (C) 2020 utgwkk.
104              
105             This library is free software; you can redistribute it and/or modify
106             it under the same terms as Perl itself.
107              
108             =head1 AUTHOR
109              
110             hogashi
111              
112             =cut
113