perform arithmetic operations during dfa (part of IDEA-143315)

This commit is contained in:
peter
2015-11-17 17:19:44 +01:00
parent 6293695598
commit ea61e3e9e6
7 changed files with 58 additions and 19 deletions
@@ -1165,8 +1165,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
private void generateOther(PsiPolyadicExpression expression, IElementType op, PsiExpression[] operands, PsiType type) {
op = substituteBinaryOperation(op, type);
PsiExpression lExpr = operands[0];
lExpr.accept(this);
PsiType lType = lExpr.getType();
@@ -1183,14 +1181,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
}
}
@Nullable
private static IElementType substituteBinaryOperation(IElementType op, PsiType type) {
if (JavaTokenType.PLUS == op && (type == null || !type.equalsToText(JAVA_LANG_STRING))) {
return null;
}
return op;
}
private void acceptBinaryRightOperand(@Nullable IElementType op, PsiType type,
PsiExpression lExpr, PsiType lType,
PsiExpression rExpr, PsiType rType) {
@@ -20,6 +20,7 @@ import com.intellij.codeInspection.dataFlow.value.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -383,7 +384,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
final IElementType opSign = instruction.getOperationSign();
if (opSign != null) {
DfaInstructionState[] states = handleConstantComparison(instruction, runner, memState, dfaRight, dfaLeft, opSign);
DfaInstructionState[] states = handleConstantBinOp(instruction, runner, memState, dfaRight, dfaLeft, opSign);
if (states == null) {
states = handleRelationBinop(instruction, runner, memState, dfaRight, dfaLeft);
}
@@ -466,11 +467,11 @@ public class StandardInstructionVisitor extends InstructionVisitor {
}
@Nullable
private static DfaInstructionState[] handleConstantComparison(BinopInstruction instruction,
DataFlowRunner runner,
DfaMemoryState memState,
DfaValue dfaRight,
DfaValue dfaLeft, IElementType opSign) {
private static DfaInstructionState[] handleConstantBinOp(BinopInstruction instruction,
DataFlowRunner runner,
DfaMemoryState memState,
DfaValue dfaRight,
DfaValue dfaLeft, IElementType opSign) {
if (dfaRight instanceof DfaConstValue && dfaLeft instanceof DfaVariableValue) {
Object value = ((DfaConstValue)dfaRight).getValue();
if (value instanceof Number) {
@@ -482,10 +483,19 @@ public class StandardInstructionVisitor extends InstructionVisitor {
}
}
if (dfaRight instanceof DfaVariableValue && dfaLeft instanceof DfaConstValue) {
return handleConstantComparison(instruction, runner, memState, dfaLeft, dfaRight, DfaRelationValue.getSymmetricOperation(opSign));
return handleConstantBinOp(instruction, runner, memState, dfaLeft, dfaRight, DfaRelationValue.getSymmetricOperation(opSign));
}
if (EQEQ != opSign && NE != opSign) {
Object value1 = getConstantValue(memState, dfaLeft);
Object value2 = getConstantValue(memState, dfaRight);
if (instruction.getPsiAnchor() instanceof PsiExpression && value1 != null && value2 != null) {
Object result = JavaConstantExpressionEvaluator.computeBinaryOperationResult(value1, value2, opSign, false);
if (result != null) {
memState.push(runner.getFactory().getConstFactory().createFromValue(result, ((PsiExpression)instruction.getPsiAnchor()).getType(), null));
return nextInstruction(instruction, runner, memState);
}
}
return null;
}
@@ -502,6 +512,12 @@ public class StandardInstructionVisitor extends InstructionVisitor {
return null;
}
@Nullable
private static Object getConstantValue(DfaMemoryState memState, DfaValue val) {
if (val instanceof DfaVariableValue) val = memState.getConstantValue((DfaVariableValue)val);
return val instanceof DfaConstValue ? ((DfaConstValue)val).getValue() : null;
}
@Nullable
private static DfaInstructionState[] checkComparingWithConstant(BinopInstruction instruction,
DataFlowRunner runner,
@@ -38,7 +38,7 @@ import org.jetbrains.annotations.Nullable;
import static com.intellij.psi.JavaTokenType.*;
public class BinopInstruction extends BranchingInstruction {
private static final TokenSet ourSignificantOperations = TokenSet.create(EQEQ, NE, LT, GT, LE, GE, INSTANCEOF_KEYWORD, PLUS);
private static final TokenSet ourSignificantOperations = TokenSet.create(EQEQ, NE, LT, GT, LE, GE, INSTANCEOF_KEYWORD, PLUS, MINUS, ASTERISK, DIV, PERC);
private final IElementType myOperationSign;
private final Project myProject;
@@ -132,7 +132,7 @@ class ConstantExpressionVisitor extends JavaElementVisitor implements PsiConstan
}
}
private Object compute(Object lOperandValue, Object rOperandValue, IElementType tokenType, PsiElement expression) {
Object compute(Object lOperandValue, Object rOperandValue, IElementType tokenType, PsiElement expression) {
Object value = null;
if (tokenType == JavaTokenType.PLUS) {
if (lOperandValue instanceof String || rOperandValue instanceof String) {
@@ -19,6 +19,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Factory;
import com.intellij.openapi.util.Key;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
@@ -29,6 +30,7 @@ import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
@@ -142,4 +144,11 @@ public class JavaConstantExpressionEvaluator extends JavaRecursiveElementWalking
public static Object computeConstantExpression(@Nullable PsiExpression expression, boolean throwExceptionOnOverflow) {
return computeConstantExpression(expression, null, throwExceptionOnOverflow);
}
@Nullable
public static Object computeBinaryOperationResult(@NotNull Object lOperandValue,
@NotNull Object rOperandValue,
@NotNull IElementType tokenType, boolean throwExceptionOnOverflow) {
return new ConstantExpressionVisitor(Collections.<PsiVariable>emptySet(), throwExceptionOnOverflow, null).compute(lOperandValue, rOperandValue, tokenType, null);
}
}
@@ -0,0 +1,17 @@
class Test {
{
int a = 0;
int b = a;
System.out.println(<warning descr="Condition 'a == b' is always 'true'">a == b</warning>);
System.out.println(a - b);
}
{
int a = 1;
int b = -3;
System.out.println(<warning descr="Condition 'a == b' is always 'false'">a == b</warning>);
if (<warning descr="Condition 'a + b + 2 == 0' is always 'true'">a + b + 2 == 0</warning>) {
System.out.println("a");
}
}
}
@@ -423,4 +423,11 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
public void testConstantConditionsWithAssignmentsInside() { doTest(); }
public void testIfConditionsWithAssignmentInside() { doTest(); }
public void testConstantArithmetic() {
final DataFlowInspection inspection = new DataFlowInspection();
inspection.REPORT_CONSTANT_REFERENCE_VALUES = true;
myFixture.enableInspections(inspection);
myFixture.testHighlighting(true, false, true, getTestName(false) + ".java");
}
}