Skip to content
Advertisement

Find if the current statement in an If/Else block is the last statement of the THEN branch

I am using JavaParser to parse through the contents of the following code and identify the sequence of statements:

class X {
   void x() {
     int x = 1;
     if (x>4) {
        x=21;
     } else {
        if (x>1) {
           x=3;
        } else {
           x=212;
        } 
     } 
     if (x==4) { 
        x=3;
     }
}}

The code I am using to parse the above example:

private static void statements(BlockStmt block, State beforeState, State afterState) {
    List<State> states = new ArrayList<>();

    for (Statement statement : block.getStatements()) {
        states.add(new State(statement));
    }

    beforeState.nextStates.add(states.get(0));

    for (int i = 0; i < states.size(); i++) {
        State currentState = states.get(i);
        
        State nextState;
        if (i == states.size() - 1) {
            nextState = afterState;
        } else {
            nextState = states.get(i + 1);
        }

        currentState.statement.accept(new VoidVisitorWithDefaults<Void>() {
            @Override
            public void visit(ExpressionStmt n, Void arg) {
                currentState.nextStates.add(nextState);
            }

            @Override
            public void visit(IfStmt n, Void arg) {
                statements(n.getThenStmt().asBlockStmt(), currentState, nextState);
                n.getElseStmt().ifPresent(elseStmt ->
                        statements(elseStmt.asBlockStmt(), currentState, nextState));
            }
        }, null);
 } }

What I would also like to do is to identify if the current statement is an expression statement (i.e., assignment), and if yes, find if it is the last statement contained in the THEN block of an If/Else statement. In the example above that would be statement x=3;. However, I am not sure how to achieve this.

So far my thinking was along these lines:

ExpressionStmt exprStmt = (ExpressionStmt) currentState.statement;
Node exprStmtParent = exprStmt.getParent();
List<Node> exprStmtSibilings = exprStmtParent.getChildNodes();
Node lastNode = exprStmtSiblings.get(exprStmtSiblings.size() - 1);
boolean exprStmtIsLast = lastNode == ifStmt;

which works for if statements but not for assignments. Any recommendations on how to approach this?

Answer

This answer is probably to late but this is how you can solve your issue.

If the result of n.getThenStmt() is a BlockStmt you can call getStatements on it that returns a NodeList and then call getLast on the list.

It’s more safety to use equals method to compare to nodes.

The visitor needs to call super.visit method to fully visit the node (expression or statement).

Below a simplified example.

public void test() {
    String str = "class X {rn" + 
            "   void x() {rn" + 
            "     int x = 1;rn" + 
            "     if (x>4) {rn" + 
            "        x=21;rn" + 
            "     } else {rn" + 
            "        if (x>1) {rn" + 
            "           x=3;rn" + 
            "        } else {rn" + 
            "           x=212;rn" + 
            "        } rn" + 
            "     } rn" + 
            "     if (x==4) { rn" + 
            "        x=3;rn" + 
            "     }rn" + 
            "}}";
    CompilationUnit cu = StaticJavaParser.parse(str);
    
    VoidVisitor<Void> visitor = new VoidVisitorAdapter<Void>() {
        
        ExpressionStmt currentStmt; 
        
        @Override
        public void visit(ExpressionStmt n, Void arg) {
            currentStmt = n;
            super.visit(n, arg);
        }
        
        @Override
        public void visit(IfStmt n, Void arg) {
            Statement then = n.getThenStmt();
            if (then instanceof BlockStmt) {
                BlockStmt blockThenStmt = then.asBlockStmt();
                super.visit(blockThenStmt, arg); // <-- visit statements in thenStmt
                Optional<Statement> oStmt = blockThenStmt.getStatements().getLast();
                if (oStmt.isPresent() && oStmt.get().equals(currentStmt)) {
                    System.out.println(String.format("--> %s expression is the last of %s", currentStmt.toString(), n.toString()));
                }
            }
            super.visit(n, arg); // <-- visit nested ifStmt
        }
    };
    cu.accept(visitor, null);
}
Advertisement