waylonion
waylonion

Reputation: 6976

Identify Variables used in a Statement/Line

Given a method I would like to identify unused variables. The format that I am currently looking at guarantees that there's an assert statement as the very last line of every method.

I am using JavaParser to parse each method, list the statements and also list all the variables used within that method.

How can I retrieve all the variables used in the last statement?

private static class MethodVisitor extends VoidVisitorAdapter<Object> {

    @Override
    public void visit(MethodDeclaration n, Object arg) {
        System.out.println("Method: " + n.getName());

        BlockStmt body = n.getBody();
        List<Statement> statements = body.getStmts();

        new VariableVisitor().visit(n, null);

        Statement lastStmt = statements.get(statements.size() - 1);

        for (Statement st : statements) {
            System.out.println("Statement: " + st.toString());
        }
        System.out.println("\n\n");
    }
}

private static class VariableVisitor extends VoidVisitorAdapter<Object> {
    @Override
    public void visit(VariableDeclarationExpr n, Object arg) {
        List<VariableDeclarator> myVars = n.getVars();
        for (VariableDeclarator vars : myVars) {
            System.out.println("Variable Name: " + vars.getId().getName());
        }
        System.out.println();
    }
}

Upvotes: 1

Views: 414

Answers (1)

Federico Tomassetti
Federico Tomassetti

Reputation: 2268

You can get different approaches on this:

  1. You just take body of the method and recursively get all children finding all NameExpr and then you check if the name corresponds to some of the variables and you mark it as used
  2. You use JavaSymbolSolver which finds out for you a NameExpr to what refers to

Now, the problem with the first 1 is that it does not always give you the correct answer. Why? Because you could have other things named as your variable and you do not have the logic to distinguish such cases

For example:

void foo(int i) {
   int i;
   {
      int i;
      {
          int j = i;
      }
   }
}

Here I have different things named "i". So you would need to consider that in your logic if you want to get a precise answer. JavaParser does not know which names refer to what because it produces an Abstract Syntax Tree. Name resolving is something that happens later and it is not part of JavaParser.

Name resolution is however part of JavaSymbolSolver. You can consider use this extension of JavaParser which calculates types and solve symbols. It means having one more dependency, so you need to consider if it is what you want in your case.

Disclaimer: I am a JavaParser contributor and the mantainer of JavaSymbolSolver

Upvotes: 3

Related Questions