File Coverage

blib/lib/Module/Checkstyle/Check/Label.pm
Criterion Covered Total %
statement 56 59 94.9
branch 16 20 80.0
condition 23 36 63.8
subroutine 9 10 90.0
pod 4 4 100.0
total 108 129 83.7


line stmt bran cond sub pod time code
1             package Module::Checkstyle::Check::Label;
2              
3 2     2   13106 use strict;
  2         5  
  2         661  
4 2     2   14 use warnings;
  2         6  
  2         83  
5              
6 2     2   12 use Carp qw(croak);
  2         4  
  2         321  
7 2     2   972 use Readonly;
  2         2827  
  2         122  
8              
9 2     2   523 use Module::Checkstyle::Util qw(:args :problem);
  2         7  
  2         1202  
10              
11 2     2   13 use base qw(Module::Checkstyle::Check);
  2         4  
  2         4508  
12              
13             # The directives we provide
14              
15             Readonly my $MATCHES_NAME => 'matches-name';
16             Readonly my $POSITION => 'position';
17             Readonly my $REQUIRE_FOR_BREAK => 'require-for-break';
18              
19             sub register {
20             return (
21 0     0 1 0 'PPI::Token::Label' => \&handle_label,
22             'PPI::Statement::Break' => \&handle_break,
23             );
24             }
25              
26             sub new {
27 3     3 1 7 my ($class, $config) = @_;
28            
29 3         22 my $self = $class->SUPER::new($config);
30            
31             # Keep configuration local
32 3         13 $self->{$MATCHES_NAME} = as_regexp($config->get_directive($MATCHES_NAME));
33              
34 3         24 my $position = $config->get_directive($POSITION);
35 3 100       9 if ($position) {
36 1 50       6 croak qq/Invalid setting '$position' for directive '$POSITION' in [Label]/ if !is_valid_position($position);
37 1         5 $self->{$POSITION} = lc($position);
38             }
39              
40 3         18 $self->{$REQUIRE_FOR_BREAK} = as_true($config->get_directive($REQUIRE_FOR_BREAK));
41            
42 3         24 return $self;
43             }
44              
45             sub handle_label {
46 7     7 1 27122 my ($self, $label, $file) = @_;
47              
48 7         13 my @problems;
49            
50 7 100       32 if ($self->{$MATCHES_NAME}) {
51 3         30 my ($name) = $label->content() =~ /(.*):$/;
52 3 100 66     37 if ($name && $name !~ $self->{$MATCHES_NAME}) {
53 1         27 push @problems, new_problem($self->config, $MATCHES_NAME,
54             qq(Label '$label' does not match '$self->{$MATCHES_NAME}'),
55             $label, $file);
56             }
57             }
58              
59 7 100       71 if ($self->{$POSITION}) {
60 4         47 my $next = $label->snext_sibling;
61            
62 4 50       124 if ($self->{$POSITION} eq 'alone') {
63             # Find first previous non-whitespace token
64 4         26 my $prev = do {
65 4         18 my $p = $label->previous_token;
66 4   100     267 while ($p && $p->isa('PPI::Token::Whitespace')) {
67 4         87 $p = $p->previous_token;
68             }
69 4         191 $p;
70             };
71            
72             # On single line
73 4 100 100     43 if (($prev && $prev->location->[0] == $label->location->[0]) or
      66        
      66        
74             ($next && $next->location->[0] == $label->location->[0])) {
75 3         120 push @problems, new_problem($self->config, $POSITION,
76             qq(Label '$label' is not on a line by its own),
77             $label, $file);
78             }
79             }
80             else {
81             # On same line
82 0 0 0     0 if ($next && $next->location->[0] != $label->location->[0]) {
83 0         0 push @problems, new_problem($self->config, $POSITION,
84             qq(Label '$label' is not on the same line as '$next'),
85             $label, $file);
86             }
87             }
88             }
89            
90 7         80 return @problems;
91             }
92              
93             sub handle_break {
94 6     6 1 14717 my ($self, $break, $file) = @_;
95              
96 6         11 my @problems;
97              
98 6 100 66     28 if ($self->{$REQUIRE_FOR_BREAK} && $break->first_token->content =~ /^last|next|redo$/) {
99             # next significan should be word
100 5         187 my $next = do {
101 5         22 my $n = $break->schild(0)->next_token;
102 5   66     241 while ($n && $n->isa('PPI::Token::Whitespace')) {
103 2         14 $n = $n->next_token;
104             }
105 5         69 $n;
106             };
107              
108 5 100 66     72 if (($next && !$next->isa('PPI::Token::Word')) or
      33        
      66        
      66        
109             ($next && $next->isa('PPI::Token::Word') && $next->content =~ /^if|unless$/)) {
110 4         24 my $break_type = $break->first_token->content;
111 4         76 push @problems, new_problem($self->config, $REQUIRE_FOR_BREAK,
112             qq(Break '$break_type' used without a label),
113             $break, $file);
114             }
115              
116             }
117            
118 6         68 return @problems;
119             }
120              
121             1;
122             __END__