logo
Free, unlimited AI code reviews that run on commit
git-lrc git-lrc GitHub Install Now We'd appreciate a star git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt

Perl::Critic::Policy::CodeLayout::RequireFinalSemicolon - require a semicolon at the end of code blocks

Bugs

       It's very difficult to distinguish a code block from an anonymous hashref constructor if there might be a
       function prototype in force, eg.

           foo { abc => 123 };   # hash ref normally
                                 # code block if foo() has prototype

       "PPI" tends to assume code.  "RequireFinalSemicolon" currently assumes  hashref  so  as  to  avoid  false
       violations.   Any  "try",  "catch" or "finally" are presumed to be code blocks (the various Try modules).
       Perhaps other common or particular functions or syntax with code blocks could be recognised.  In  general
       this sort of ambiguity is another good reason to avoid function prototypes.

       PPI as of its version 1.270 sometimes takes hashrefs in lists and arrarefs to be code blocks, eg.

           ppidump 'foo({%y,x=>1})'
           ppidump '[{%y,x=>1}]'

           ppidump '[{x=>1,%y}]'       # ok, hash

Configuration

       "except_same_line" (boolean, default true)
           If  true  (the default) then don't demand a semicolon if the closing brace is on the same line as the
           final statement.

               sub foo { return 123 }     # ok  if "except_same_line=yes"
                                          # bad if "except_same_line=no"

       "except_expression_blocks" (boolean, default true)
           If true (the default) then don't demand a semicolon at the end of an expression block,  as  described
           under "Final Value Expression" above.

               # ok under "except_expression_blocks=yes"
               # bad under "except_expression_blocks=no"
               do { 1+2+3 }
               map { $_+1 } @array
               grep {defined} @x

           The  statements  and functions for this exception are currently hard coded.  Maybe in the future they
           could be configurable, though multi-line expressions in this  sort  of  thing  tends  to  be  unusual
           anyway.   (See policy "BuiltinFunctions::RequireSimpleSortBlock" for example to demand "sort" is only
           one line.)

Description

       This policy is part of the "Perl::Critic::Pulp" add-on.  It asks you to put a semicolon ";" on the final
       statement of a subroutine or block.

           sub foo {
             do_something();      # ok
           }

           sub bar {
             do_something()       # bad
           }

       The idea is that if you add more code you don't have to notice the previous line needs a terminator.
       It's also more like the C language, if you consider that a virtue.

       This is only a matter of style since the code runs the same either way, and on that basis this policy is
       low severity and under the "cosmetic" theme (see "POLICY THEMES" in Perl::Critic).

   SameLineClosingBrace
       By default (see "CONFIGURATION" below), a semicolon is not required when the closing brace is on the same
       line as the last statement.  This is good for constants and one-liners.

           sub foo { 'my-constant-value' }     # ok

           sub square { return $_[0] ** 2 }    # ok

   FinalValueExpression
       A semicolon is not required in places where the last statement is an expression giving a value.

           map { some_thing();
                 $_+123             # ok
               } @values;

           do {
             foo();
             1+2+3                  # ok
           }

       This currently means

           do grep map sort                         # builtins

           reduce any all none notall first         # List::Util
           pairfirst pairgrep pairmap

           mapp map_pairwise grepp grep_pairwise    # List::Pairwise
           firstp first_pairwise lastp last_pairwise

       These module function names are always treated as expressions.  There's no check for whether the
       respective module is actually in use.  Fully qualified names like "List::Util::first" are recognised too.

       "do {} while" or "do {} until" loops are ordinary blocks, not expression blocks, so still require a
       semicolon on the last statement inside.

           do {
             foo()                  # bad
           } until ($condition);

   Try/CatchBlocks
       The "Try", "TryCatch" and "Syntax::Feature::Try" modules all add "try" block forms.  These are blocks not
       requiring a terminating semicolon, the same as an "if" etc doesn't.

           use TryCatch;
           sub foo {
             try {
                 attempt_something();
             } catch {
                 error_recovery();
             } # ok, no semi required here for TryCatch
           }

       The insides of the "try" and "catch" are the same as other blocks, but the "try" statement itself doesn't
       require a semicolon.  (See policy "ValuesAndExpressions::ProhibitNullStatements" to notice one added
       unnecessarily.)

       For reference, "PPI" doesn't know "try"/"catch" specifically, so when they don't have a final semicolon
       the next statement runs together and the nature of those parts might be lost.  This could upset things
       like recognition of "for" loops and could potentially make some perlcritic reports go wrong.

       The "try"/"catch" block exemption here is only for the modules with this block syntax.  There are other
       try modules such as "Try::Tiny" and friends where a final semicolon is normal and necessary if more code
       follows (because their "try" and "catch" are ordinary function calls prototyped to take code blocks).

           use Try::Tiny;
           sub foo {
             try {
                 attempt_something();
             } catch {
                 error_recovery();
             } # bad, semi required here for Try::Tiny
           }

   Disabling
       If you don't care about this you can always disable from your .perlcriticrc file in the usual way (see
       "CONFIGURATION" in Perl::Critic),

           [-CodeLayout::RequireFinalSemicolon]

Home Page

Name

       Perl::Critic::Policy::CodeLayout::RequireFinalSemicolon - require a semicolon at the end of code blocks

See Also

       Perl::Critic::Pulp,         Perl::Critic,        Perl::Critic::Policy::CodeLayout::RequireTrailingCommas,
       Perl::Critic::Policy::CodeLayout::RequireTrailingCommaAtNewline,
       Perl::Critic::Policy::Subroutines::RequireFinalReturn,
       Perl::Critic::Policy::ValuesAndExpressions::ProhibitNullStatements,
       Perl::Critic::Policy::BuiltinFunctions::RequireSimpleSortBlock

       List::Util, List::Pairwise, Try, TryCatch, Syntax::Feature::Try

See Also