| Module-Checkstyle documentation | Contained in the Module-Checkstyle distribution. |
Module::Checkstyle::Check::Label - Checks label declarations and usage
Checks that a label is named correctly. Use matches-name to specify a regular expression that must match.
matches-name = qr/^(?:[A-Z]+_)*[A-Z]+$/
Checks that a label is positioned correctly. Use position to specify either 'alone' or 'same'.
# position = alone
LABEL:
while (1) {
}
# position = same
LABEL: while(1) {
}
position = alone | same
Checks that last, next and redo are called with a label. Set require-for-break to enable.
require-for-break = true
Writing configuration files. Format in Module::Checkstyle::Config
| Module-Checkstyle documentation | Contained in the Module-Checkstyle distribution. |
package Module::Checkstyle::Check::Label; use strict; use warnings; use Carp qw(croak); use Readonly; use Module::Checkstyle::Util qw(:args :problem); use base qw(Module::Checkstyle::Check); # The directives we provide Readonly my $MATCHES_NAME => 'matches-name'; Readonly my $POSITION => 'position'; Readonly my $REQUIRE_FOR_BREAK => 'require-for-break'; sub register { return ( 'PPI::Token::Label' => \&handle_label, 'PPI::Statement::Break' => \&handle_break, ); } sub new { my ($class, $config) = @_; my $self = $class->SUPER::new($config); # Keep configuration local $self->{$MATCHES_NAME} = as_regexp($config->get_directive($MATCHES_NAME)); my $position = $config->get_directive($POSITION); if ($position) { croak qq/Invalid setting '$position' for directive '$POSITION' in [Label]/ if !is_valid_position($position); $self->{$POSITION} = lc($position); } $self->{$REQUIRE_FOR_BREAK} = as_true($config->get_directive($REQUIRE_FOR_BREAK)); return $self; } sub handle_label { my ($self, $label, $file) = @_; my @problems; if ($self->{$MATCHES_NAME}) { my ($name) = $label->content() =~ /(.*):$/; if ($name && $name !~ $self->{$MATCHES_NAME}) { push @problems, new_problem($self->config, $MATCHES_NAME, qq(Label '$label' does not match '$self->{$MATCHES_NAME}'), $label, $file); } } if ($self->{$POSITION}) { my $next = $label->snext_sibling; if ($self->{$POSITION} eq 'alone') { # Find first previous non-whitespace token my $prev = do { my $p = $label->previous_token; while ($p && $p->isa('PPI::Token::Whitespace')) { $p = $p->previous_token; } $p; }; # On single line if (($prev && $prev->location->[0] == $label->location->[0]) or ($next && $next->location->[0] == $label->location->[0])) { push @problems, new_problem($self->config, $POSITION, qq(Label '$label' is not on a line by its own), $label, $file); } } else { # On same line if ($next && $next->location->[0] != $label->location->[0]) { push @problems, new_problem($self->config, $POSITION, qq(Label '$label' is not on the same line as '$next'), $label, $file); } } } return @problems; } sub handle_break { my ($self, $break, $file) = @_; my @problems; if ($self->{$REQUIRE_FOR_BREAK} && $break->first_token->content =~ /^last|next|redo$/) { # next significan should be word my $next = do { my $n = $break->schild(0)->next_token; while ($n && $n->isa('PPI::Token::Whitespace')) { $n = $n->next_token; } $n; }; if (($next && !$next->isa('PPI::Token::Word')) or ($next && $next->isa('PPI::Token::Word') && $next->content =~ /^if|unless$/)) { my $break_type = $break->first_token->content; push @problems, new_problem($self->config, $REQUIRE_FOR_BREAK, qq(Break '$break_type' used without a label), $break, $file); } } return @problems; } 1; __END__