checkFields - whether to check references to fields. Default value is true.
+ *
checkMethods - whether to check references to methods.
+ * Default value is true.
+ *
validateOnlyOverlapping - whether to check only overlapping by variables or
+ * arguments. Default value is true.
*
- *
Warning: the Check is very controversial and not that actual nowadays.
+ *
Warning: the Check is very controversial if 'validateOnlyOverlapping' option is set to 'false'
+ * and not that actual nowadays.
*
*
Examples of use:
*
@@ -76,6 +84,7 @@ import com.puppycrawl.tools.checkstyle.utils.ScopeUtils;
*
* @author Stephen Bloch
* @author o_sukhodolsky
+ * @author Andrei Selkin
*/
public class RequireThisCheck extends AbstractCheck {
@@ -84,40 +93,61 @@ public class RequireThisCheck extends AbstractCheck {
* file.
*/
public static final String MSG_METHOD = "require.this.method";
-
/**
* A key is pointing to the warning message text in "messages.properties"
* file.
*/
public static final String MSG_VARIABLE = "require.this.variable";
- /**
- * Set of all declaration tokens.
- */
+
+ /** Set of all declaration tokens. */
private static final ImmutableSet DECLARATION_TOKENS = ImmutableSet.of(
- TokenTypes.VARIABLE_DEF,
- TokenTypes.CTOR_DEF,
- TokenTypes.METHOD_DEF,
- TokenTypes.CLASS_DEF,
- TokenTypes.ENUM_DEF,
- TokenTypes.INTERFACE_DEF,
- TokenTypes.PARAMETER_DEF,
- TokenTypes.TYPE_ARGUMENT
+ TokenTypes.VARIABLE_DEF,
+ TokenTypes.CTOR_DEF,
+ TokenTypes.METHOD_DEF,
+ TokenTypes.CLASS_DEF,
+ TokenTypes.ENUM_DEF,
+ TokenTypes.INTERFACE_DEF,
+ TokenTypes.PARAMETER_DEF,
+ TokenTypes.TYPE_ARGUMENT
+ );
+ /** Set of all assign tokens. */
+ private static final ImmutableSet ASSIGN_TOKENS = ImmutableSet.of(
+ TokenTypes.ASSIGN,
+ TokenTypes.PLUS_ASSIGN,
+ TokenTypes.STAR_ASSIGN,
+ TokenTypes.DIV_ASSIGN,
+ TokenTypes.MOD_ASSIGN,
+ TokenTypes.SR_ASSIGN,
+ TokenTypes.BSR_ASSIGN,
+ TokenTypes.SL_ASSIGN,
+ TokenTypes.BAND_ASSIGN,
+ TokenTypes.BXOR_ASSIGN
+ );
+ /** Set of all compound assign tokens. */
+ private static final ImmutableSet COMPOUND_ASSIGN_TOKENS = ImmutableSet.of(
+ TokenTypes.PLUS_ASSIGN,
+ TokenTypes.STAR_ASSIGN,
+ TokenTypes.DIV_ASSIGN,
+ TokenTypes.MOD_ASSIGN,
+ TokenTypes.SR_ASSIGN,
+ TokenTypes.BSR_ASSIGN,
+ TokenTypes.SL_ASSIGN,
+ TokenTypes.BAND_ASSIGN,
+ TokenTypes.BXOR_ASSIGN
);
- /**
- * Tree of all the parsed frames.
- */
+ /** Tree of all the parsed frames. */
private Map frames;
- /**
- * Frame for the currently processed AST.
- */
+ /** Frame for the currently processed AST. */
private AbstractFrame current;
/** Whether we should check fields usage. */
private boolean checkFields = true;
/** Whether we should check methods usage. */
private boolean checkMethods = true;
+ /** Whether we should check only overlapping by variables or arguments. */
+ private boolean validateOnlyOverlapping = true;
/**
* Setter for checkFields property.
@@ -135,6 +165,14 @@ public class RequireThisCheck extends AbstractCheck {
this.checkMethods = checkMethods;
}
+ /**
+ * Setter for validateOnlyOverlapping property.
+ * @param validateOnlyOverlapping should we check only overlapping by variables or arguments.
+ */
+ public void setValidateOnlyOverlapping(boolean validateOnlyOverlapping) {
+ this.validateOnlyOverlapping = validateOnlyOverlapping;
+ }
+
@Override
public int[] getDefaultTokens() {
return getAcceptableTokens();
@@ -160,10 +198,10 @@ public class RequireThisCheck extends AbstractCheck {
@Override
public void beginTree(DetailAST rootAST) {
- final Deque frameStack = Lists.newLinkedList();
-
frames = Maps.newHashMap();
+ current = null;
+ final Deque frameStack = Lists.newLinkedList();
DetailAST curNode = rootAST;
while (curNode != null) {
collectDeclarations(frameStack, curNode);
@@ -201,8 +239,7 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Checks if a given IDENT is method call or field name which
- * require explicit {@code this} qualifier.
- *
+ * requires explicit {@code this} qualifier.
* @param ast IDENT to check.
*/
private void processIdent(DetailAST ast) {
@@ -214,9 +251,8 @@ public class RequireThisCheck extends AbstractCheck {
// no need to check annotations content
break;
case TokenTypes.METHOD_CALL:
- // let's check method calls
if (checkMethods) {
- final AbstractFrame frame = checkMethod(ast);
+ final AbstractFrame frame = getMethodWithoutThis(ast);
if (frame != null) {
logViolation(MSG_METHOD, ast, frame);
}
@@ -224,7 +260,7 @@ public class RequireThisCheck extends AbstractCheck {
break;
default:
if (checkFields) {
- final AbstractFrame frame = processField(ast, parentType);
+ final AbstractFrame frame = getFieldWithoutThis(ast, parentType);
if (frame != null) {
logViolation(MSG_VARIABLE, ast, frame);
}
@@ -237,7 +273,7 @@ public class RequireThisCheck extends AbstractCheck {
* Helper method to log a LocalizedMessage.
* @param ast a node to get line id column numbers associated with the message.
* @param msgKey key to locale message format.
- * @param frame the frame, where the violation is found.
+ * @param frame the class frame where the violation is found.
*/
private void logViolation(String msgKey, DetailAST ast, AbstractFrame frame) {
if (frame.getFrameName().equals(getNearestClassFrameName())) {
@@ -249,12 +285,14 @@ public class RequireThisCheck extends AbstractCheck {
}
/**
- * Process validation of Field.
- * @param ast field definition ast token
- * @param parentType type of the parent
- * @return frame, where the field is declared, if the violation is found and null otherwise
+ * Returns the frame where the field is declared, if the given field is used without
+ * 'this', and null otherwise.
+ * @param ast field definition ast token.
+ * @param parentType type of the parent.
+ * @return the frame where the field is declared, if the given field is used without
+ * 'this' and null otherwise.
*/
- private AbstractFrame processField(DetailAST ast, int parentType) {
+ private AbstractFrame getFieldWithoutThis(DetailAST ast, int parentType) {
final boolean importOrPackage = ScopeUtils.getSurroundingScope(ast) == null;
final boolean methodNameInMethodCall = parentType == TokenTypes.DOT
&& ast.getPreviousSibling() != null;
@@ -266,19 +304,17 @@ public class RequireThisCheck extends AbstractCheck {
&& !methodNameInMethodCall
&& !typeName
&& !isDeclarationToken(parentType)) {
- frame = checkField(ast);
+ frame = getClassFrameWhereViolationIsFound(ast);
}
return frame;
}
/**
- * Parse the next AST for declarations.
- *
- * @param frameStack Stack containing the FrameTree being built
- * @param ast AST to parse
+ * Parses the next AST for declarations.
+ * @param frameStack stack containing the FrameTree being built.
+ * @param ast AST to parse.
*/
- private static void collectDeclarations(Deque frameStack,
- DetailAST ast) {
+ private static void collectDeclarations(Deque frameStack, DetailAST ast) {
final AbstractFrame frame = frameStack.peek();
switch (ast.getType()) {
case TokenTypes.VARIABLE_DEF :
@@ -292,28 +328,28 @@ public class RequireThisCheck extends AbstractCheck {
case TokenTypes.INTERFACE_DEF :
case TokenTypes.ENUM_DEF :
case TokenTypes.ANNOTATION_DEF :
- final DetailAST classIdent = ast.findFirstToken(TokenTypes.IDENT);
- frameStack.addFirst(new ClassFrame(frame, classIdent.getText()));
+ final DetailAST classFrameNameIdent = ast.findFirstToken(TokenTypes.IDENT);
+ frameStack.addFirst(new ClassFrame(frame, classFrameNameIdent));
break;
case TokenTypes.SLIST :
- frameStack.addFirst(new BlockFrame(frame));
+ frameStack.addFirst(new BlockFrame(frame, ast));
break;
case TokenTypes.METHOD_DEF :
- final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
+ final DetailAST methodFrameNameIdent = ast.findFirstToken(TokenTypes.IDENT);
if (frame.getType() == FrameType.CLASS_FRAME) {
- final DetailAST mods =
- ast.findFirstToken(TokenTypes.MODIFIERS);
+ final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS);
if (mods.branchContains(TokenTypes.LITERAL_STATIC)) {
- ((ClassFrame) frame).addStaticMethod(ident);
+ ((ClassFrame) frame).addStaticMethod(methodFrameNameIdent);
}
else {
- ((ClassFrame) frame).addInstanceMethod(ident);
+ ((ClassFrame) frame).addInstanceMethod(methodFrameNameIdent);
}
}
- frameStack.addFirst(new MethodFrame(frame));
+ frameStack.addFirst(new MethodFrame(frame, methodFrameNameIdent));
break;
case TokenTypes.CTOR_DEF :
- frameStack.addFirst(new MethodFrame(frame));
+ final DetailAST ctorFrameNameIdent = ast.findFirstToken(TokenTypes.IDENT);
+ frameStack.addFirst(new ConstructorFrame(frame, ctorFrameNameIdent));
break;
default:
// do nothing
@@ -321,9 +357,9 @@ public class RequireThisCheck extends AbstractCheck {
}
/**
- * Collect Variable Declarations.
- * @param ast variable token
- * @param frame current frame
+ * Collects variable declarations.
+ * @param ast variable token.
+ * @param frame current frame.
*/
private static void collectVariableDeclarations(DetailAST ast, AbstractFrame frame) {
final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
@@ -344,13 +380,11 @@ public class RequireThisCheck extends AbstractCheck {
}
/**
- * End parsing of the AST for declarations.
- *
- * @param frameStack Stack containing the FrameTree being built
- * @param ast AST that was parsed
+ * Ends parsing of the AST for declarations.
+ * @param frameStack Stack containing the FrameTree being built.
+ * @param ast AST that was parsed.
*/
- private void endCollectingDeclarations(Queue frameStack,
- DetailAST ast) {
+ private void endCollectingDeclarations(Queue frameStack, DetailAST ast) {
switch (ast.getType()) {
case TokenTypes.CLASS_DEF :
case TokenTypes.INTERFACE_DEF :
@@ -367,33 +401,389 @@ public class RequireThisCheck extends AbstractCheck {
}
/**
- * Check if given name is a name for class field in current environment.
- * @param ast an IDENT ast to check
- * @return frame, where the field is declared, if the violation is found and null otherwise
+ * Returns the class frame where violation is found (where the field is used without 'this')
+ * or null otherwise.
+ * @param ast IDENT ast to check.
+ * @return the class frame where violation is found or null otherwise.
*/
- private AbstractFrame checkField(DetailAST ast) {
- final AbstractFrame frame = findFrame(ast, false);
- if (frame != null
- && frame.getType() == FrameType.CLASS_FRAME
- && ((ClassFrame) frame).hasInstanceMember(ast)) {
- return frame;
+ private AbstractFrame getClassFrameWhereViolationIsFound(DetailAST ast) {
+ AbstractFrame frameWhereViolationIsFound = null;
+ final AbstractFrame variableDeclarationFrame = findFrame(ast, false);
+ if (variableDeclarationFrame != null) {
+ final FrameType variableDeclarationFrameType = variableDeclarationFrame.getType();
+ final DetailAST prevSibling = ast.getPreviousSibling();
+ if (variableDeclarationFrameType == FrameType.CLASS_FRAME
+ && !validateOnlyOverlapping
+ && prevSibling == null
+ && !ScopeUtils.isInInterfaceBlock(ast)
+ && canBeReferencedFromStaticContext(ast)) {
+ frameWhereViolationIsFound = variableDeclarationFrame;
+ }
+ else if (variableDeclarationFrameType == FrameType.METHOD_FRAME) {
+ if (isOverlappingByArgument(ast)) {
+ if (!isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)
+ && !isReturnedVariable(variableDeclarationFrame, ast)
+ && canBeReferencedFromStaticContext(ast)
+ && canAssignValueToClassField(ast)) {
+ frameWhereViolationIsFound = findFrame(ast, true);
+ }
+ }
+ else if (!validateOnlyOverlapping
+ && prevSibling == null
+ && isAssignToken(ast.getParent().getType())
+ && !isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)
+ && canBeReferencedFromStaticContext(ast)
+ && canAssignValueToClassField(ast)) {
+ frameWhereViolationIsFound = findFrame(ast, true);
+
+ }
+ }
+ else if (variableDeclarationFrameType == FrameType.CTOR_FRAME
+ && isOverlappingByArgument(ast)
+ && !isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)) {
+ frameWhereViolationIsFound = findFrame(ast, true);
+ }
+ else if (variableDeclarationFrameType == FrameType.BLOCK_FRAME) {
+ if (isOverlappingByLocalVariable(ast)) {
+ if (canAssignValueToClassField(ast)
+ && !isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)
+ && !isReturnedVariable(variableDeclarationFrame, ast)
+ && canBeReferencedFromStaticContext(ast)) {
+ frameWhereViolationIsFound = findFrame(ast, true);
+ }
+ }
+ else if (!validateOnlyOverlapping
+ && prevSibling == null
+ && isAssignToken(ast.getParent().getType())
+ && !isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)
+ && canBeReferencedFromStaticContext(ast)) {
+ frameWhereViolationIsFound = findFrame(ast, true);
+ }
+ }
}
- return null;
+ return frameWhereViolationIsFound;
}
/**
- * Check if given name is a name for class method in current environment.
- * @param ast the IDENT ast of the name to check
- * @return frame, where the method is declared, if the violation is found and null otherwise
+ * Checks whether user arranges 'this' for variable in method, constructor, or block on his own.
+ * @param currentFrame current frame.
+ * @param ident ident token.
+ * @return true if user arranges 'this' for variable in method, constructor,
+ * or block on his own.
*/
- private AbstractFrame checkMethod(DetailAST ast) {
+ private static boolean isUserDefinedArrangementOfThis(AbstractFrame currentFrame,
+ DetailAST ident) {
+ final DetailAST blockFrameNameIdent = currentFrame.getFrameNameIdent();
+ final DetailAST definitionToken = blockFrameNameIdent.getParent();
+ final DetailAST blockStartToken = definitionToken.findFirstToken(TokenTypes.SLIST);
+ final DetailAST blockEndToken = getBlockEndToken(blockFrameNameIdent, blockStartToken);
+
+ final Set variableUsagesInsideBlock =
+ getAllTokensWhichAreEqualToCurrent(definitionToken, ident, blockEndToken.getLineNo());
+
+ boolean userDefinedArrangementOfThis = false;
+ for (DetailAST variableUsage : variableUsagesInsideBlock) {
+ final DetailAST prevSibling = variableUsage.getPreviousSibling();
+ if (prevSibling != null
+ && prevSibling.getType() == TokenTypes.LITERAL_THIS) {
+ userDefinedArrangementOfThis = true;
+ }
+ }
+ return userDefinedArrangementOfThis;
+ }
+
+ /**
+ * Returns the token which ends the code block.
+ * @param blockNameIdent block name identifier.
+ * @param blockStartToken token which starts the block.
+ * @return the token which ends the code block.
+ */
+ private static DetailAST getBlockEndToken(DetailAST blockNameIdent, DetailAST blockStartToken) {
+ final Set rcurlyTokens = getAllTokensOfType(blockNameIdent, TokenTypes.RCURLY);
+ DetailAST blockEndToken = null;
+ for (DetailAST currentRcurly : rcurlyTokens) {
+ final DetailAST parent = currentRcurly.getParent();
+ if (blockStartToken.getLineNo() == parent.getLineNo()) {
+ blockEndToken = currentRcurly;
+ }
+ }
+ return blockEndToken;
+ }
+
+ /**
+ * Checks whether the current variable is returned from the method.
+ * @param currentFrame current frame.
+ * @param ident variable ident token.
+ * @return true if the current variable is returned from the method.
+ */
+ private static boolean isReturnedVariable(AbstractFrame currentFrame, DetailAST ident) {
+ final DetailAST blockFrameNameIdent = currentFrame.getFrameNameIdent();
+ final DetailAST definitionToken = blockFrameNameIdent.getParent();
+ final DetailAST blockStartToken = definitionToken.findFirstToken(TokenTypes.SLIST);
+ final DetailAST blockEndToken = getBlockEndToken(blockFrameNameIdent, blockStartToken);
+
+ final Set returnsInsideBlock = getAllTokensOfType(definitionToken,
+ TokenTypes.LITERAL_RETURN, blockEndToken.getLineNo());
+
+ boolean returnedVariable = false;
+ for (DetailAST returnToken : returnsInsideBlock) {
+ returnedVariable = returnToken.findAll(ident).hasMoreNodes();
+ if (returnedVariable) {
+ break;
+ }
+ }
+ return returnedVariable;
+ }
+
+ /**
+ * Checks whether a field can be referenced from a static context.
+ * @param ident ident token.
+ * @return true if field can be referenced from a static context.
+ */
+ private boolean canBeReferencedFromStaticContext(DetailAST ident) {
+ AbstractFrame variableDeclarationFrame = findFrame(ident, false);
+ boolean staticInitializationBlock = false;
+ while (variableDeclarationFrame.getType() == FrameType.BLOCK_FRAME) {
+ final DetailAST blockFrameNameIdent = variableDeclarationFrame.getFrameNameIdent();
+ final DetailAST definitionToken = blockFrameNameIdent.getParent();
+ if (definitionToken.getType() == TokenTypes.STATIC_INIT) {
+ staticInitializationBlock = true;
+ break;
+ }
+ variableDeclarationFrame = variableDeclarationFrame.getParent();
+ }
+
+ boolean staticContext = false;
+ if (staticInitializationBlock) {
+ staticContext = true;
+ }
+ else {
+ if (variableDeclarationFrame.getType() == FrameType.CLASS_FRAME) {
+ final DetailAST codeBlockDefinition = getCodeBlockDefinitionToken(ident);
+ if (codeBlockDefinition != null) {
+ final DetailAST modifiers = codeBlockDefinition.getFirstChild();
+ staticContext = codeBlockDefinition.getType() == TokenTypes.STATIC_INIT
+ || modifiers.branchContains(TokenTypes.LITERAL_STATIC);
+ }
+ }
+ else {
+ final DetailAST frameNameIdent = variableDeclarationFrame.getFrameNameIdent();
+ final DetailAST definitionToken = frameNameIdent.getParent();
+ staticContext = definitionToken.branchContains(TokenTypes.LITERAL_STATIC);
+ }
+ }
+ return !staticContext;
+ }
+
+ /**
+ * Returns code block definition token for current identifier.
+ * @param ident ident token.
+ * @return code block definition token for current identifier or null if code block
+ * definition was not found.
+ */
+ private static DetailAST getCodeBlockDefinitionToken(DetailAST ident) {
+ DetailAST parent = ident.getParent();
+ while (parent != null
+ && parent.getType() != TokenTypes.METHOD_DEF
+ && parent.getType() != TokenTypes.CTOR_DEF
+ && parent.getType() != TokenTypes.STATIC_INIT) {
+ parent = parent.getParent();
+ }
+ return parent;
+ }
+
+ /**
+ * Checks whether a value can be assigned to a field.
+ * A value can be assigned to a final field only in constructor block. If there is a method
+ * block, value assignment can be performed only to non final field.
+ * @param ast an identifier token.
+ * @return true if a value can be assigned to a field.
+ */
+ private boolean canAssignValueToClassField(DetailAST ast) {
+ final AbstractFrame fieldUsageFrame = findFrame(ast, false);
+ final boolean fieldUsageInConstructor = isInsideConstructorFrame(fieldUsageFrame);
+
+ final AbstractFrame declarationFrame = findFrame(ast, true);
+ boolean finalField = false;
+ if (declarationFrame != null) {
+ finalField = ((ClassFrame) declarationFrame).hasFinalField(ast);
+ }
+
+ return fieldUsageInConstructor || !finalField;
+ }
+
+ /**
+ * Checks whether a field usage frame is inside constructor frame.
+ * @param frame frame, where field is used.
+ * @return true if the field usage frame is inside constructor frame.
+ */
+ private static boolean isInsideConstructorFrame(AbstractFrame frame) {
+ boolean assignmentInConstructor = false;
+ AbstractFrame fieldUsageFrame = frame;
+ if (fieldUsageFrame.getType() == FrameType.BLOCK_FRAME) {
+ while (fieldUsageFrame.getType() == FrameType.BLOCK_FRAME) {
+ fieldUsageFrame = fieldUsageFrame.getParent();
+ }
+ if (fieldUsageFrame.getType() == FrameType.CTOR_FRAME) {
+ assignmentInConstructor = true;
+ }
+ }
+ return assignmentInConstructor;
+ }
+
+ /**
+ * Checks whether an overlapping by method or constructor argument takes place.
+ * @param ast an identifier.
+ * @return true if an overlapping by method or constructor argument takes place.
+ */
+ private boolean isOverlappingByArgument(DetailAST ast) {
+ boolean overlapping = false;
+ final DetailAST parent = ast.getParent();
+ final DetailAST sibling = ast.getNextSibling();
+ if (sibling != null && isAssignToken(parent.getType())) {
+ final ClassFrame classFrame = (ClassFrame) findFrame(ast, true);
+ if (classFrame != null) {
+ final Set exprIdents = getAllTokensOfType(sibling, TokenTypes.IDENT);
+ if (isCompoundAssignToken(parent.getType())) {
+ overlapping = true;
+ }
+ else {
+ overlapping = classFrame.containsFieldOrVariableDef(exprIdents, ast);
+ }
+ }
+ }
+ return overlapping;
+ }
+
+ /**
+ * Checks whether an overlapping by local variable takes place.
+ * @param ast an identifier.
+ * @return true if an overlapping by local variable takes place.
+ */
+ private boolean isOverlappingByLocalVariable(DetailAST ast) {
+ boolean overlapping = false;
+ final DetailAST parent = ast.getParent();
+ final DetailAST sibling = ast.getNextSibling();
+ if (sibling != null && isAssignToken(parent.getType())) {
+ final ClassFrame classFrame = (ClassFrame) findFrame(ast, true);
+ if (classFrame != null) {
+ final Set exprIdents = getAllTokensOfType(sibling, TokenTypes.IDENT);
+ if (classFrame.hasInstanceMember(ast)) {
+ overlapping = classFrame.containsFieldOrVariableDef(exprIdents, ast);
+ }
+ }
+ }
+ return overlapping;
+ }
+
+ /**
+ * Collects all tokens of specific type starting with the current ast node.
+ * @param ast ast node.
+ * @param tokenType token type.
+ * @return a set of all tokens of specific type starting with the current ast node.
+ */
+ private static Set getAllTokensOfType(DetailAST ast, int tokenType) {
+ DetailAST vertex = ast;
+ final Set result = Sets.newHashSet();
+ final Deque stack = Queues.newArrayDeque();
+ while (vertex != null || !stack.isEmpty()) {
+ if (!stack.isEmpty()) {
+ vertex = stack.pop();
+ }
+ while (vertex != null) {
+ if (vertex.getType() == tokenType) {
+ result.add(vertex);
+ }
+ if (vertex.getNextSibling() != null) {
+ stack.push(vertex.getNextSibling());
+ }
+ vertex = vertex.getFirstChild();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Collects all tokens of specific type starting with the current ast node and which line
+ * number is lower or equal to the end line number.
+ * @param ast ast node.
+ * @param tokenType token type.
+ * @param endLineNumber end line number.
+ * @return a set of all tokens of specific type starting with the current ast node and which
+ * line number is lower or equal to the end line number.
+ */
+ private static Set getAllTokensOfType(DetailAST ast, int tokenType,
+ int endLineNumber) {
+ DetailAST vertex = ast;
+ final Set result = Sets.newHashSet();
+ final Deque stack = Queues.newArrayDeque();
+ while (vertex != null || !stack.isEmpty()) {
+ if (!stack.isEmpty()) {
+ vertex = stack.pop();
+ }
+ while (vertex != null) {
+ if (tokenType == vertex.getType()
+ && vertex.getLineNo() <= endLineNumber) {
+ result.add(vertex);
+ }
+ if (vertex.getNextSibling() != null) {
+ stack.push(vertex.getNextSibling());
+ }
+ vertex = vertex.getFirstChild();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Collects all tokens which are equal to current token starting with the current ast node and
+ * which line number is lower or equal to the end line number.
+ * @param ast ast node.
+ * @param token token.
+ * @param endLineNumber end line number.
+ * @return a set of tokens which are equal to current token starting with the current ast node
+ * and which line number is lower or equal to the end line number.
+ */
+ private static Set getAllTokensWhichAreEqualToCurrent(DetailAST ast, DetailAST token,
+ int endLineNumber) {
+ DetailAST vertex = ast;
+ final Set result = Sets.newHashSet();
+ final Deque stack = Queues.newArrayDeque();
+ while (vertex != null || !stack.isEmpty()) {
+ if (!stack.isEmpty()) {
+ vertex = stack.pop();
+ }
+ while (vertex != null) {
+ if (token.equals(vertex)
+ && vertex.getLineNo() <= endLineNumber) {
+ result.add(vertex);
+ }
+ if (vertex.getNextSibling() != null) {
+ stack.push(vertex.getNextSibling());
+ }
+ vertex = vertex.getFirstChild();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns the frame where the method is declared, if the given method is used without
+ * 'this' and null otherwise.
+ * @param ast the IDENT ast of the name to check.
+ * @return the frame where the method is declared, if the given method is used without
+ * 'this' and null otherwise.
+ */
+ private AbstractFrame getMethodWithoutThis(DetailAST ast) {
+ AbstractFrame result = null;
final AbstractFrame frame = findFrame(ast, true);
if (frame != null
- && ((ClassFrame) frame).hasInstanceMethod(ast)
- && !((ClassFrame) frame).hasStaticMethod(ast)) {
- return frame;
+ && !validateOnlyOverlapping
+ && ((ClassFrame) frame).hasInstanceMethod(ast)
+ && !((ClassFrame) frame).hasStaticMethod(ast)) {
+ result = frame;
}
- return null;
+ return result;
}
/**
@@ -403,25 +793,45 @@ public class RequireThisCheck extends AbstractCheck {
* @return AbstractFrame containing declaration or null.
*/
private AbstractFrame findFrame(DetailAST name, boolean lookForMethod) {
+ final AbstractFrame result;
if (current == null) {
- return null;
+ result = null;
}
else {
- return current.getIfContains(name, lookForMethod);
+ result = current.getIfContains(name, lookForMethod);
}
+ return result;
}
/**
* Check that token is related to Definition tokens.
- * @param parentType token Type
- * @return true if token is related to Definition Tokens
+ * @param parentType token Type.
+ * @return true if token is related to Definition Tokens.
*/
private static boolean isDeclarationToken(int parentType) {
return DECLARATION_TOKENS.contains(parentType);
}
/**
- * Get the name of the nearest parent ClassFrame.
+ * Check that token is related to assign tokens.
+ * @param tokenType token type.
+ * @return true if token is related to assign tokens.
+ */
+ private static boolean isAssignToken(int tokenType) {
+ return ASSIGN_TOKENS.contains(tokenType);
+ }
+
+ /**
+ * Check that token is related to compound assign tokens.
+ * @param tokenType token type.
+ * @return true if token is related to compound assign tokens.
+ */
+ private static boolean isCompoundAssignToken(int tokenType) {
+ return COMPOUND_ASSIGN_TOKENS.contains(tokenType);
+ }
+
+ /**
+ * Gets the name of the nearest parent ClassFrame.
* @return the name of the nearest parent ClassFrame.
*/
private String getNearestClassFrameName() {
@@ -436,6 +846,8 @@ public class RequireThisCheck extends AbstractCheck {
private enum FrameType {
/** Class frame type. */
CLASS_FRAME,
+ /** Constructor frame type. */
+ CTOR_FRAME,
/** Method frame type. */
METHOD_FRAME,
/** Block frame type. */
@@ -445,30 +857,26 @@ public class RequireThisCheck extends AbstractCheck {
/**
* A declaration frame.
* @author Stephen Bloch
+ * @author Andrei Selkin
*/
private abstract static class AbstractFrame {
/** Set of name of variables declared in this frame. */
private final Set varIdents;
- /**
- * Parent frame.
- */
+ /** Parent frame. */
private final AbstractFrame parent;
- /**
- * Frame name.
- */
- private final String frameName;
+ /** Name identifier token. */
+ private final DetailAST frameNameIdent;
/**
* Constructor -- invokable only via super() from subclasses.
- *
- * @param parent parent frame
- * @param frameName frame name
+ * @param parent parent frame.
+ * @param ident frame name ident.
*/
- protected AbstractFrame(AbstractFrame parent, String frameName) {
+ protected AbstractFrame(AbstractFrame parent, DetailAST ident) {
this.parent = parent;
- this.frameName = frameName;
+ frameNameIdent = ident;
varIdents = Sets.newHashSet();
}
@@ -480,7 +888,7 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Add a name to the frame.
- * @param identToAdd the name we're adding
+ * @param identToAdd the name we're adding.
*/
private void addIdent(DetailAST identToAdd) {
varIdents.add(identToAdd);
@@ -491,18 +899,24 @@ public class RequireThisCheck extends AbstractCheck {
}
protected String getFrameName() {
- return frameName;
+ return frameNameIdent.getText();
}
- /** Check whether the frame contains a field or a variable with the given name.
- * @param nameToFind the IDENT ast of the name we're looking for
- * @return whether it was found
+ public DetailAST getFrameNameIdent() {
+ return frameNameIdent;
+ }
+
+ /**
+ * Check whether the frame contains a field or a variable with the given name.
+ * @param nameToFind the IDENT ast of the name we're looking for.
+ * @return whether it was found.
*/
protected boolean containsFieldOrVariable(DetailAST nameToFind) {
return containsFieldOrVariableDef(varIdents, nameToFind);
}
- /** Check whether the frame contains a given name.
+ /**
+ * Check whether the frame contains a given name.
* @param nameToFind IDENT ast of the name we're looking for.
* @param lookForMethod whether we are looking for a method name.
* @return whether it was found.
@@ -524,7 +938,7 @@ public class RequireThisCheck extends AbstractCheck {
* Whether the set contains a declaration with the text of the specified
* IDENT ast and it is declared in a proper position.
* @param set the set of declarations.
- * @param ident the specified IDENT ast
+ * @param ident the specified IDENT ast.
* @return true if the set contains a declaration with the text of the specified
* IDENT ast and it is declared in a proper position.
*/
@@ -560,8 +974,8 @@ public class RequireThisCheck extends AbstractCheck {
private static boolean checkPosition(DetailAST ast1, DetailAST ast2) {
boolean result = false;
if (ast1.getLineNo() < ast2.getLineNo()
- || ast1.getLineNo() == ast2.getLineNo()
- && ast1.getColumnNo() < ast2.getColumnNo()) {
+ || ast1.getLineNo() == ast2.getLineNo()
+ && ast1.getColumnNo() < ast2.getColumnNo()) {
result = true;
}
return result;
@@ -569,16 +983,19 @@ public class RequireThisCheck extends AbstractCheck {
}
/**
- * A frame initiated at method definition; holds parameter names.
+ * A frame initiated at method definition; holds a method definition token.
* @author Stephen Bloch
+ * @author Andrei Selkin
*/
private static class MethodFrame extends AbstractFrame {
+
/**
* Creates method frame.
- * @param parent parent frame
+ * @param parent parent frame.
+ * @param ident method name identifier token.
*/
- protected MethodFrame(AbstractFrame parent) {
- super(parent, null);
+ protected MethodFrame(AbstractFrame parent, DetailAST ident) {
+ super(parent, ident);
}
@Override
@@ -587,9 +1004,31 @@ public class RequireThisCheck extends AbstractCheck {
}
}
+ /**
+ * A frame initiated at constructor definition.
+ * @author Andrei Selkin
+ */
+ private static class ConstructorFrame extends AbstractFrame {
+
+ /**
+ * Creates a constructor frame.
+ * @param parent parent frame.
+ * @param ident frame name ident.
+ */
+ protected ConstructorFrame(AbstractFrame parent, DetailAST ident) {
+ super(parent, ident);
+ }
+
+ @Override
+ protected FrameType getType() {
+ return FrameType.CTOR_FRAME;
+ }
+ }
+
/**
* A frame initiated at class< enum or interface definition; holds instance variable names.
* @author Stephen Bloch
+ * @author Andrei Selkin
*/
private static class ClassFrame extends AbstractFrame {
/** Set of idents of instance members declared in this frame. */
@@ -603,11 +1042,11 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Creates new instance of ClassFrame.
- * @param parent parent frame
- * @param frameName frame name
+ * @param parent parent frame.
+ * @param ident frame name ident.
*/
- ClassFrame(AbstractFrame parent, String frameName) {
- super(parent, frameName);
+ ClassFrame(AbstractFrame parent, DetailAST ident) {
+ super(parent, ident);
instanceMembers = Sets.newHashSet();
instanceMethods = Sets.newHashSet();
staticMembers = Sets.newHashSet();
@@ -621,7 +1060,7 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Adds static member's ident.
- * @param ident an ident of static member of the class
+ * @param ident an ident of static member of the class.
*/
public void addStaticMember(final DetailAST ident) {
staticMembers.add(ident);
@@ -629,7 +1068,7 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Adds static method's name.
- * @param ident an ident of static method of the class
+ * @param ident an ident of static method of the class.
*/
public void addStaticMethod(final DetailAST ident) {
staticMethods.add(ident);
@@ -637,7 +1076,7 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Adds instance member's ident.
- * @param ident an ident of instance member of the class
+ * @param ident an ident of instance member of the class.
*/
public void addInstanceMember(final DetailAST ident) {
instanceMembers.add(ident);
@@ -645,7 +1084,7 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Adds instance method's name.
- * @param ident an ident of instance method of the class
+ * @param ident an ident of instance method of the class.
*/
public void addInstanceMethod(final DetailAST ident) {
instanceMethods.add(ident);
@@ -653,9 +1092,9 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Checks if a given name is a known instance member of the class.
- * @param ident the IDENT ast of the name to check
+ * @param ident the IDENT ast of the name to check.
* @return true is the given name is a name of a known
- * instance member of the class
+ * instance member of the class.
*/
public boolean hasInstanceMember(final DetailAST ident) {
return containsFieldOrVariableDef(instanceMembers, ident);
@@ -663,9 +1102,9 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Checks if a given name is a known instance method of the class.
- * @param ident the IDENT ast of the method call to check
+ * @param ident the IDENT ast of the method call to check.
* @return true if the given ast is correspondent to a known
- * instance method of the class
+ * instance method of the class.
*/
public boolean hasInstanceMethod(final DetailAST ident) {
return containsMethodDef(instanceMethods, ident);
@@ -673,14 +1112,31 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Checks if a given name is a known static method of the class.
- * @param ident the IDENT ast of the method call to check
+ * @param ident the IDENT ast of the method call to check.
* @return true is the given ast is correspondent to a known
- * instance method of the class
+ * instance method of the class.
*/
public boolean hasStaticMethod(final DetailAST ident) {
return containsMethodDef(staticMethods, ident);
}
+ /**
+ * Checks whether given instance member has final modifier.
+ * @param instanceMember an instance member of a class.
+ * @return true if given instance member has final modifier.
+ */
+ public boolean hasFinalField(final DetailAST instanceMember) {
+ boolean result = false;
+ for (DetailAST member : instanceMembers) {
+ final DetailAST mods = member.getParent().findFirstToken(TokenTypes.MODIFIERS);
+ final boolean finalMod = mods.branchContains(TokenTypes.FINAL);
+ if (finalMod && member.equals(instanceMember)) {
+ result = true;
+ }
+ }
+ return result;
+ }
+
@Override
protected boolean containsFieldOrVariable(DetailAST nameToFind) {
return containsFieldOrVariableDef(instanceMembers, nameToFind)
@@ -745,11 +1201,11 @@ public class RequireThisCheck extends AbstractCheck {
*/
private boolean isSimilarSignature(DetailAST ident, DetailAST ast) {
boolean result = false;
- if (ident.getText().equals(ast.getText())) {
- final int paramsNumber = ast.getParent().findFirstToken(TokenTypes.PARAMETERS)
- .getChildCount();
- final int argsNumber = ident.getParent().findFirstToken(TokenTypes.ELIST)
- .getChildCount();
+ final DetailAST elistToken = ident.getParent().findFirstToken(TokenTypes.ELIST);
+ if (elistToken != null && ident.getText().equals(ast.getText())) {
+ final int paramsNumber =
+ ast.getParent().findFirstToken(TokenTypes.PARAMETERS).getChildCount();
+ final int argsNumber = elistToken.getChildCount();
result = paramsNumber == argsNumber;
}
return result;
@@ -764,10 +1220,11 @@ public class RequireThisCheck extends AbstractCheck {
/**
* Creates block frame.
- * @param parent parent frame
+ * @param parent parent frame.
+ * @param ident ident frame name ident.
*/
- protected BlockFrame(AbstractFrame parent) {
- super(parent, null);
+ protected BlockFrame(AbstractFrame parent, DetailAST ident) {
+ super(parent, ident);
}
@Override
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/RequireThisCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/RequireThisCheckTest.java
index c138322dd..5c69dd518 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/RequireThisCheckTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/RequireThisCheckTest.java
@@ -30,7 +30,6 @@ import org.junit.Assert;
import org.junit.Test;
import antlr.CommonHiddenStreamToken;
-
import com.puppycrawl.tools.checkstyle.BaseCheckTestSupport;
import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
@@ -47,12 +46,14 @@ public class RequireThisCheckTest extends BaseCheckTestSupport {
public void testIt() throws Exception {
final DefaultConfiguration checkConfig =
createCheckConfig(RequireThisCheck.class);
+ checkConfig.addAttribute("validateOnlyOverlapping", "false");
final String[] expected = {
"11:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
"17:9: " + getCheckMessage(MSG_METHOD, "method1", ""),
"31:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
"49:13: " + getCheckMessage(MSG_VARIABLE, "z", ""),
"56:9: " + getCheckMessage(MSG_VARIABLE, "z", ""),
+ "86:16: " + getCheckMessage(MSG_VARIABLE, "CONST", ""),
"113:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
"114:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
"115:9: " + getCheckMessage(MSG_METHOD, "instanceMethod", ""),
@@ -70,6 +71,7 @@ public class RequireThisCheckTest extends BaseCheckTestSupport {
final DefaultConfiguration checkConfig =
createCheckConfig(RequireThisCheck.class);
checkConfig.addAttribute("checkFields", "false");
+ checkConfig.addAttribute("validateOnlyOverlapping", "false");
final String[] expected = {
"17:9: " + getCheckMessage(MSG_METHOD, "method1", ""),
"115:9: " + getCheckMessage(MSG_METHOD, "instanceMethod", ""),
@@ -86,11 +88,13 @@ public class RequireThisCheckTest extends BaseCheckTestSupport {
final DefaultConfiguration checkConfig =
createCheckConfig(RequireThisCheck.class);
checkConfig.addAttribute("checkMethods", "false");
+ checkConfig.addAttribute("validateOnlyOverlapping", "false");
final String[] expected = {
"11:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
"31:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
"49:13: " + getCheckMessage(MSG_VARIABLE, "z", ""),
"56:9: " + getCheckMessage(MSG_VARIABLE, "z", ""),
+ "86:16: " + getCheckMessage(MSG_VARIABLE, "CONST", ""),
"113:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
"114:9: " + getCheckMessage(MSG_VARIABLE, "i", ""),
"122:13: " + getCheckMessage(MSG_VARIABLE, "i", "Issue2240."),
@@ -104,6 +108,7 @@ public class RequireThisCheckTest extends BaseCheckTestSupport {
public void testGenerics() throws Exception {
final DefaultConfiguration checkConfig =
createCheckConfig(RequireThisCheck.class);
+ checkConfig.addAttribute("validateOnlyOverlapping", "false");
final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY;
verify(checkConfig, getPath("Input15Extensions.java"), expected);
}
@@ -112,6 +117,7 @@ public class RequireThisCheckTest extends BaseCheckTestSupport {
public void testGithubIssue41() throws Exception {
final DefaultConfiguration checkConfig =
createCheckConfig(RequireThisCheck.class);
+ checkConfig.addAttribute("validateOnlyOverlapping", "false");
final String[] expected = {
"7:19: " + getCheckMessage(MSG_VARIABLE, "number", ""),
"8:16: " + getCheckMessage(MSG_METHOD, "other", ""),
@@ -132,6 +138,7 @@ public class RequireThisCheckTest extends BaseCheckTestSupport {
@Test
public void testWithAnonymousClass() throws Exception {
final DefaultConfiguration checkConfig = createCheckConfig(RequireThisCheck.class);
+ checkConfig.addAttribute("validateOnlyOverlapping", "false");
final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY;
verify(checkConfig,
getPath("InputRequireThis3.java"),
@@ -145,4 +152,120 @@ public class RequireThisCheckTest extends BaseCheckTestSupport {
ast.initialize(new CommonHiddenStreamToken(TokenTypes.ENUM, "ENUM"));
check.visitToken(ast);
}
+
+ @Test
+ public void testValidateOnlyOverlappingFalse() throws Exception {
+ final DefaultConfiguration checkConfig = createCheckConfig(RequireThisCheck.class);
+ checkConfig.addAttribute("validateOnlyOverlapping", "false");
+ final String[] expected = {
+ "20:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "21:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
+ "22:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
+ "23:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
+
+ "27:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
+ "28:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
+ "29:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
+
+ "33:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
+ "37:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
+
+ "41:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
+ "43:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "45:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
+
+ "49:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
+ "50:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
+
+ "60:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
+ "61:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
+
+ "80:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "84:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+
+ "119:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "128:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "132:9: " + getCheckMessage(MSG_METHOD, "method1", ""),
+
+ "168:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
+ "169:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
+ "170:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
+ "172:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "176:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal1", ""),
+ "177:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal2", ""),
+ "178:9: " + getCheckMessage(MSG_VARIABLE, "fieldFinal3", ""),
+ "180:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "185:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "189:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "210:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "215:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "225:21: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "228:21: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "238:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "253:9: " + getCheckMessage(MSG_VARIABLE, "booleanField", ""),
+
+ "262:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "270:18: " + getCheckMessage(MSG_METHOD, "addSuffixToField", ""),
+
+ "275:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "275:18: " + getCheckMessage(MSG_METHOD, "addSuffixToField", ""),
+
+ "301:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "340:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+
+ "360:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+
+ "374:40: " + getCheckMessage(MSG_METHOD, "getServletRelativeAction", ""),
+ "376:20: " + getCheckMessage(MSG_METHOD, "processAction", ""),
+ "383:9: " + getCheckMessage(MSG_VARIABLE, "servletRelativeAction", ""),
+ "384:16: " + getCheckMessage(MSG_METHOD, "processAction", ""),
+
+ "443:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+ "447:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+ "451:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+
+ "455:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+ "459:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+ "463:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+
+ };
+ verify(checkConfig, getPath("InputValidateOnlyOverlappingFalse.java"), expected);
+ }
+
+ @Test
+ public void testValidateOnlyOverlappingTrue() throws Exception {
+ final DefaultConfiguration checkConfig = createCheckConfig(RequireThisCheck.class);
+ final String[] expected = {
+ "20:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "43:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "80:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "119:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "172:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "180:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "238:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "253:9: " + getCheckMessage(MSG_VARIABLE, "booleanField", ""),
+ "262:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "275:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "301:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "339:9: " + getCheckMessage(MSG_VARIABLE, "field1", ""),
+ "359:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+ "442:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+ "450:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+ "454:9: " + getCheckMessage(MSG_VARIABLE, "fieldStatic", ""),
+ };
+ verify(checkConfig, getPath("InputValidateOnlyOverlappingTrue.java"), expected);
+ }
}
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/InputValidateOnlyOverlappingFalse.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/InputValidateOnlyOverlappingFalse.java
new file mode 100644
index 000000000..f9149f25e
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/InputValidateOnlyOverlappingFalse.java
@@ -0,0 +1,469 @@
+package com.puppycrawl.tools.checkstyle.checks.coding;
+
+import java.util.BitSet;
+
+public class InputValidateOnlyOverlappingFalse {
+
+ private static String fieldStatic = "fieldStatic";
+
+ private final long fieldFinal1;
+ private final long fieldFinal2;
+ private final BitSet fieldFinal3;
+
+ private String field1;
+ private String field2;
+ private String field3 = "some string";
+ private boolean booleanField;
+ private int intField;
+
+ public InputValidateOnlyOverlappingFalse(String field1) {
+ field1 = field1; // violation
+ fieldFinal1 = 0; // violation
+ fieldFinal2 = 0; // violation
+ fieldFinal3 = new BitSet(); // violation
+ }
+
+ public InputValidateOnlyOverlappingFalse(long value) {
+ fieldFinal1 = value; // violation
+ fieldFinal2 = 0; // violation
+ fieldFinal3 = new BitSet(); // violation
+ }
+
+ public InputValidateOnlyOverlappingFalse() {
+ fieldFinal1 = 0; // violation
+ long fieldFinal2 = 0L;
+ fieldFinal2 = 1L;
+ this.fieldFinal2 = fieldFinal2;
+ fieldFinal3 = new BitSet(); // violation
+ }
+
+ public InputValidateOnlyOverlappingFalse(String name, long id) {
+ fieldFinal1 = 0; // violation
+ long field1 = 0L;
+ field1 = field1; // violation
+ this.fieldFinal2 = 1L;
+ fieldFinal3 = new BitSet(); // violation
+ }
+
+ public InputValidateOnlyOverlappingFalse(int param) {
+ fieldFinal2 = 0L; // violation
+ fieldFinal3 = new BitSet(); // violation
+ long fieldFinal1 = 1L;
+ try {
+ fieldFinal1 = 2L;
+ }
+ catch (Exception ex) {}
+ this.fieldFinal1 = fieldFinal1;
+ }
+
+ public InputValidateOnlyOverlappingFalse(BitSet fieldFinal3) {
+ fieldFinal1 = 1L; // violation
+ fieldFinal2 = 0L; // violation
+ fieldFinal3 = new BitSet();
+ if (true) {
+ fieldFinal3 = (BitSet) fieldFinal3.clone();
+ }
+ this.fieldFinal3 = fieldFinal3;
+ }
+
+ void foo1(String methodParam) {
+ methodParam = methodParam;
+ }
+
+ void foo2() {
+ String localVar = "values";
+ localVar = localVar;
+ }
+
+ void foo3() {
+ String field1 = "values";
+ field1 = field1; // violation
+ }
+
+ void foo4(String methodParam) {
+ fieldStatic = methodParam; // violation
+ }
+
+ void foo5(String methodParam) {
+ methodParam = methodParam + "string";
+ }
+
+ void foo6(String field1) {
+ field1 = this.field1 + field1;
+ this.field1 = field1 + this.field1;
+ field1 = field1 + this.field1;
+ field1 = this.field1 + this.field1;
+ this.field1 = this.field1 + this.field1;
+ this.field1 = this.field1 + field1;
+ field1 += field1;
+ }
+
+ String addSuffixToParameter(String methodParam) {
+ return methodParam += "suffix";
+ }
+
+ String addSuffixToField(String field1) {
+ return field1 += "suffix";
+ }
+
+ String addSuffixToThisField(String field1) {
+ return this.field1 += "suffix";
+ }
+
+ static void foo7(String fieldStatic) {
+// this.fieldStatic = fieldStatic; <- fieldStatic cannot be referenced from a static context
+ fieldStatic = fieldStatic;
+ }
+
+ void foo8(Long field1) {
+ field1 += field1; // violation
+ }
+
+ void foo9(Long fieldFinal1) {
+// this.fieldFinal1 += fieldFinal1; <- cannot assign value to a final variable
+ fieldFinal1 += fieldFinal1;
+ }
+
+ void method1() {
+ field1 = "2"; // violation
+ }
+
+ void method2() {
+ method1() ; // violation
+ }
+
+ void method3() {
+ staticFoo();
+ staticTwoArgs("message", "arg");
+ staticTwoArgs("message", 1);
+ this.method1() ;
+ }
+
+ static void staticFoo() { }
+
+ static void foo10() {
+ staticFoo();
+ staticTwoArgs("message", "arg");
+ }
+
+// void staticFoo() {} -> compile time error. Already defined in the scope.
+
+ static void staticTwoArgs(String message1, String argument) {}
+
+ void staticTwoArgs(String message1, int argument) {}
+
+ static void foo16() {
+ long fieldFinal1 = 5L;
+// this.fieldFinal1 = fieldFinal1; // compile time error: cannot be referenced from a static context
+ fieldFinal1 = 11L;
+ }
+
+ static void foo17() {
+ String fieldStatic = "";
+// this.fieldStatic = fieldStatic; // compile time error: cannot be referenced from a static context
+ fieldStatic = "Hello, World!";
+ }
+
+ InputValidateOnlyOverlappingFalse(boolean flag) {
+ fieldFinal1 = 0L; // violation
+ fieldFinal2 = 0L; // violation
+ fieldFinal3 = new BitSet(); // violation
+ long field1 = 1L;
+ field1 = field1; // violation
+ }
+
+ InputValidateOnlyOverlappingFalse(boolean flag, String name) {
+ fieldFinal1 = 0L; // violation
+ fieldFinal2 = 0L; // violation
+ fieldFinal3 = new BitSet(); // violation
+ long field1 = 1L;
+ field1 = field1; // violation
+ return;
+ }
+
+ void foo18() {
+ field1 = "Hello"; // violation
+ }
+
+ void foo19(String field1) {
+ field1 = "Hello"; // violation
+ }
+
+ void foo20() {
+ boolean foo21 = this.foo21("");
+ if (foo21) {
+
+ }
+ }
+
+ boolean foo21(String s) {
+ return true;
+ }
+
+ void foo22() {
+ long fieldFinal1 = 1L;
+// this.fieldFinal1 = fieldFinal1; <- cannot assign value to a final variable
+ fieldFinal1 = fieldFinal1;
+ }
+
+ void foo23() {
+ field1 = "Hello!"; // violation
+ }
+
+ void foo24() {
+ String field1 = "Hello";
+ field1 = "Java"; // violation
+ this.booleanField = true;
+ this.booleanField = booleanField;
+ }
+
+ void foo25() {
+ try {
+ if (true) {
+ String field1 = "Hello, World!";
+ if (true) {
+ field1 = new String(); // violation
+ }
+ else {
+ field1 = new String(); // violation
+ }
+ }
+ }
+ catch (Exception ex) {
+
+ }
+ }
+
+ void foo26(String field1) {
+ field1 = field1.replace('/', '*'); // violation
+ }
+
+ void foo27() {
+ int intField = -1;
+ if (intField == -1) {
+ intField = 20;
+ }
+ else {
+ intField = this.intField / 100;
+ }
+ }
+
+ void foo28() {
+ boolean booleanField = true;
+ booleanField = !booleanField; // violation
+ }
+
+ static void foo29(String field1) {
+// this.field1 = true ? "field1" : field1; <- compile time error: cannot be referenced from a static context
+ field1 = true ? "field1" : field1;
+ }
+
+ void foo30(String field1) {
+ field1 = true ? "field1" : field1; // violation
+ }
+
+ void foo31(String field1) {
+ field1 = this.field1;
+ }
+
+ String foo32(String field1) {
+ field1 = addSuffixToField(field1); // no violation!!! it is just modification of parameter which is returned at the end of the method
+ return field1;
+ }
+
+ String foo33(String field1 ) {
+ field1 = addSuffixToField(field1); // violation (no return, variable 'stringField' will not be saved after method execution)
+ return "New String";
+ }
+
+ String foo34(String field1) {
+ field1 = field1.replace('A', 'B');
+ if (field1.contains("C")) {
+ return field1;
+ }
+ else {
+ return field1 + 'C';
+ }
+ }
+
+ String foo35() {
+ String field1 = "values";
+ field1 = field1;
+ return field1;
+ }
+
+ void foo36(String field1) {
+ field1 = field1.replace('/', '*');
+ field1 = this.field1;
+ }
+
+ String foo37(String field1) {
+ field1 += "suffix"; // violation
+ return "New string";
+ }
+
+ static void foo38() {
+// this.fieldStatic = ""; <-- compile time error: cannot be referenced from a static context
+ fieldStatic = "";
+ }
+
+ static void foo39() {
+ boolean booleanField = true;
+// this.booleanField = !booleanField; <-- compile time error: cannot be referenced from a static context
+ booleanField = !booleanField;
+ }
+
+ static void foo40() {
+ try {
+ boolean booleanField = true;
+// this.booleanField = !booleanField; <-- compile time error: cannot be referenced from a static context
+ booleanField = !booleanField;
+ }
+ catch (Exception e) {}
+ }
+
+ static {
+// this.fieldStatic = ""; <-- compile time error: cannot be referenced from a static context
+ fieldStatic = "";
+ }
+
+ {
+// if we assign variable to a final variable in initialization block,
+// it will lead to compile time error in constructor block: variable migh have been
+// already assigned
+
+// fieldFinal1 = 1;
+ }
+
+ {
+ String field1 = "";
+ field1 = field1; // violation
+ }
+
+ static {
+ fieldStatic = "";
+ String field1 = "";
+// this.field1 = field1; <-- compile time error: cannot be referenced from a static context
+ field1 = field1;
+ }
+
+ void foo41(long fieldFinal1) {
+// this.fieldFinal1 = 1L; <- cannot assign value to a final variable
+ fieldFinal1 = fieldFinal1;
+ }
+
+ void foo42(String fieldStatic) {
+ this.fieldStatic = fieldStatic;
+ }
+
+ void foo43(String fieldStatic) {
+ fieldStatic = fieldStatic; // violation
+ }
+
+ void foo44(String fieldStatic) {
+ fieldStatic = this.fieldStatic;
+ }
+
+ private String servletRelativeAction;
+
+ public String getServletRelativeAction() {
+ return this.servletRelativeAction;
+ }
+
+ public String foo45() {
+ String servletRelativeAction = getServletRelativeAction(); // violation (Method call to 'getServletRelativeAction' needs "this.".)
+ if (true) {
+ return processAction("action"); // violation (Method call to 'processAction' needs "this.".)
+ }
+ else if (servletRelativeAction.endsWith("/")) {
+ if (servletRelativeAction.startsWith("/")) {
+ servletRelativeAction = "" + servletRelativeAction;
+ }
+ }
+ servletRelativeAction = "servletRelativeAction"; // violation
+ return processAction(servletRelativeAction); // violation (Method call to 'processAction' needs "this.".)
+ }
+
+ private String processAction(String servletRelativeAction) {
+ return "";
+ }
+
+ public InputValidateOnlyOverlappingFalse(long fieldFinal1, long fieldFinal2,
+ BitSet fieldFinal3, boolean booleanField) {
+ this.fieldFinal1 = fieldFinal1;
+ this.fieldFinal2 = fieldFinal2;
+ this.fieldFinal3 = fieldFinal3;
+
+ booleanField = this.booleanField;
+ if (booleanField) {
+ booleanField = "Hello, World!".equals("Hello, Checkstyle!");
+ }
+
+ this.booleanField = booleanField;
+ }
+
+ void foo46(boolean booleanField) {
+ booleanField = this.booleanField;
+ if (booleanField) {
+ booleanField = "Hello, World!".equals("Hello, Checkstyle!");
+ }
+
+ this.booleanField = booleanField;
+ }
+
+ static void foo47(String fieldStatic) {
+ fieldStatic = "Andrei";
+ }
+
+ void foo48(long fieldFinal1) {
+ fieldFinal1 = 1L;
+ }
+
+ private boolean foo49(boolean booleanField) {
+ boolean suppressionSourceExists = true;
+ try {
+
+ }
+ catch (Exception ex) {
+ suppressionSourceExists = false;
+ }
+ finally {
+ if (booleanField) {
+ try {
+ }
+ catch (Exception ignored) {
+ this.booleanField = false;
+ }
+ }
+ }
+ return suppressionSourceExists;
+ }
+
+ void foo50(String fieldStatic) {
+ fieldStatic = fieldStatic; // violation
+ }
+
+ void foo51(String methodParam) {
+ fieldStatic = methodParam; // violation
+ }
+
+ void foo52(String fieldStatic) {
+ fieldStatic += fieldStatic; // violation
+ }
+
+ void foo53(String fieldStatic) {
+ fieldStatic += fieldStatic; // violation
+ }
+
+ void foo54(String methodParam) {
+ fieldStatic += methodParam; // violation
+ }
+
+ void foo55(String methodParam) {
+ fieldStatic += fieldStatic; // violation
+ }
+
+ void foo56(boolean booleanField) { booleanField = this.booleanField; }
+
+ boolean foo57(boolean booleanField) { booleanField = !booleanField; return booleanField; }
+}
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/InputValidateOnlyOverlappingTrue.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/InputValidateOnlyOverlappingTrue.java
new file mode 100644
index 000000000..9dd288d0d
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/InputValidateOnlyOverlappingTrue.java
@@ -0,0 +1,468 @@
+package com.puppycrawl.tools.checkstyle.checks.coding;
+
+import java.util.BitSet;
+
+public class InputValidateOnlyOverlappingTrue {
+
+ private static String fieldStatic = "fieldStatic";
+
+ private final long fieldFinal1;
+ private final long fieldFinal2;
+ private final BitSet fieldFinal3;
+
+ private String field1;
+ private String field2;
+ private String field3 = "some string";
+ private boolean booleanField;
+ private int intField;
+
+ public InputValidateOnlyOverlappingTrue(String field1) {
+ field1 = field1; // violation
+ fieldFinal1 = 0;
+ fieldFinal2 = 0;
+ fieldFinal3 = new BitSet();
+ }
+
+ public InputValidateOnlyOverlappingTrue(long value) {
+ fieldFinal1 = value;
+ fieldFinal2 = 0;
+ fieldFinal3 = new BitSet();
+ }
+
+ public InputValidateOnlyOverlappingTrue() {
+ fieldFinal1 = 0;
+ long fieldFinal2 = 0L;
+ fieldFinal2 = 1L;
+ this.fieldFinal2 = fieldFinal2;
+ fieldFinal3 = new BitSet();
+ }
+
+ public InputValidateOnlyOverlappingTrue(String name, long id) {
+ fieldFinal1 = 0;
+ long field1 = 0L;
+ field1 = field1; // violation
+ this.fieldFinal2 = 1L;
+ fieldFinal3 = new BitSet();
+ }
+
+ public InputValidateOnlyOverlappingTrue(int param) {
+ fieldFinal2 = 0L;
+ fieldFinal3 = new BitSet();
+ long finalField1 = 1L;
+ try {
+ finalField1 = 2L;
+ }
+ catch (Exception ex) {}
+ this.fieldFinal1 = finalField1;
+ }
+
+ public InputValidateOnlyOverlappingTrue(BitSet fieldFinal3) {
+ fieldFinal1 = 1L;
+ fieldFinal2 = 0L;
+ fieldFinal3 = new BitSet();
+ if (true) {
+ fieldFinal3 = (BitSet) fieldFinal3.clone();
+ }
+ this.fieldFinal3 = fieldFinal3;
+ }
+
+ void foo1(String methodParam) {
+ methodParam = methodParam;
+ }
+
+ void foo2() {
+ String localVar = "values";
+ localVar = localVar;
+ }
+
+ void foo3() {
+ String field1 = "values";
+ field1 = field1; // violation
+ }
+
+ void foo4(String methodParam) {
+ fieldStatic = methodParam;
+ }
+
+ void foo5(String methodParam) {
+ methodParam = methodParam + "string";
+ }
+
+ void foo6(String field1) {
+ field1 = this.field1 + field1;
+ this.field1 = field1 + field1;
+ field1 = field1 + this.field1;
+ field1 = this.field1 + this.field1;
+ this.field1 = this.field1 + this.field1;
+ this.field1 = this.field1 + field1;
+ field1 += field1;
+ }
+
+ String addSuffixToParameter(String methodParam) {
+ return methodParam += "suffix";
+ }
+
+ String addSuffixToField(String field1) {
+ return field1 += "suffix";
+ }
+
+ String addSuffixToThisField(String field1) {
+ return this.field1 += "suffix";
+ }
+
+ static void foo7(String fieldStatic) {
+// this.fieldStatic = fieldStatic; <- fieldStatic cannot be referenced from a static context
+ fieldStatic = fieldStatic;
+ }
+
+ void foo8(Long field1) {
+ field1 += field1; // violation
+ }
+
+ void foo9(Long fieldFinal1) {
+// this.fieldFinal1 += fieldFinal1; <- cannot assign value to a final variable
+ fieldFinal1 += fieldFinal1;
+ }
+
+ void method1() {
+ field1 = "2";
+ }
+
+ void method2() {
+ method1();
+ }
+
+ void method3() {
+ staticFoo();
+ staticTwoArgs("message", "arg");
+ staticTwoArgs("message", 1);
+ this.method1() ;
+ }
+
+ static void staticFoo() { }
+
+ static void foo10() {
+ staticFoo();
+ staticTwoArgs("message", "arg");
+ }
+
+// void staticFoo() {} -> compile time error. Already defined in the scope.
+
+ static void staticTwoArgs(String message1, String argument) {}
+
+ void staticTwoArgs(String message1, int argument) {}
+
+ static void foo16() {
+ long fieldFinal1 = 5L;
+// this.fieldFinal1 = fieldFinal1; // compile time error: cannot be referenced from a static context
+ fieldFinal1 = 11L;
+ }
+
+ static void foo17() {
+ String fieldStatic = "";
+// this.fieldStatic = fieldStatic; // compile time error: cannot be referenced from a static context
+ fieldStatic = "Hello, World!";
+ }
+
+ InputValidateOnlyOverlappingTrue(boolean flag) {
+ fieldFinal1 = 0L;
+ fieldFinal2 = 0L;
+ fieldFinal3 = new BitSet();
+ long field1 = 1L;
+ field1 = field1; // violation
+ }
+
+ InputValidateOnlyOverlappingTrue(boolean flag, String name) {
+ fieldFinal1 = 0L;
+ fieldFinal2 = 0L;
+ fieldFinal3 = new BitSet();
+ long field1 = 1L;
+ field1 = field1; // violation
+ return;
+ }
+
+ void foo18() {
+ field1 = "Hello";
+ }
+
+ void foo19(String field1) {
+ field1 = "Hello";
+ }
+
+ void foo20() {
+ boolean foo21 = this.foo21("");
+ if (foo21) {
+
+ }
+ }
+
+ boolean foo21(String s) {
+ return true;
+ }
+
+ void foo22() {
+ long fieldFinal1 = 1L;
+// this.fieldFinal1 = fieldFinal1; <- cannot assign value to a final variable
+ fieldFinal1 = fieldFinal1;
+ }
+
+ void foo23() {
+ field1 = "Hello!";
+ }
+
+ void foo24() {
+ String field1 = "Hello";
+ field1 = "Java";
+ this.booleanField = true;
+ this.booleanField = booleanField;
+ }
+
+ void foo25() {
+ try {
+ if (true) {
+ String field1 = "Hello, World!";
+ if (true) {
+ field1 = new String();
+ }
+ else {
+ field1 = new String();
+ }
+ }
+ }
+ catch (Exception ex) {
+
+ }
+ }
+
+ void foo26(String field1) {
+ field1 = field1.replace('/', '*'); // violation
+ }
+
+ void foo27() {
+ int intField = -1;
+ if (intField == -1) {
+ intField = 20;
+ }
+ else {
+ intField = this.intField / 100;
+ }
+ }
+
+ void foo28() {
+ boolean booleanField = true;
+ booleanField = !booleanField; // violation
+ }
+
+ static void foo29(String field1) {
+// this.field1 = true ? "field1" : field1; <- compile time error: cannot be referenced from a static context
+ field1 = true ? "field1" : field1;
+ }
+
+ void foo30(String field1) {
+ field1 = true ? "field1" : field1; // violation
+ }
+
+ void foo31(String field1) {
+ field1 = this.field1;
+ }
+
+ String foo32(String field1) {
+ field1 = addSuffixToField(field1); // no violation!!! it is just modification of parameter which is returned at the end of the method
+ return field1;
+ }
+
+ String foo33(String field1) {
+ field1 = addSuffixToField(field1); // violation (no return, variable 'stringField' will not be saved after method execution)
+ return "New String";
+ }
+
+ String foo34(String field1) {
+ field1 = field1.replace('A', 'B');
+ if (field1.contains("C")) {
+ return field1;
+ }
+ else {
+ return field1 + 'C';
+ }
+ }
+
+ String foo35() {
+ String field1 = "values";
+ field1 = field1;
+ return field1;
+ }
+
+ void foo36(String field1) {
+ field1 = field1.replace('/', '*');
+ field1 = this.field1;
+ }
+
+ String foo37(String field1) {
+ field1 += "suffix"; // violation
+ return "New string";
+ }
+
+ static void foo38() {
+// this.fieldStatic = ""; <-- compile time error: cannot be referenced from a static context
+ fieldStatic = "";
+ }
+
+ static void foo39() {
+ boolean booleanField = true;
+// this.booleanField = !booleanField; <-- compile time error: cannot be referenced from a static context
+ booleanField = !booleanField;
+ }
+
+ static void foo40() {
+ try {
+ boolean booleanField = true;
+// this.booleanField = !booleanField; <-- compile time error: cannot be referenced from a static context
+ booleanField = !booleanField;
+ }
+ catch (Exception e) {}
+ }
+
+ static {
+ fieldStatic = "";
+ }
+
+// {
+// if we assign variable to a final variable in initialization block,
+// it will lead to compile time error in constructor block: variable migh have been
+// already assigned
+
+// fieldFinal1 = 1;
+// }
+
+ {
+ String field1 = "";
+ field1 = field1; // violation
+ }
+
+ static {
+ fieldStatic = "";
+ String field1 = "";
+// this.field1 = field1; <-- compile time error: cannot be referenced from a static context
+ field1 = field1;
+ }
+
+ void foo41(long fieldFinal1) {
+// this.fieldFinal1 = 1L; <- cannot assign value to a final variable
+ fieldFinal1 = fieldFinal1;
+ }
+
+ void foo42(String fieldStatic) {
+ this.fieldStatic = fieldStatic;
+ }
+
+ void foo43(String fieldStatic) {
+ fieldStatic = fieldStatic; // violation
+ }
+
+ void foo44(String fieldStatic) {
+ fieldStatic = this.fieldStatic;
+ }
+
+ private String servletRelativeAction;
+
+ public String getServletRelativeAction() {
+ return this.servletRelativeAction;
+ }
+
+ public String foo45() {
+ String servletRelativeAction = getServletRelativeAction();
+ if (true) {
+ return processAction("action");
+ }
+ else if (servletRelativeAction.endsWith("/")) {
+ if (servletRelativeAction.startsWith("/")) {
+ servletRelativeAction = "" + servletRelativeAction;
+ }
+ }
+ servletRelativeAction = "servletRelativeAction";
+ return processAction(servletRelativeAction);
+ }
+
+ private String processAction(String servletRelativeAction) {
+ return "";
+ }
+
+ public InputValidateOnlyOverlappingTrue(long fieldFinal1, long fieldFinal2,
+ BitSet fieldFinal3, boolean booleanField) {
+ this.fieldFinal1 = fieldFinal1;
+ this.fieldFinal2 = fieldFinal2;
+ this.fieldFinal3 = fieldFinal3;
+
+ booleanField = this.booleanField;
+ if (booleanField) {
+ booleanField = "Hello, World!".equals("Hello, Checkstyle!");
+ }
+
+ this.booleanField = booleanField;
+ }
+
+ void foo46(boolean booleanField) {
+ booleanField = this.booleanField;
+ if (booleanField) {
+ booleanField = "Hello, World!".equals("Hello, Checkstyle!");
+ }
+
+ this.booleanField = booleanField;
+ }
+
+ static void foo47(String fieldStatic) {
+ fieldStatic = "Andrei";
+ }
+
+ void foo48(long fieldFinal1) {
+ fieldFinal1 = 1L;
+ }
+
+ private boolean foo49(boolean booleanField) {
+ boolean suppressionSourceExists = true;
+ try {
+
+ }
+ catch (Exception ex) {
+ suppressionSourceExists = false;
+ }
+ finally {
+ if (booleanField) {
+ try {
+ }
+ catch (Exception ignored) {
+ this.booleanField = false;
+ }
+ }
+ }
+ return suppressionSourceExists;
+ }
+
+ void foo50(String fieldStatic) {
+ fieldStatic = fieldStatic; // violation
+ }
+
+ void foo51(String methodParam) {
+ fieldStatic = methodParam;
+ }
+
+ void foo52(String fieldStatic) {
+ fieldStatic += fieldStatic; // violation
+ }
+
+ void foo53(String fieldStatic) {
+ fieldStatic += fieldStatic; // violation
+ }
+
+ void foo54(String methodParam) {
+ fieldStatic += methodParam;
+ }
+
+ void foo55(String methodParam) {
+ fieldStatic += fieldStatic;
+ }
+
+ void foo56(boolean booleanField) { booleanField = this.booleanField; }
+
+ boolean foo57(boolean booleanField) { booleanField = !booleanField; return booleanField; }
+}
diff --git a/src/xdocs/config_coding.xml b/src/xdocs/config_coding.xml
index 20b61d9c9..06f6141b1 100644
--- a/src/xdocs/config_coding.xml
+++ b/src/xdocs/config_coding.xml
@@ -3255,7 +3255,8 @@ public void foo(int i, String s) {}
- Warning: the Check is very controversial and not that actual nowadays.
+ Warning: the Check is very controversial if 'validateOnlyOverlapping' option is set to
+ 'false' and not that actual nowadays.
@@ -3294,6 +3295,12 @@ public void foo(int i, String s) {}
@@ -3313,6 +3320,105 @@ public void foo(int i, String s) {}
<property name="checkMethods" value="false"/>
</module>
+
+
+ Examples of how the check works if validateOnlyOverlapping option is set to true:
+
+
+public static class A {
+ private int field1;
+ private int field2;
+
+ public A(int field1) {
+ // Overlapping by constructor argument.
+ field1 = field1; // violation: Reference to instance variable "field1" needs "this".
+ field2 = 0;
+ }
+
+ void foo3() {
+ String field1 = "values";
+ // Overlapping by local variable.
+ field1 = field1; // violation: Reference to instance variable "field1" needs "this".
+ }
+}
+
+public static class B {
+ private int field1;
+
+ public A(int f) {
+ field1 = f;
+ }
+
+ String addSuffixToField(String field1) {
+ // Overlapping by method argument. Equal to "return field1 = field1 + "suffix";"
+ return field1 += "suffix"; // violation: Reference to instance variable "field1" needs "this".
+ }
+}
+
+
+ Please, be aware of the following logic, which is implemented in the check:
+
+
+ 1) If you arranges 'this' in your code on your own, the check will not rise violation for
+ variables which use 'this' to reference a class field, for example:
+
+
+public class C {
+ private int scale;
+ private int x;
+ public void foo(int scale) {
+ scale = this.scale; // no violation
+ if (scale > 0) {
+ scale = -scale; // no violation
+ }
+ x *= scale;
+ }
+}
+
+
+ 2) If method parameter is returned from the method, the check will not rise violation for
+ returned variable/parameter, for example:
+
+
+public class D {
+ private String prefix;
+ public String modifyPrefix(String prefix) {
+ prefix = "^" + prefix + "$" // no violation (modification of parameter)
+ return prefix; // modified method parameter is returned from the method
+ }
+}
+
+
+ Examples of how the check works if validateOnlyOverlapping option is set to false:
+
+
+public static class A {
+ private int field1;
+ private int field2;
+
+ public A(int field1) {
+ field1 = field1; // violation: Reference to instance variable "field1" needs "this".
+ field2 = 0; // violation: Reference to instance variable "field2" needs "this".
+ }
+
+ void foo3() {
+ String field1 = "values";
+ field1 = field1; // violation: Reference to instance variable "field1" needs "this".
+ }
+ }
+
+public static class B {
+ private int field1;
+
+ public A(int f) {
+ field1 = f; // violation: Reference to instance variable "field1" needs "this".
+ }
+
+ String addSuffixToField(String field1) {
+ return field1 += "suffix"; // violation: Reference to instance variable "field1" needs "this".
+ }
+}
+