mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
DFA: Move equals handling to hardcoded contracts
This commit is contained in:
-43
@@ -20,7 +20,6 @@ import com.intellij.codeInsight.ExceptionUtil;
|
||||
import com.intellij.codeInspection.dataFlow.inliner.*;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.*;
|
||||
import com.intellij.codeInspection.dataFlow.value.*;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
@@ -883,23 +882,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
ifNoException.setOffset(myCurrentFlow.getInstructionCount());
|
||||
}
|
||||
|
||||
private static class ApplyNotNullInstruction extends Instruction {
|
||||
@Override
|
||||
public DfaInstructionState[] accept(DataFlowRunner runner, DfaMemoryState state, InstructionVisitor visitor) {
|
||||
DfaValue value = state.pop();
|
||||
DfaValueFactory factory = runner.getFactory();
|
||||
if (state.applyCondition(factory.createCondition(value, RelationType.NE, factory.getConstFactory().getNull()))) {
|
||||
return nextInstruction(runner, state);
|
||||
}
|
||||
return DfaInstructionState.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "APPLY NOT NULL";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryStatement(PsiTryStatement statement) {
|
||||
startElement(statement);
|
||||
@@ -1499,10 +1481,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
JavaResolveResult result = methodExpression.advancedResolve(false);
|
||||
PsiElement method = result.getElement();
|
||||
PsiParameter[] parameters = method instanceof PsiMethod ? ((PsiMethod)method).getParameterList().getParameters() : null;
|
||||
boolean isEqualsCall = expressions.length == 1 && method instanceof PsiMethod &&
|
||||
"equals".equals(((PsiMethod)method).getName()) && parameters.length == 1 &&
|
||||
parameters[0].getType().equalsToText(JAVA_LANG_OBJECT) &&
|
||||
PsiType.BOOLEAN.equals(((PsiMethod)method).getReturnType());
|
||||
|
||||
for (int i = 0; i < expressions.length; i++) {
|
||||
PsiExpression paramExpr = expressions[i];
|
||||
@@ -1510,30 +1488,9 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
if (parameters != null && i < parameters.length) {
|
||||
generateBoxingUnboxingInstructionFor(paramExpr, result.getSubstitutor().substitute(parameters[i].getType()));
|
||||
}
|
||||
if (i == 0 && isEqualsCall) {
|
||||
// stack: .., qualifier, arg1
|
||||
addInstruction(new SpliceInstruction(2, 0, 1, 0));
|
||||
// stack: .., arg1, qualifier, arg1
|
||||
}
|
||||
}
|
||||
|
||||
addBareCall(expression, expression.getMethodExpression());
|
||||
|
||||
if (isEqualsCall) {
|
||||
// assume equals argument must be not-null if the result is true
|
||||
// don't assume the call result to be false if arg1==null
|
||||
|
||||
// stack: .., arg1, call-result
|
||||
ConditionalGotoInstruction ifFalse = addInstruction(new ConditionalGotoInstruction(null, true, null));
|
||||
|
||||
addInstruction(new ApplyNotNullInstruction());
|
||||
addInstruction(new PushInstruction(myFactory.getConstFactory().getTrue(), null));
|
||||
addInstruction(new GotoInstruction(getEndOffset(expression)));
|
||||
|
||||
ifFalse.setOffset(myCurrentFlow.getInstructionCount());
|
||||
addInstruction(new PopInstruction());
|
||||
addInstruction(new PushInstruction(myFactory.getConstFactory().getFalse(), null));
|
||||
}
|
||||
finishElement(expression);
|
||||
}
|
||||
|
||||
|
||||
+1
-5
@@ -109,11 +109,7 @@ public class CustomMethodHandlers {
|
||||
if (leftConst != null && rightConst != null) {
|
||||
return singleResult(memState, factory.getBoolean(ignoreCase ? leftConst.equalsIgnoreCase(rightConst) : leftConst.equals(rightConst)));
|
||||
}
|
||||
DfaValue leftLength = SpecialField.STRING_LENGTH.createValue(factory, args.myQualifier);
|
||||
DfaValue rightLength = SpecialField.STRING_LENGTH.createValue(factory, arg);
|
||||
DfaValue trueRelation = factory.createCondition(leftLength, RelationType.EQ, rightLength);
|
||||
DfaValue falseRelation = factory.createCondition(leftLength, RelationType.NE, rightLength);
|
||||
return applyCondition(memState, trueRelation, DfaUnknownValue.getInstance(), falseRelation, factory.getBoolean(false));
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static List<DfaMemoryState> indexOf(DfaValue qualifier,
|
||||
|
||||
+15
-2
@@ -110,6 +110,11 @@ public class HardcodedContracts {
|
||||
else if ("isEmpty".equals(methodName) && paramCount == 0) {
|
||||
return SpecialField.STRING_LENGTH.getEmptyContracts();
|
||||
}
|
||||
else if (("equals".equals(methodName) || "equalsIgnoreCase".equals(methodName)) && paramCount == 1) {
|
||||
return Arrays.asList(getEqualsContract(), MethodContract.singleConditionContract(
|
||||
ContractValue.qualifier().specialField(SpecialField.STRING_LENGTH), RelationType.NE,
|
||||
ContractValue.argument(0).specialField(SpecialField.STRING_LENGTH), FALSE_VALUE));
|
||||
}
|
||||
}
|
||||
else if (MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_COLLECTION, PsiType.BOOLEAN, "isEmpty")) {
|
||||
return SpecialField.COLLECTION_SIZE.getEmptyContracts();
|
||||
@@ -120,7 +125,7 @@ public class HardcodedContracts {
|
||||
}
|
||||
else if (MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_SET, PsiType.BOOLEAN, "equals", (PsiType)null) ||
|
||||
MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_LIST, PsiType.BOOLEAN, "equals", (PsiType)null)) {
|
||||
return Collections.singletonList(MethodContract.singleConditionContract(
|
||||
return Arrays.asList(getEqualsContract(), MethodContract.singleConditionContract(
|
||||
ContractValue.qualifier().specialField(SpecialField.COLLECTION_SIZE), RelationType.NE,
|
||||
ContractValue.argument(0).specialField(SpecialField.COLLECTION_SIZE), FALSE_VALUE));
|
||||
}
|
||||
@@ -141,7 +146,7 @@ public class HardcodedContracts {
|
||||
ContractValue.qualifier().specialField(SpecialField.MAP_SIZE), RelationType.EQ, ContractValue.zero(), FALSE_VALUE));
|
||||
}
|
||||
else if (MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_MAP, PsiType.BOOLEAN, "equals", (PsiType)null)) {
|
||||
return Collections.singletonList(MethodContract.singleConditionContract(
|
||||
return Arrays.asList(getEqualsContract(), MethodContract.singleConditionContract(
|
||||
ContractValue.qualifier().specialField(SpecialField.MAP_SIZE), RelationType.NE,
|
||||
ContractValue.argument(0).specialField(SpecialField.MAP_SIZE), FALSE_VALUE));
|
||||
}
|
||||
@@ -176,10 +181,18 @@ public class HardcodedContracts {
|
||||
return Arrays.asList(optionalAbsentContract(FALSE_VALUE), MethodContract.trivialContract(TRUE_VALUE));
|
||||
}
|
||||
}
|
||||
else if (MethodUtils.isEquals(method)) {
|
||||
return Collections.singletonList(getEqualsContract());
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static StandardMethodContract getEqualsContract() {
|
||||
return new StandardMethodContract(new MethodContract.ValueConstraint[] {NULL_VALUE}, FALSE_VALUE);
|
||||
}
|
||||
|
||||
static MethodContract optionalAbsentContract(MethodContract.ValueConstraint returnValue) {
|
||||
return MethodContract
|
||||
.singleConditionContract(ContractValue.qualifier(), RelationType.IS, ContractValue.optionalValue(false), returnValue);
|
||||
|
||||
+3
-8
@@ -324,15 +324,10 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
private List<DfaMemoryState> handleKnownMethods(MethodCallInstruction instruction, DataFlowRunner runner, DfaMemoryState memState) {
|
||||
CustomMethodHandlers.CustomMethodHandler handler = CustomMethodHandlers.find(instruction);
|
||||
if (handler == null) return Collections.emptyList();
|
||||
memState = memState.createCopy();
|
||||
DfaCallArguments callArguments = popCall(instruction, runner, memState, false);
|
||||
List<DfaMemoryState> states =
|
||||
callArguments.myArguments == null ? Collections.emptyList() :
|
||||
handler.handle(callArguments, memState, runner.getFactory());
|
||||
if (states.isEmpty()) {
|
||||
memState.push(getMethodResultValue(instruction, callArguments.myQualifier, memState, runner.getFactory()));
|
||||
return Collections.singletonList(memState);
|
||||
}
|
||||
return states;
|
||||
return callArguments.myArguments == null ? Collections.emptyList() :
|
||||
handler.handle(callArguments, memState, runner.getFactory());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
Reference in New Issue
Block a user