IDEA-142317 ("Use of the variable which is known to be constant" false positive)

This commit is contained in:
Bas Leijdekkers
2015-07-06 16:24:22 +02:00
parent 40a3b20ed4
commit 1d10dea77b
2 changed files with 34 additions and 231 deletions
@@ -179,8 +179,7 @@ public class ConstantValueVariableUseInspection extends BaseInspection {
return false;
}
final PsiVariable variable = (PsiVariable)target;
final VariableReadVisitor visitor =
new VariableReadVisitor(variable);
final VariableReadVisitor visitor = new VariableReadVisitor(variable);
body.accept(visitor);
if (!visitor.isRead()) {
return false;
@@ -190,8 +189,7 @@ public class ConstantValueVariableUseInspection extends BaseInspection {
}
}
private static class VariableReadVisitor
extends JavaRecursiveElementVisitor {
private static class VariableReadVisitor extends JavaRecursiveElementWalkingVisitor {
@NotNull
private final PsiVariable variable;
@@ -212,197 +210,23 @@ public class ConstantValueVariableUseInspection extends BaseInspection {
}
@Override
public void visitAssignmentExpression(
@NotNull PsiAssignmentExpression assignment) {
public void visitReferenceExpression(PsiReferenceExpression expression) {
if (read || written) {
return;
}
super.visitAssignmentExpression(assignment);
final PsiExpression lhs = assignment.getLExpression();
if (lhs instanceof PsiReferenceExpression) {
final PsiReferenceExpression referenceExpression = (PsiReferenceExpression)lhs;
final PsiElement target = referenceExpression.resolve();
if (variable.equals(target)) {
written = true;
final PsiElement target = expression.resolve();
if (variable.equals(target)) {
if (PsiUtil.isAccessedForWriting(expression)) {
written = true;
return;
}
}
final PsiExpression rhs = assignment.getRExpression();
if (rhs == null) {
return;
}
final VariableUsedVisitor visitor =
new VariableUsedVisitor(variable);
rhs.accept(visitor);
read = visitor.isUsed();
reference = visitor.getReference();
}
@Override
public void visitPrefixExpression(
@NotNull PsiPrefixExpression prefixExpression) {
if (read || written) {
return;
}
super.visitPrefixExpression(prefixExpression);
final IElementType tokenType = prefixExpression.getOperationTokenType();
if (!tokenType.equals(JavaTokenType.PLUSPLUS) &&
!tokenType.equals(JavaTokenType.MINUSMINUS)) {
return;
}
final PsiExpression operand = prefixExpression.getOperand();
if (!(operand instanceof PsiReferenceExpression)) {
return;
}
final PsiReferenceExpression referenceExpression =
(PsiReferenceExpression)operand;
final PsiElement target = referenceExpression.resolve();
if (!variable.equals(target)) {
return;
}
written = true;
}
@Override
public void visitPostfixExpression(
@NotNull PsiPostfixExpression postfixExpression) {
if (read || written) {
return;
}
super.visitPostfixExpression(postfixExpression);
final IElementType tokenType = postfixExpression.getOperationTokenType();
if (!tokenType.equals(JavaTokenType.PLUSPLUS) &&
!tokenType.equals(JavaTokenType.MINUSMINUS)) {
return;
}
final PsiExpression operand = postfixExpression.getOperand();
if (!(operand instanceof PsiReferenceExpression)) {
return;
}
final PsiReferenceExpression referenceExpression =
(PsiReferenceExpression)operand;
final PsiElement target = referenceExpression.resolve();
if (!variable.equals(target)) {
return;
}
written = true;
}
@Override
public void visitVariable(@NotNull PsiVariable variable) {
if (read || written) {
return;
}
super.visitVariable(variable);
final PsiExpression initalizer = variable.getInitializer();
if (initalizer == null) {
return;
}
final VariableUsedVisitor visitor =
new VariableUsedVisitor(variable);
initalizer.accept(visitor);
read = visitor.isUsed();
reference = visitor.getReference();
}
@Override
public void visitMethodCallExpression(
@NotNull PsiMethodCallExpression call) {
if (read || written) {
return;
}
super.visitMethodCallExpression(call);
final PsiExpressionList argumentList = call.getArgumentList();
final PsiExpression[] arguments = argumentList.getExpressions();
for (final PsiExpression argument : arguments) {
final VariableUsedVisitor visitor =
new VariableUsedVisitor(variable);
argument.accept(visitor);
if (visitor.isUsed()) {
if (PsiUtil.isAccessedForReading(expression)) {
reference = expression;
read = true;
reference = visitor.getReference();
return;
}
}
}
@Override
public void visitNewExpression(
@NotNull PsiNewExpression newExpression) {
if (read || written) {
return;
}
super.visitNewExpression(newExpression);
final PsiExpressionList argumentList =
newExpression.getArgumentList();
if (argumentList == null) {
return;
}
final PsiExpression[] arguments = argumentList.getExpressions();
for (final PsiExpression argument : arguments) {
final VariableUsedVisitor visitor =
new VariableUsedVisitor(variable);
argument.accept(visitor);
if (visitor.isUsed()) {
read = true;
reference = visitor.getReference();
return;
}
}
}
@Override
public void visitArrayInitializerExpression(
PsiArrayInitializerExpression expression) {
if (read || written) {
return;
}
super.visitArrayInitializerExpression(expression);
final PsiExpression[] arguments = expression.getInitializers();
for (final PsiExpression argument : arguments) {
final VariableUsedVisitor visitor =
new VariableUsedVisitor(variable);
argument.accept(visitor);
if (visitor.isUsed()) {
read = true;
reference = visitor.getReference();
return;
}
}
}
@Override
public void visitReturnStatement(
@NotNull PsiReturnStatement returnStatement) {
if (read || written) {
return;
}
super.visitReturnStatement(returnStatement);
final PsiExpression returnValue = returnStatement.getReturnValue();
if (returnValue == null) {
return;
}
final VariableUsedVisitor visitor =
new VariableUsedVisitor(variable);
returnValue.accept(visitor);
read = visitor.isUsed();
reference = visitor.getReference();
}
/**
* check if variable is used in nested/inner class.
*/
@Override
public void visitClass(PsiClass aClass) {
if (read || written) {
return;
}
super.visitClass(aClass);
final VariableUsedVisitor visitor =
new VariableUsedVisitor(variable);
aClass.accept(visitor);
read = visitor.isUsed();
reference = visitor.getReference();
super.visitReferenceExpression(expression);
}
public boolean isRead() {
@@ -413,49 +237,4 @@ public class ConstantValueVariableUseInspection extends BaseInspection {
return reference;
}
}
private static class VariableUsedVisitor
extends JavaRecursiveElementVisitor {
private final PsiVariable variable;
private boolean used = false;
private PsiReferenceExpression reference = null;
VariableUsedVisitor(PsiVariable variable) {
this.variable = variable;
}
@Override
public void visitElement(PsiElement element) {
if (used) {
return;
}
super.visitElement(element);
}
@Override
public void visitReferenceExpression(
@NotNull PsiReferenceExpression expression) {
if (used) {
return;
}
super.visitReferenceExpression(expression);
final PsiElement referent = expression.resolve();
if (referent == null) {
return;
}
if (referent.equals(variable)) {
reference = expression;
used = true;
}
}
public boolean isUsed() {
return used;
}
public PsiReferenceExpression getReference() {
return reference;
}
}
}
@@ -20,6 +20,30 @@ public class ConstantValueVariableUse {
if ((i) == 2 && true && true) { // polyadic
f(<warning descr="Value of 'i' is known to be constant">i</warning>);
}
int j = 10;
while (i < 10 && j == 10) {
f(<warning descr="Value of 'j' is known to be constant">j</warning>);
}
for (; i < 10 && j == 10; ) {
f(<warning descr="Value of 'j' is known to be constant">j</warning>);
}
if (i == 3) {
i = 4;
System.out.println(i);
}
}
}
class C {
private int hash;
@Override
public int hashCode() {
int h = hash;
if (h == 0) {
hash = h = "StringUtil.stringHashCode(this, 0, length())".hashCode();
}
return h;
}
}