Class UnusedLocalVariableCheck

All Implemented Interfaces:
Configurable, Contextualizable

public class UnusedLocalVariableCheck extends AbstractCheck

Checks that a local variable is declared and/or assigned, but not used. Doesn't support pattern variables yet. Doesn't check array components as array components are classified as different kind of variables by JLS.

To configure the check:

 <module name="UnusedLocalVariable"/>
 

Example:

 class Test {

     int a;

     {
         int k = 12; // violation, assigned and updated but never used
         k++;
     }

     Test(int a) {   // ok as 'a' is a constructor parameter not a local variable
         this.a = 12;
     }

     void method(int b) {
         int a = 10;             // violation
         int[] arr = {1, 2, 3};  // violation
         int[] anotherArr = {1}; // ok
         anotherArr[0] = 4;
     }

     String convertValue(String newValue) {
         String s = newValue.toLowerCase(); // violation
         return newValue.toLowerCase();
     }

     void read() throws IOException {
         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
         String s; // violation
         while ((s = reader.readLine()) != null) {
         }
         try (BufferedReader reader1 // ok as 'reader1' is a resource and resources are closed
                                     // at the end of the statement
             = new BufferedReader(new FileReader("abc.txt"))) {
         }
         try {
         } catch (Exception e) {     // ok as e is an exception parameter
         }
     }

     void loops() {
         int j = 12;
         for (int i = 0; j < 11; i++) { // violation, unused local variable 'i'.
         }
         for (int p = 0; j < 11; p++)   // ok
             p /= 2;
     }

     void lambdas() {
         Predicate<String> obj = (String str) -> { // ok as 'str' is a lambda parameter
             return true;
         };
         obj.test("test");
     }
 }
 

Parent is com.puppycrawl.tools.checkstyle.TreeWalker

Violation Message Keys:

  • unused.local.var
Since:
9.3
  • Field Details

    • MSG_UNUSED_LOCAL_VARIABLE

      public static final String MSG_UNUSED_LOCAL_VARIABLE
      A key is pointing to the warning message text in "messages.properties" file.
      See Also:
    • INCREMENT_AND_DECREMENT_TOKENS

      private static final int[] INCREMENT_AND_DECREMENT_TOKENS
      An array of increment and decrement tokens.
    • SCOPES

      private static final int[] SCOPES
      An array of scope tokens.
    • UNACCEPTABLE_CHILD_OF_DOT

      private static final int[] UNACCEPTABLE_CHILD_OF_DOT
      An array of unacceptable children of ast of type TokenTypes.DOT.
    • UNACCEPTABLE_PARENT_OF_IDENT

      private static final int[] UNACCEPTABLE_PARENT_OF_IDENT
      An array of unacceptable parent of ast of type TokenTypes.IDENT.
    • CONTAINERS_FOR_ANON_INNERS

      private static final int[] CONTAINERS_FOR_ANON_INNERS
      An array of blocks in which local anon inner classes can exist.
    • PACKAGE_SEPARATOR

      private static final String PACKAGE_SEPARATOR
      Package separator.
      See Also:
    • variables

      private final Deque<UnusedLocalVariableCheck.VariableDesc> variables
      Keeps tracks of the variables declared in file.
    • typeDeclarations

      private final Deque<UnusedLocalVariableCheck.TypeDeclDesc> typeDeclarations
      Keeps track of all the type declarations present in the file. Pops the type out of the stack while leaving the type in visitor pattern.
    • typeDeclAstToTypeDeclDesc

      private final Map<DetailAST,UnusedLocalVariableCheck.TypeDeclDesc> typeDeclAstToTypeDeclDesc
      Maps type declaration ast to their respective TypeDeclDesc objects.
    • anonInnerAstToTypeDeclDesc

      private final Map<DetailAST,UnusedLocalVariableCheck.TypeDeclDesc> anonInnerAstToTypeDeclDesc
      Maps local anonymous inner class to the TypeDeclDesc object containing it.
    • anonInnerClassHolders

      private final Set<DetailAST> anonInnerClassHolders
      Set of tokens of type CONTAINERS_FOR_ANON_INNERS and TokenTypes.LAMBDA in some cases.
    • packageName

      private String packageName
      Name of the package.
    • depth

      private int depth
      Depth at which a type declaration is nested, 0 for top level type declarations.
  • Constructor Details

    • UnusedLocalVariableCheck

      public UnusedLocalVariableCheck()
      Creates a new UnusedLocalVariableCheck instance.
  • Method Details

    • getDefaultTokens

      public int[] getDefaultTokens()
      Description copied from class: AbstractCheck
      Returns the default token a check is interested in. Only used if the configuration for a check does not define the tokens.
      Specified by:
      getDefaultTokens in class AbstractCheck
      Returns:
      the default tokens
      See Also:
    • getAcceptableTokens

      public int[] getAcceptableTokens()
      Description copied from class: AbstractCheck
      The configurable token set. Used to protect Checks against malicious users who specify an unacceptable token set in the configuration file. The default implementation returns the check's default tokens.
      Specified by:
      getAcceptableTokens in class AbstractCheck
      Returns:
      the token set this check is designed for.
      See Also:
    • getRequiredTokens

      public int[] getRequiredTokens()
      Description copied from class: AbstractCheck
      The tokens that this check must be registered for.
      Specified by:
      getRequiredTokens in class AbstractCheck
      Returns:
      the token set this must be registered for.
      See Also:
    • beginTree

      public void beginTree(DetailAST root)
      Description copied from class: AbstractCheck
      Called before the starting to process a tree. Ideal place to initialize information that is to be collected whilst processing a tree.
      Overrides:
      beginTree in class AbstractCheck
      Parameters:
      root - the root of the tree
    • visitToken

      public void visitToken(DetailAST ast)
      Description copied from class: AbstractCheck
      Called to process a token.
      Overrides:
      visitToken in class AbstractCheck
      Parameters:
      ast - the token to process
    • leaveToken

      public void leaveToken(DetailAST ast)
      Description copied from class: AbstractCheck
      Called after all the child nodes have been process.
      Overrides:
      leaveToken in class AbstractCheck
      Parameters:
      ast - the token leaving
    • visitDotToken

      private static void visitDotToken(DetailAST dotAst, Deque<UnusedLocalVariableCheck.VariableDesc> variablesStack)
      Visit ast of type TokenTypes.DOT.
      Parameters:
      dotAst - dotAst
      variablesStack - stack of all the relevant variables in the scope
    • visitVariableDefToken

      private void visitVariableDefToken(DetailAST varDefAst)
      Visit ast of type TokenTypes.VARIABLE_DEF.
      Parameters:
      varDefAst - varDefAst
    • visitIdentToken

      private static void visitIdentToken(DetailAST identAst, Deque<UnusedLocalVariableCheck.VariableDesc> variablesStack)
      Visit ast of type TokenTypes.IDENT.
      Parameters:
      identAst - identAst
      variablesStack - stack of all the relevant variables in the scope
    • visitTypeDeclarationToken

      private void visitTypeDeclarationToken(DetailAST typeDeclAst)
      Visit the type declaration token.
      Parameters:
      typeDeclAst - type declaration ast
    • visitLocalAnonInnerClass

      private void visitLocalAnonInnerClass(DetailAST literalNewAst)
      Visit the local anon inner class.
      Parameters:
      literalNewAst - literalNewAst
    • extractQualifiedName

      private static String extractQualifiedName(DetailAST ast)
      Get name of package and super class of anon inner class by concatenating the identifier values under TokenTypes.DOT. Duplicated, until https://github.com/checkstyle/checkstyle/issues/11201
      Parameters:
      ast - ast to extract superclass or package name from
      Returns:
      qualified name
    • isInsideLocalAnonInnerClass

      private static boolean isInsideLocalAnonInnerClass(DetailAST literalNewAst)
      Whether ast node of type TokenTypes.LITERAL_NEW is a part of a local anonymous inner class.
      Parameters:
      literalNewAst - ast node of type TokenTypes.LITERAL_NEW
      Returns:
      true if variableDefAst is an instance variable in local anonymous inner class
    • logViolations

      private void logViolations(DetailAST scopeAst, Deque<UnusedLocalVariableCheck.VariableDesc> variablesStack)
      Traverse variablesStack stack and log the violations.
      Parameters:
      scopeAst - ast node of type SCOPES
      variablesStack - stack of all the relevant variables in the scope
    • leaveCompilationUnit

      private void leaveCompilationUnit()
      We process all the blocks containing local anonymous inner classes separately after processing all the other nodes. This is being done due to the fact the instance variables of local anon inner classes can cast a shadow on local variables.
    • isNonLocalTypeDeclaration

      private static boolean isNonLocalTypeDeclaration(DetailAST typeDeclAst)
      Whether a type declaration is non-local. Annotated interfaces are always non-local.
      Parameters:
      typeDeclAst - type declaration ast
      Returns:
      true if type declaration is non-local
    • getBlockContainingLocalAnonInnerClass

      private static DetailAST getBlockContainingLocalAnonInnerClass(DetailAST literalNewAst)
      Get the block containing local anon inner class.
      Parameters:
      literalNewAst - ast node of type TokenTypes.LITERAL_NEW
      Returns:
      the block containing local anon inner class
    • addLocalVariables

      private static void addLocalVariables(DetailAST varDefAst, Deque<UnusedLocalVariableCheck.VariableDesc> variablesStack)
      Add local variables to the variablesStack stack. Also adds the instance variables defined in a local anonymous inner class.
      Parameters:
      varDefAst - ast node of type TokenTypes.VARIABLE_DEF
      variablesStack - stack of all the relevant variables in the scope
    • addInstanceOrClassVar

      private void addInstanceOrClassVar(DetailAST varDefAst)
      Add instance variables and class variables to the UnusedLocalVariableCheck.TypeDeclDesc.instanceAndClassVarStack.
      Parameters:
      varDefAst - ast node of type TokenTypes.VARIABLE_DEF
    • isPrivateInstanceVariable

      private static boolean isPrivateInstanceVariable(DetailAST varDefAst)
      Whether instance variable or class variable have private access modifier.
      Parameters:
      varDefAst - ast node of type TokenTypes.VARIABLE_DEF
      Returns:
      true if instance variable or class variable have private access modifier
    • getSuperClassOfAnonInnerClass

      private UnusedLocalVariableCheck.TypeDeclDesc getSuperClassOfAnonInnerClass(DetailAST literalNewAst)
      Get the UnusedLocalVariableCheck.TypeDeclDesc of the super class of anonymous inner class.
      Parameters:
      literalNewAst - ast node of type TokenTypes.LITERAL_NEW
      Returns:
      UnusedLocalVariableCheck.TypeDeclDesc of the super class of anonymous inner class
    • getShortNameOfAnonInnerClass

      public static String getShortNameOfAnonInnerClass(DetailAST literalNewAst)
      Get the short name of super class of anonymous inner class. Example-
       TestClass.NestedClass obj = new Test().new NestedClass() {};
       // Short name will be Test.NestedClass
       
      Parameters:
      literalNewAst - ast node of type TokenTypes.LITERAL_NEW
      Returns:
      short name of base class of anonymous inner class
    • modifyVariablesStack

      private void modifyVariablesStack(UnusedLocalVariableCheck.TypeDeclDesc obtainedClass, Deque<UnusedLocalVariableCheck.VariableDesc> variablesStack, DetailAST literalNewAst)
      Add non-private instance and class variables of the super class of the anonymous class to the variables stack.
      Parameters:
      obtainedClass - super class of the anon inner class
      variablesStack - stack of all the relevant variables in the scope
      literalNewAst - ast node of type TokenTypes.LITERAL_NEW
    • typeDeclWithSameName

      private List<UnusedLocalVariableCheck.TypeDeclDesc> typeDeclWithSameName(String superClassName)
      Checks if there is a type declaration with same name as the super class. Duplicated, until https://github.com/checkstyle/checkstyle/issues/11201
      Parameters:
      superClassName - name of the super class
      Returns:
      true if there is another type declaration with same name.
    • hasSameNameAsSuperClass

      private boolean hasSameNameAsSuperClass(String superClassName, UnusedLocalVariableCheck.TypeDeclDesc typeDeclDesc)
      Whether the qualified name of typeDeclDesc matches the super class name.
      Parameters:
      superClassName - name of the super class
      typeDeclDesc - type declaration description
      Returns:
      true if the qualified name of typeDeclDesc matches the super class name
    • getTheNearestClass

      private static UnusedLocalVariableCheck.TypeDeclDesc getTheNearestClass(String outerTypeDeclName, List<UnusedLocalVariableCheck.TypeDeclDesc> typeDeclWithSameName)
      For all type declarations with the same name as the superclass, gets the nearest type declaration. Duplicated, until https://github.com/checkstyle/checkstyle/issues/11201
      Parameters:
      outerTypeDeclName - outer type declaration of anonymous inner class
      typeDeclWithSameName - typeDeclarations which have the same name as the super class
      Returns:
      the nearest class
    • typeDeclNameMatchingCount

      private static int typeDeclNameMatchingCount(String patternClass, String classToBeMatched)
      Calculates and returns the type declaration name matching count.

      Suppose our pattern class is foo.a.b and class to be matched is foo.a.ball then type declaration name matching count would be calculated by comparing every character, and updating main counter when we hit "." to prevent matching "a.b" with "a.ball". In this case type declaration name matching count would be equal to 6 and not 7 (b of ball is not counted).

      Duplicated, until https://github.com/checkstyle/checkstyle/issues/11201
      Parameters:
      patternClass - class against which the given class has to be matched
      classToBeMatched - class to be matched
      Returns:
      class name matching count
    • getQualifiedTypeDeclarationName

      private String getQualifiedTypeDeclarationName(DetailAST typeDeclAst)
      Get qualified type declaration name from type ast. Duplicated, until https://github.com/checkstyle/checkstyle/issues/11201
      Parameters:
      typeDeclAst - type declaration ast
      Returns:
      qualified name of type declaration
    • getQualifiedTypeDeclarationName

      private static String getQualifiedTypeDeclarationName(String packageName, String outerClassQualifiedName, String className)
      Get the qualified name of type declaration by combining packageName, outerClassQualifiedName and className. Duplicated, until https://github.com/checkstyle/checkstyle/issues/11201
      Parameters:
      packageName - packageName
      outerClassQualifiedName - outerClassQualifiedName
      className - className
      Returns:
      the qualified name of type declaration by combining packageName, outerClassQualifiedName and className
    • iterateOverBlockContainingLocalAnonInnerClass

      private void iterateOverBlockContainingLocalAnonInnerClass(DetailAST ast, Deque<UnusedLocalVariableCheck.VariableDesc> variablesStack)
      Iterate over all the ast nodes present under ast.
      Parameters:
      ast - ast
      variablesStack - stack of all the relevant variables in the scope
    • customVisitToken

      private void customVisitToken(DetailAST ast, Deque<UnusedLocalVariableCheck.VariableDesc> variablesStack)
      Visit all ast nodes under anonInnerClassHolders once again.
      Parameters:
      ast - ast
      variablesStack - stack of all the relevant variables in the scope
    • customLeaveToken

      private void customLeaveToken(DetailAST ast, Deque<UnusedLocalVariableCheck.VariableDesc> variablesStack)
      Leave all ast nodes under anonInnerClassHolders once again.
      Parameters:
      ast - ast
      variablesStack - stack of all the relevant variables in the scope
    • shouldCheckIdentWithMethodRefParent

      public static boolean shouldCheckIdentWithMethodRefParent(DetailAST identAst)
      Whether an ident with parent node of type TokenTypes.METHOD_REF should be checked or not.
      Parameters:
      identAst - identAst
      Returns:
      true if an ident with parent node of type TokenTypes.METHOD_REF should be checked or if the parent type is not TokenTypes.METHOD_REF
    • shouldCheckIdentTokenNestedUnderDot

      public static boolean shouldCheckIdentTokenNestedUnderDot(DetailAST dotAst)
      Whether to check identifier token nested under dotAst.
      Parameters:
      dotAst - dotAst
      Returns:
      true if ident nested under dotAst should be checked
    • checkIdentifierAst

      private static void checkIdentifierAst(DetailAST identAst, Deque<UnusedLocalVariableCheck.VariableDesc> variablesStack)
      Checks the identifier ast.
      Parameters:
      identAst - ast of type TokenTypes.IDENT
      variablesStack - stack of all the relevant variables in the scope
    • findScopeOfVariable

      private static DetailAST findScopeOfVariable(DetailAST variableDef)
      Find the scope of variable.
      Parameters:
      variableDef - ast of type TokenTypes.VARIABLE_DEF
      Returns:
      scope of variableDef
    • isLeftHandSideValue

      private static boolean isLeftHandSideValue(DetailAST identAst)
      Checks whether the ast of type TokenTypes.IDENT is used as left-hand side value. An identifier is being used as a left-hand side value if it is used as the left operand of an assignment or as an operand of a stand-alone increment or decrement.
      Parameters:
      identAst - ast of type TokenTypes.IDENT
      Returns:
      true if identAst is used as a left-hand side value
    • isStandAloneIncrementOrDecrement

      private static boolean isStandAloneIncrementOrDecrement(DetailAST identAst)
      Checks whether the ast of type TokenTypes.IDENT is used as an operand of a stand-alone increment or decrement.
      Parameters:
      identAst - ast of type TokenTypes.IDENT
      Returns:
      true if identAst is used as an operand of stand-alone increment or decrement
    • isIncrementOrDecrementVariableUsed

      private static boolean isIncrementOrDecrementVariableUsed(DetailAST exprAst)
      A variable with increment or decrement operator is considered used if it is used as an argument or as an array index or for assigning value to a variable.
      Parameters:
      exprAst - ast of type TokenTypes.EXPR
      Returns:
      true if variable nested in exprAst is used