Class NormalCompletionVisitor

  • All Implemented Interfaces:
    GenericVisitor<java.lang.Boolean,​java.lang.Void>

    public class NormalCompletionVisitor
    extends GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
    When deciding into which scope pattern variables should be introduced, it is sometimes necessary to determine whether a statement can complete normally {@see https://docs.oracle.com/javase/specs/jls/se22/html/jls-14.html#jls-14.22}. The JLS specifies that a statement can complete normally only if it is reachable and specifies rules for what it means for a statement to be reachable, but that part can be ignored in JavaParser since having unreachable code results in a compilation error and is thus not supported. This means that all of the rules are implemented with the assumption that provided nodes are reachable. An example of where this is needed is for the following rule regarding pattern variables introduced by if-statements. 6.3.2.2. if Statements {@see https://docs.oracle.com/javase/specs/jls/se22/html/jls-6.html#jls-6.3.2.2}: The following rules apply to a statement if (e) S (ยง14.9.1): A pattern variable is introduced by if (e) S iff (i) it is introduced by e when false and (ii) S cannot complete normally. This means that in this example: if (!(x instanceof Foo f)) { return; } System.out.println(f); f will be in scope for the println call since the block making up the then-block of the if statement (S in the rule above) cannot complete normally (since the last statement, return, cannot complete normally). But, in this example: if (!(x instanceof Foo f)) { } f is not introduced by the if statement since the empty then-block can complete normally.
    • Field Summary

      Fields 
      Modifier and Type Field Description
      private static java.lang.String[] nonEnhancedSwitchTypes  
    • Method Summary

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      static boolean containsCorrespondingBreak​(Statement statement)  
      java.lang.Boolean defaultAction​(Node n, java.lang.Void unused)
      This will be called by every node visit method that is not overridden.
      private static boolean isEnhanced​(SwitchStmt stmt)
      From https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.11.2 An enhanced switch statement is one where either (i) the type of the selector expression is not char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type, or (ii) there is a case pattern or null literal associated with the switch block.
      private boolean switchRuleCompletesNormally​(SwitchEntry switchEntry, java.lang.Void unused)
      A switch statement whose switch block consists of switch rules can complete normally iff at least one of the following is true: - One of the switch rules introduces a switch rule expression (which is necessarily a statement expression).
      java.lang.Boolean visit​(BlockStmt block, java.lang.Void unused)
      An empty block that is not a switch block can complete normally iff it is reachable.
      java.lang.Boolean visit​(BreakStmt breakStmt, java.lang.Void unused)
      A break statement cannot complete normally.
      java.lang.Boolean visit​(ContinueStmt continueStmt, java.lang.Void unused)
      A continue statement cannot complete normally.
      java.lang.Boolean visit​(DoStmt doStmt, java.lang.Void unused)
      A do statement can complete normally iff at least one of the following is true: - The contained statement can complete normally and the condition expression is not a constant expression with value true.
      java.lang.Boolean visit​(ForStmt forStmt, java.lang.Void unused)
      A basic for statement can complete normally iff at least one of the following is true: - The for statement is reachable, there is a condition expression, and the condition expression is not a constant expression with value true.
      java.lang.Boolean visit​(IfStmt ifStmt, java.lang.Void unused)
      An if-then statement can complete normally iff it is reachable.
      java.lang.Boolean visit​(LabeledStmt labeledStmt, java.lang.Void unused)
      A labeled statement can complete normally if at least one of the following is true: - The contained statement can complete normally.
      java.lang.Boolean visit​(ReturnStmt returnStmt, java.lang.Void unused)
      A return statement cannot complete normally.
      java.lang.Boolean visit​(SwitchStmt switchStmt, java.lang.Void unused)
      A switch statement whose switch block is empty, or contains only switch labels, can complete normally.
      java.lang.Boolean visit​(SynchronizedStmt synchronizedStmt, java.lang.Void unused)
      A synchronized statement can complete normally iff the contained statement can complete normally.
      java.lang.Boolean visit​(ThrowStmt throwStmt, java.lang.Void unused)
      A throw statement cannot complete normally.
      java.lang.Boolean visit​(TryStmt tryStmt, java.lang.Void unused)
      A try statement can complete normally iff both of the following are true: - The try block can complete normally or any catch block can complete normally.
      java.lang.Boolean visit​(WhileStmt whileStmt, java.lang.Void unused)
      A while statement can complete normally iff at least one of the following is true: - The while statement is reachable and the condition expression is not a constant expression with value true.
      java.lang.Boolean visit​(YieldStmt yieldStmt, java.lang.Void unused)
      A yield statement cannot complete normally.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Field Detail

      • nonEnhancedSwitchTypes

        private static java.lang.String[] nonEnhancedSwitchTypes
    • Constructor Detail

      • NormalCompletionVisitor

        public NormalCompletionVisitor()
    • Method Detail

      • visit

        public java.lang.Boolean visit​(BreakStmt breakStmt,
                                       java.lang.Void unused)
        A break statement cannot complete normally.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(ContinueStmt continueStmt,
                                       java.lang.Void unused)
        A continue statement cannot complete normally.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(ReturnStmt returnStmt,
                                       java.lang.Void unused)
        A return statement cannot complete normally.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(ThrowStmt throwStmt,
                                       java.lang.Void unused)
        A throw statement cannot complete normally.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(YieldStmt yieldStmt,
                                       java.lang.Void unused)
        A yield statement cannot complete normally.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(BlockStmt block,
                                       java.lang.Void unused)
        An empty block that is not a switch block can complete normally iff it is reachable. A non-empty block that is not a switch block can complete normally iff the last statement in it can complete normally. The first statement in a non-empty block that is not a switch block is reachable iff the block is reachable. Every other statement S in a non-empty block that is not a switch block is reachable iff the statement preceding S can complete normally.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(LabeledStmt labeledStmt,
                                       java.lang.Void unused)
        A labeled statement can complete normally if at least one of the following is true: - The contained statement can complete normally. - There is a reachable break statement that exits the labeled statement.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(IfStmt ifStmt,
                                       java.lang.Void unused)
        An if-then statement can complete normally iff it is reachable. An if-then-else statement can complete normally iff the then-statement can complete normally or the else-statement can complete normally.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(WhileStmt whileStmt,
                                       java.lang.Void unused)
        A while statement can complete normally iff at least one of the following is true: - The while statement is reachable and the condition expression is not a constant expression with value true. - There is a reachable break statement that exits the while statement.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(DoStmt doStmt,
                                       java.lang.Void unused)
        A do statement can complete normally iff at least one of the following is true: - The contained statement can complete normally and the condition expression is not a constant expression with value true. - The do statement contains a reachable continue statement with no label, and the do statement is the innermost while, do, or for statement that contains that continue statement, and the continue statement continues that do statement, and the condition expression is not a constant expression with value true. - The do statement contains a reachable continue statement with label L, and the do statement has label L, and the continue statement continues that do statement, and the condition expression is not a constant expression with value true. - There is a reachable break statement that exits the do statement.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(ForStmt forStmt,
                                       java.lang.Void unused)
        A basic for statement can complete normally iff at least one of the following is true: - The for statement is reachable, there is a condition expression, and the condition expression is not a constant expression with value true. - There is a reachable break statement that exits the for statement.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(SynchronizedStmt synchronizedStmt,
                                       java.lang.Void unused)
        A synchronized statement can complete normally iff the contained statement can complete normally.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(TryStmt tryStmt,
                                       java.lang.Void unused)
        A try statement can complete normally iff both of the following are true: - The try block can complete normally or any catch block can complete normally. - If the try statement has a finally block, then the finally block can complete normally.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • visit

        public java.lang.Boolean visit​(SwitchStmt switchStmt,
                                       java.lang.Void unused)
        A switch statement whose switch block is empty, or contains only switch labels, can complete normally. A switch statement whose switch block consists of switch labeled statement groups can complete normally iff at least one of the following is true: - The last statement in the switch block can complete normally. - There is at least one switch label after the last switch block statement group. - There is a reachable break statement that exits the switch statement. - The switch statement is not enhanced and its switch block does not contain a default label. A switch statement whose switch block consists of switch rules can complete normally iff at least one of the following is true: - One of the switch rules introduces a switch rule expression (which is necessarily a statement expression). - One of the switch rules introduces a switch rule block that can complete normally. - One of the switch rules introduces a switch rule block that contains a reachable break statement which exits the switch statement. - The switch statement is not enhanced and its switch block does not contain a default label.
        Specified by:
        visit in interface GenericVisitor<java.lang.Boolean,​java.lang.Void>
        Overrides:
        visit in class GenericVisitorWithDefaults<java.lang.Boolean,​java.lang.Void>
      • switchRuleCompletesNormally

        private boolean switchRuleCompletesNormally​(SwitchEntry switchEntry,
                                                    java.lang.Void unused)
        A switch statement whose switch block consists of switch rules can complete normally iff at least one of the following is true: - One of the switch rules introduces a switch rule expression (which is necessarily a statement expression). - One of the switch rules introduces a switch rule block that can complete normally.
      • containsCorrespondingBreak

        public static boolean containsCorrespondingBreak​(Statement statement)
        Parameters:
        statement - should be one of: SwitchStatement, WhileStatement, DoStatement, ForStatement
        Returns:
        true if a break corresponding to the statement is found; false otherwise
      • isEnhanced

        private static boolean isEnhanced​(SwitchStmt stmt)
        From https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.11.2 An enhanced switch statement is one where either (i) the type of the selector expression is not char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type, or (ii) there is a case pattern or null literal associated with the switch block. Since this relies on resolving the type of the selector expression, it might not be possible to determine whether a given switch statement is enhanced or not. If this cannot be determined, assume that it is enhanced.