Issue #2474: Fix NPE in EqualsAvoidNull check

This commit is contained in:
Vladislav Lisetskiy 2015-10-30 19:54:40 +03:00 committed by Roman Ivanov
parent 91a49a90d4
commit a172cb76e2
2 changed files with 75 additions and 26 deletions

View File

@ -277,7 +277,7 @@ public class EqualsAvoidNullCheck extends Check {
if (isObjectValid(objCalledOn)
&& containsOneArgument(methodCall)
&& containsAllSafeTokens(expr)
&& isCalledOnStringField(objCalledOn)) {
&& isCalledOnStringFieldOrVariable(objCalledOn)) {
final String methodName = methodCall.getFirstChild().getLastChild().getText();
if (EQUALS.equals(methodName)) {
log(methodCall.getLineNo(), methodCall.getColumnNo(),
@ -375,44 +375,85 @@ public class EqualsAvoidNullCheck extends Check {
* @param objCalledOn object ast.
* @return true if the object is of String type.
*/
private boolean isCalledOnStringField(DetailAST objCalledOn) {
boolean result = false;
private boolean isCalledOnStringFieldOrVariable(DetailAST objCalledOn) {
boolean result;
final DetailAST previousSiblingAst = objCalledOn.getPreviousSibling();
final String name = objCalledOn.getText();
if (previousSiblingAst == null) {
FieldFrame frame = currentFrame;
while (frame != null) {
final DetailAST field = frame.findField(name);
if (field != null
&& (frame.isClassOrEnumOrEnumConstDef()
|| checkLineNo(field, objCalledOn))) {
result = STRING.equals(getFieldType(field));
break;
}
frame = frame.getParent();
}
result = isStringFieldOrVariable(objCalledOn);
}
else {
if (previousSiblingAst.getType() == TokenTypes.LITERAL_THIS) {
final DetailAST field = getObjectFrame(currentFrame).findField(name);
result = STRING.equals(getFieldType(field));
result = isStringFieldOrVariableFromThisInstance(objCalledOn);
}
else {
final String className = previousSiblingAst.getText();
FieldFrame frame = getObjectFrame(currentFrame);
while (frame != null) {
if (className.equals(frame.getFrameName())) {
final DetailAST field = frame.findField(name);
result = STRING.equals(getFieldType(field));
break;
}
frame = getObjectFrame(frame.getParent());
}
result = isStringFieldOrVariableFromClass(objCalledOn, className);
}
}
return result;
}
/**
* Whether the field or the variable is of String type.
* @param objCalledOn the field or the variable to check.
* @return true if the field or the variable is of String type.
*/
private boolean isStringFieldOrVariable(DetailAST objCalledOn) {
boolean result = false;
final String name = objCalledOn.getText();
FieldFrame frame = currentFrame;
while (frame != null) {
final DetailAST field = frame.findField(name);
if (field != null
&& (frame.isClassOrEnumOrEnumConstDef()
|| checkLineNo(field, objCalledOn))) {
result = STRING.equals(getFieldType(field));
break;
}
frame = frame.getParent();
}
return result;
}
/**
* Whether the field or the variable from THIS instance is of String type.
* @param objCalledOn the field or the variable from THIS instance to check.
* @return true if the field or the variable from THIS instance is of String type.
*/
private boolean isStringFieldOrVariableFromThisInstance(DetailAST objCalledOn) {
boolean result = false;
final String name = objCalledOn.getText();
final DetailAST field = getObjectFrame(currentFrame).findField(name);
if (field != null) {
result = STRING.equals(getFieldType(field));
}
return result;
}
/**
* Whether the field or the variable from the specified class is of String type.
* @param objCalledOn the field or the variable from the specified class to check.
* @param className the name of the class to check in.
* @return true if the field or the variable from the specified class is of String type.
*/
private boolean isStringFieldOrVariableFromClass(DetailAST objCalledOn,
final String className) {
boolean result = false;
final String name = objCalledOn.getText();
FieldFrame frame = getObjectFrame(currentFrame);
while (frame != null) {
if (className.equals(frame.getFrameName())) {
final DetailAST field = frame.findField(name);
if (field != null) {
result = STRING.equals(getFieldType(field));
}
break;
}
frame = getObjectFrame(frame.getParent());
}
return result;
}
/**
* Get the nearest parent frame which is CLASS_DEF, ENUM_DEF or ENUM_CONST_DEF.
* @param frame to start the search from.

View File

@ -399,3 +399,11 @@ class Anonymous {
}
{}
}
enum TestEnum {
ONE;
public void foo() {
TestEnum.ONE.equals(this);
this.ONE.equals(this);
}
}