1

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();
    }
}
waylonion
  • 6,866
  • 8
  • 51
  • 92
  • 2
    What I am wondering: why do you want to re-invent the wheel? There are tools that do such checking for you. Heck, you can even tune javac to give you a warning for unused variables. So, why create your own solution that will always come with the risk of being not fully correct? – GhostCat Nov 27 '16 at 20:41

1 Answers1

3

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

Federico Tomassetti
  • 2,100
  • 1
  • 19
  • 26