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().

Parent is com.puppycrawl.tools.checkstyle.TreeWalker

Violation Message Keys:

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

    • MSG_KEY

      public static final String MSG_KEY
      A key is pointing to the warning message text in "messages.properties" file.
      See Also:
    • 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.
    • ALLOWED_ASSIGNMENT_IN_COMPARISON_CONTEXT

      private static final int[][] ALLOWED_ASSIGNMENT_IN_COMPARISON_CONTEXT
      Allowed AST types from a comparison node (above an assignment) towards the root.
    • COMPARISON_TYPES

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

      private static final BitSet LOOP_IDIOM_IGNORED_PARENTS
      The token types that are ignored while checking "loop-idiom".
  • Constructor Details

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