Class InnerAssignmentCheck

  • All Implemented Interfaces:
    Configurable, Contextualizable

    public class InnerAssignmentCheck
    extends AbstractCheck

    Checks for assignments in subexpressions, such as in String s = Integer.toString(i = 2);.

    Rationale: Except for the loop idioms, all assignments should occur in their own top-level statement to increase readability. With inner assignments like the one given above, it is difficult to see all places where a variable is set.

    Note: Check allows usage of the popular assignments in loops:

     String line;
     while ((line = bufferedReader.readLine()) != null) { // OK
       // process the line
     }
    
     for (;(line = bufferedReader.readLine()) != null;) { // OK
       // process the line
     }
    
     do {
       // process the line
     }
     while ((line = bufferedReader.readLine()) != null); // OK
     

    Assignment inside a condition is not a problem here, as the assignment is surrounded by an extra pair of parentheses. The comparison is != null and there is no chance that intention was to write line == reader.readLine().

    To configure the check:

     <module name="InnerAssignment"/>
     

    Example:

     class MyClass {
    
       void foo() {
         int a, b;
         a = b = 5; // violation, assignment to each variable should be in a separate statement
         a = b += 5; // violation
    
         a = 5; // OK
         b = 5; // OK
         a = 5; b = 5; // OK
    
         double myDouble;
         double[] doubleArray = new double[] {myDouble = 4.5, 15.5}; // violation
    
         String nameOne;
         List<String> myList = new ArrayList<String>();
         myList.add(nameOne = "tom"); // violation
         for (int k = 0; k < 10; k = k + 2) { // OK
           // some code
         }
    
         boolean someVal;
         if (someVal = true) { // violation
           // some code
         }
    
         while (someVal = false) {} // violation
    
         InputStream is = new FileInputStream("textFile.txt");
         while ((b = is.read()) != -1) { // OK, this is a common idiom
           // some code
         }
    
       }
    
       boolean testMethod() {
         boolean val;
         return val = true; // violation
       }
     }
     

    Parent is com.puppycrawl.tools.checkstyle.TreeWalker

    Violation Message Keys:

    • assignment.inner.avoid
    Since:
    3.0
    • Field Detail

      • ALLOWED_ASSIGNMENT_CONTEXT

        private static final int[][] ALLOWED_ASSIGNMENT_CONTEXT
        Allowed AST types from an assignment AST node towards the root.
      • CONTROL_CONTEXT

        private static final int[][] CONTROL_CONTEXT
        Allowed AST types from an assignment AST node towards the root.
      • COMPARISON_TYPES

        private static final BitSet COMPARISON_TYPES
        The token types that identify comparison operators.
    • Method Detail

      • 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
      • isInNoBraceControlStatement

        private static boolean isInNoBraceControlStatement​(DetailAST ast)
        Determines if ast is in the body of a flow control statement without braces. An example of such a statement would be
         if (y < 0)
             x = y;
         

        This leads to the following AST structure:

         LITERAL_IF
             LPAREN
             EXPR // test
             RPAREN
             EXPR // body
             SEMI
         

        We need to ensure that ast is in the body and not in the test.

        Parameters:
        ast - an assignment operator AST
        Returns:
        whether ast is in the body of a flow control statement
      • isInLoopIdiom

        private static boolean isInLoopIdiom​(DetailAST ast)
        Tests whether the given AST is used in the "assignment in loop" idiom.
         String line;
         while ((line = bufferedReader.readLine()) != null) {
           // process the line
         }
         for (;(line = bufferedReader.readLine()) != null;) {
           // process the line
         }
         do {
           // process the line
         }
         while ((line = bufferedReader.readLine()) != null);
         
        Assignment inside a condition is not a problem here, as the assignment is surrounded by an extra pair of parentheses. The comparison is != null and there is no chance that intention was to write line == reader.readLine().
        Parameters:
        ast - assignment AST
        Returns:
        whether the context of the assignment AST indicates the idiom
      • isComparison

        private static boolean isComparison​(DetailAST ast)
        Checks if an AST is a comparison operator.
        Parameters:
        ast - the AST to check
        Returns:
        true iff ast is a comparison operator.
      • isInContext

        private static boolean isInContext​(DetailAST ast,
                                           int[][] contextSet,
                                           BitSet skipTokens)
        Tests whether the provided AST is in one of the given contexts.
        Parameters:
        ast - the AST from which to start walking towards root
        contextSet - the contexts to test against.
        skipTokens - parent token types to ignore
        Returns:
        whether the parents nodes of ast match one of the allowed type paths.
      • getParent

        private static DetailAST getParent​(DetailAST ast,
                                           BitSet skipTokens)
        Get ast parent, ignoring token types from skipTokens.
        Parameters:
        ast - token to get parent
        skipTokens - token types to skip
        Returns:
        first not ignored parent of ast