mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
perform arithmetic operations during dfa (part of IDEA-143315)
This commit is contained in:
-10
@@ -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) {
|
||||
|
||||
+23
-7
@@ -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,
|
||||
|
||||
+1
-1
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user