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 Detail

      • MSG_UNUSED_LOCAL_VARIABLE

        public static final java.lang.String MSG_UNUSED_LOCAL_VARIABLE
        A key is pointing to the warning message text in "messages.properties" file.
        See Also:
        Constant Field Values
      • 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 java.lang.String PACKAGE_SEPARATOR
        Package separator.
        See Also:
        Constant Field Values
      • typeDeclarations

        private final java.util.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.
      • packageName

        private java.lang.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 Detail

      • UnusedLocalVariableCheck

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

      • 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:
        TokenTypes
      • 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:
        TokenTypes
      • 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:
        TokenTypes
      • 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
      • 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
      • visitVariableDefToken

        private void visitVariableDefToken​(DetailAST varDefAst)
        Visit ast of type TokenTypes.VARIABLE_DEF.
        Parameters:
        varDefAst - varDefAst
      • 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
      • 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,
                                   java.util.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,
                                              java.util.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
      • 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
      • getShortNameOfAnonInnerClass

        public static java.lang.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
      • hasSameNameAsSuperClass

        private boolean hasSameNameAsSuperClass​(java.lang.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
      • typeDeclNameMatchingCount

        private static int typeDeclNameMatchingCount​(java.lang.String patternClass,
                                                     java.lang.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 java.lang.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 java.lang.String getQualifiedTypeDeclarationName​(java.lang.String packageName,
                                                                        java.lang.String outerClassQualifiedName,
                                                                        java.lang.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,
                                                                   java.util.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
      • 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
      • 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