0

I need to identify unused variables ( arguments, local variables, class member variables) unused in Java code. Basically i have to use BCEL to access the byte code and reach my objective.

I have managed using ClassGen to get all the methods called and then by using MethodGen i managed to get all the local variables and function arguments. However i still can't differentiate between a used and an unused variable.

I am guessing i have to access the JVM stack to see what variables are actually being loaded and what is not being loaded are not being used.

So the question is simple: How do i access the JVM stack using BCEL?

Filburt
  • 17,626
  • 12
  • 64
  • 115
Ali_AUB
  • 3
  • 2

1 Answers1

1

It it possible to detect the used/unused variables from the bytecode by obtaining the instruction list of the method.

I have not tried this before, and this is only an experiment that shows that it is possible at all, but I hope there is an easier and more elegant way than this:

import org.apache.bcel.Repository;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.ConstantFieldref;
import org.apache.bcel.classfile.ConstantNameAndType;
import org.apache.bcel.classfile.ConstantPool;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.LocalVariable;
import org.apache.bcel.classfile.LocalVariableTable;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETFIELD;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LoadInstruction;
import org.apache.bcel.generic.LocalVariableInstruction;
import org.apache.bcel.generic.MethodGen;

public class UnusedVariablesTest
{
    private int usedInt;
    private String usedString;
    private int unusedInt;
    private String unusedString;

    public static void main(String[] args) throws ClassNotFoundException
    {
        String className = "UnusedVariablesTest";
        JavaClass c = Repository.lookupClass(className);
        ConstantPool cp = c.getConstantPool();
        ConstantPoolGen cpg = new ConstantPoolGen(cp);
        for (Method m : c.getMethods())
        {
            //System.out.println("Method "+m);
            MethodGen mg = new MethodGen(m, className, cpg);
            InstructionList il = mg.getInstructionList();
            InstructionHandle[] ihs = il.getInstructionHandles();
             for(int i=0; i < ihs.length; i++) {
                InstructionHandle ih = ihs[i];
                Instruction instruction = ih.getInstruction();
                //System.out.println("    "+instruction);
                if (instruction instanceof LocalVariableInstruction)
                {
                    LocalVariableInstruction lvi = (LocalVariableInstruction)instruction;
                    LocalVariableTable lvt = m.getLocalVariableTable();
                    int index = lvi.getIndex();
                    LocalVariable lv = lvt.getLocalVariable(index, ih.getPosition());
                    if (lv != null)
                    {
                        System.out.println("Using "+lv.getName());
                    }
                }
                else if (instruction instanceof GETFIELD)
                {
                    GETFIELD getfield = (GETFIELD)instruction;
                    int index = getfield.getIndex();
                    Constant constant = cp.getConstant(index);
                    if (constant instanceof ConstantFieldref)
                    {
                        ConstantFieldref cfr = (ConstantFieldref)constant;
                        Constant constant2 = cp.getConstant(cfr.getNameAndTypeIndex());
                        if (constant2 instanceof ConstantNameAndType)
                        {
                            ConstantNameAndType cnat = (ConstantNameAndType)constant2;
                            System.out.println("Using "+cnat.getName(cp));
                        }
                    }
                }
             }
        }
    }

    void someMethod(int usedIntArgument, int unusedIntArgument)
    {
        System.out.println(usedInt+usedString+usedIntArgument);
    }
}

At least it prints the fields, arguments and local variables that are used, which could serve as a basis to detect the UNused ones.

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • This was a of a great help thank you so much my friend however it does not get you static class member variables used so i had to add a third if statements that checks for instructions that deal with static class member variables in order to get them. – Ali_AUB Mar 09 '14 at 15:21
  • @Ali_AUB Yes, as I mentioned, it was only a "proof of concept", and would have to be verified further (e.g. whether it works with anonymous inner classes) and possibly extended (for the static members that you mentioned). However, if it helped you to find a final, working solution, you should consider posting this solution as an answer (to your own question), maybe it will be helpful for others. – Marco13 Mar 09 '14 at 15:48