mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
ContractValue: fully declarative extended contract description
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaUnknownValue;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValue;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
|
||||
import com.intellij.psi.PsiType;
|
||||
import com.intellij.util.Function;
|
||||
|
||||
/**
|
||||
* @author Tagir Valeev
|
||||
*/
|
||||
public abstract class ContractValue {
|
||||
ContractValue() {
|
||||
|
||||
}
|
||||
|
||||
public abstract DfaValue makeDfaValue(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments);
|
||||
|
||||
public static ContractValue qualifier() {
|
||||
return Qualifier.INSTANCE;
|
||||
}
|
||||
|
||||
public static ContractValue argument(int index) {
|
||||
return new Argument(index);
|
||||
}
|
||||
|
||||
public static ContractValue constant(Object value, PsiType type) {
|
||||
return new IndependentValue(factory -> factory.getConstFactory().createFromValue(value, type, null), String.valueOf(value));
|
||||
}
|
||||
|
||||
public static ContractValue booleanValue(boolean value) {
|
||||
return value ? IndependentValue.TRUE : IndependentValue.FALSE;
|
||||
}
|
||||
|
||||
public static ContractValue optionalValue(boolean present) {
|
||||
return present ? IndependentValue.PRESENT : IndependentValue.ABSENT;
|
||||
}
|
||||
|
||||
public static ContractValue nullValue() {
|
||||
return IndependentValue.NULL;
|
||||
}
|
||||
|
||||
public static ContractValue specialField(ContractValue qualifier, SpecialField field) {
|
||||
return new Spec(qualifier, field);
|
||||
}
|
||||
|
||||
public static ContractValue condition(ContractValue left, DfaRelationValue.RelationType relation, ContractValue right) {
|
||||
return new Condition(left, relation, right);
|
||||
}
|
||||
|
||||
static class Qualifier extends ContractValue {
|
||||
static final Qualifier INSTANCE = new Qualifier();
|
||||
|
||||
@Override
|
||||
public DfaValue makeDfaValue(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
return qualifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "this";
|
||||
}
|
||||
}
|
||||
|
||||
static class Argument extends ContractValue {
|
||||
private final int myIndex;
|
||||
|
||||
Argument(int index) {
|
||||
myIndex = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DfaValue makeDfaValue(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
return arguments.length <= myIndex ? DfaUnknownValue.getInstance() : arguments[myIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "arg#" + myIndex;
|
||||
}
|
||||
}
|
||||
|
||||
static class IndependentValue extends ContractValue {
|
||||
static final IndependentValue NULL = new IndependentValue(factory -> factory.getConstFactory().getNull(), "null");
|
||||
static final IndependentValue TRUE = new IndependentValue(factory -> factory.getConstFactory().getTrue(), "true");
|
||||
static final IndependentValue FALSE = new IndependentValue(factory -> factory.getConstFactory().getFalse(), "false");
|
||||
static final IndependentValue PRESENT = new IndependentValue(factory -> factory.getOptionalFactory().getOptional(true), "present");
|
||||
static final IndependentValue ABSENT = new IndependentValue(factory -> factory.getOptionalFactory().getOptional(false), "empty");
|
||||
|
||||
private final Function<DfaValueFactory, DfaValue> mySupplier;
|
||||
private final String myPresentation;
|
||||
|
||||
IndependentValue(Function<DfaValueFactory, DfaValue> supplier, String presentation) {
|
||||
mySupplier = supplier;
|
||||
myPresentation = presentation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DfaValue makeDfaValue(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
return mySupplier.fun(factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myPresentation;
|
||||
}
|
||||
}
|
||||
|
||||
static class Spec extends ContractValue {
|
||||
private final ContractValue myQualifier;
|
||||
private final SpecialField myField;
|
||||
|
||||
Spec(ContractValue qualifier, SpecialField field) {
|
||||
myQualifier = qualifier;
|
||||
myField = field;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DfaValue makeDfaValue(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
return myField.createValue(factory, myQualifier.makeDfaValue(factory, qualifier, arguments));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myQualifier + "." + myField.getMethodName() + "()";
|
||||
}
|
||||
}
|
||||
|
||||
static class Condition extends ContractValue {
|
||||
private final ContractValue myLeft, myRight;
|
||||
private final DfaRelationValue.RelationType myRelationType;
|
||||
|
||||
Condition(ContractValue left, DfaRelationValue.RelationType type, ContractValue right) {
|
||||
myLeft = left;
|
||||
myRight = right;
|
||||
myRelationType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DfaValue makeDfaValue(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
return factory.createCondition(myLeft.makeDfaValue(factory, qualifier, arguments), myRelationType,
|
||||
myRight.makeDfaValue(factory, qualifier, arguments));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myLeft + " " + myRelationType + " " + myRight;
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-131
@@ -15,11 +15,7 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaOptionalValue;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValue;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
|
||||
import com.intellij.codeInspection.dataFlow.value.SpecialField;
|
||||
import com.intellij.lang.injection.InjectedLanguageManager;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
@@ -27,7 +23,6 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.psiutils.ExpressionUtils;
|
||||
import com.siyeh.ig.psiutils.MethodUtils;
|
||||
import com.siyeh.ig.psiutils.TypeUtils;
|
||||
import one.util.streamex.IntStreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -78,17 +73,19 @@ public class HardcodedContracts {
|
||||
}
|
||||
else if (CommonClassNames.JAVA_LANG_STRING.equals(className)) {
|
||||
if (("charAt".equals(methodName) || "codePointAt".equals(methodName)) && paramCount == 1) {
|
||||
return Arrays.asList(new NonnegativeArgumentContract(1, 0),
|
||||
new SpecialFieldRangeContract(1, 0, RelationType.LT, SpecialField.STRING_LENGTH));
|
||||
return Arrays.asList(nonnegativeArgumentContract(0),
|
||||
specialFieldRangeContract(0, RelationType.LT, SpecialField.STRING_LENGTH));
|
||||
}
|
||||
else if (("substring".equals(methodName) || "subSequence".equals(methodName)) && paramCount <= 2) {
|
||||
List<MethodContract> contracts = new ArrayList<>(5);
|
||||
contracts.add(new NonnegativeArgumentContract(paramCount, 0));
|
||||
contracts.add(new SpecialFieldRangeContract(paramCount, 0, RelationType.LE, SpecialField.STRING_LENGTH));
|
||||
contracts.add(nonnegativeArgumentContract(0));
|
||||
contracts.add(specialFieldRangeContract(0, RelationType.LE, SpecialField.STRING_LENGTH));
|
||||
if (paramCount == 2) {
|
||||
contracts.add(new NonnegativeArgumentContract(paramCount, 1));
|
||||
contracts.add(new SpecialFieldRangeContract(paramCount, 1, RelationType.LE, SpecialField.STRING_LENGTH));
|
||||
contracts.add(new ArgumentRelationContract(paramCount, 0, RelationType.LE, 1));
|
||||
contracts.add(nonnegativeArgumentContract(1));
|
||||
contracts.add(specialFieldRangeContract(1, RelationType.LE, SpecialField.STRING_LENGTH));
|
||||
contracts.add(MethodContract
|
||||
.singleConditionContract(ContractValue.argument(0), RelationType.LE.getNegated(), ContractValue.argument(1),
|
||||
THROW_EXCEPTION));
|
||||
}
|
||||
return contracts;
|
||||
}
|
||||
@@ -100,8 +97,8 @@ public class HardcodedContracts {
|
||||
return SpecialField.COLLECTION_SIZE.getEmptyContracts();
|
||||
}
|
||||
else if (MethodUtils.methodMatches(method, CommonClassNames.JAVA_UTIL_COLLECTION, null, "get", PsiType.INT)) {
|
||||
return Arrays.asList(new NonnegativeArgumentContract(paramCount, 0),
|
||||
new SpecialFieldRangeContract(paramCount, 0, RelationType.LT, SpecialField.COLLECTION_SIZE));
|
||||
return Arrays.asList(nonnegativeArgumentContract(0),
|
||||
specialFieldRangeContract(0, RelationType.LT, SpecialField.COLLECTION_SIZE));
|
||||
}
|
||||
else if ("org.apache.commons.lang.Validate".equals(className) ||
|
||||
"org.apache.commons.lang3.Validate".equals(className) ||
|
||||
@@ -124,135 +121,29 @@ public class HardcodedContracts {
|
||||
}
|
||||
else if (TypeUtils.isOptional(owner)) {
|
||||
if (DfaOptionalSupport.isOptionalGetMethodName(methodName) || "orElseThrow".equals(methodName)) {
|
||||
return Arrays.asList(new OptionalPresenceContract(false, THROW_EXCEPTION),
|
||||
new OptionalPresenceContract(true, NOT_NULL_VALUE));
|
||||
return Arrays.asList(optionalAbsentContract(THROW_EXCEPTION), MethodContract.trivialContract(NOT_NULL_VALUE));
|
||||
}
|
||||
else if ("isPresent".equals(methodName)) {
|
||||
return Arrays.asList(new OptionalPresenceContract(false, FALSE_VALUE),
|
||||
new OptionalPresenceContract(true, TRUE_VALUE));
|
||||
return Arrays.asList(optionalAbsentContract(FALSE_VALUE), MethodContract.trivialContract(TRUE_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
static class OptionalPresenceContract extends MethodContract {
|
||||
private final boolean myPresent;
|
||||
private final ValueConstraint myReturnValue;
|
||||
|
||||
public OptionalPresenceContract(boolean mustPresent, ValueConstraint returnValue) {
|
||||
myReturnValue = returnValue;
|
||||
myPresent = mustPresent;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DfaValue> getConditions(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
DfaOptionalValue optional = factory.getOptionalFactory().getOptional(myPresent);
|
||||
return Collections.singletonList(factory.createCondition(qualifier, RelationType.IS, optional));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getArgumentsPresentation() {
|
||||
return "[" + (myPresent ? "present" : "absent") + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueConstraint getReturnValue() {
|
||||
return myReturnValue;
|
||||
}
|
||||
static MethodContract optionalAbsentContract(MethodContract.ValueConstraint returnValue) {
|
||||
return MethodContract
|
||||
.singleConditionContract(ContractValue.qualifier(), RelationType.IS, ContractValue.optionalValue(false), returnValue);
|
||||
}
|
||||
|
||||
static abstract class ArgumentRangeContract extends MethodContract {
|
||||
final int myParamCount;
|
||||
final int myIndex;
|
||||
final RelationType myRelationType;
|
||||
|
||||
ArgumentRangeContract(int paramCount, int index, RelationType type) {
|
||||
myParamCount = paramCount;
|
||||
myIndex = index;
|
||||
myRelationType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DfaValue> getConditions(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
DfaValue left = arguments[myIndex];
|
||||
DfaValue right = getBound(factory, qualifier, arguments);
|
||||
return Collections.singletonList(factory.createCondition(left, myRelationType.getNegated(), right));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
abstract DfaValue getBound(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments);
|
||||
|
||||
abstract String getBoundRepresentation();
|
||||
|
||||
@Override
|
||||
protected String getArgumentsPresentation() {
|
||||
return IntStreamEx.range(myParamCount)
|
||||
.mapToObj(idx -> idx == myIndex ? myRelationType.getNegated() + getBoundRepresentation() : "_")
|
||||
.joining(", ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueConstraint getReturnValue() {
|
||||
return THROW_EXCEPTION;
|
||||
}
|
||||
static MethodContract nonnegativeArgumentContract(int argNumber) {
|
||||
return MethodContract
|
||||
.singleConditionContract(ContractValue.argument(argNumber), RelationType.LT, ContractValue.constant(0, PsiType.INT), THROW_EXCEPTION);
|
||||
}
|
||||
|
||||
static class NonnegativeArgumentContract extends ArgumentRangeContract {
|
||||
public NonnegativeArgumentContract(int paramCount, int nonNegativeArgumentIndex) {
|
||||
super(paramCount, nonNegativeArgumentIndex, RelationType.GE);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
DfaValue getBound(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
return factory.getConstFactory().createFromValue(0, PsiType.INT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getBoundRepresentation() {
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
|
||||
static class ArgumentRelationContract extends ArgumentRangeContract {
|
||||
private final int myIndex;
|
||||
|
||||
public ArgumentRelationContract(int paramCount, int leftIndex, RelationType relationType, int rightIndex) {
|
||||
super(paramCount, leftIndex, relationType);
|
||||
myIndex = rightIndex;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
DfaValue getBound(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
return arguments[myIndex];
|
||||
}
|
||||
|
||||
@Override
|
||||
String getBoundRepresentation() {
|
||||
return "arg#" + myIndex;
|
||||
}
|
||||
}
|
||||
|
||||
static class SpecialFieldRangeContract extends ArgumentRangeContract {
|
||||
private final SpecialField mySpecialField;
|
||||
|
||||
SpecialFieldRangeContract(int paramCount, int index, RelationType type, SpecialField specialField) {
|
||||
super(paramCount, index, type);
|
||||
mySpecialField = specialField;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
DfaValue getBound(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
return mySpecialField.createValue(factory, qualifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getBoundRepresentation() {
|
||||
return "this."+mySpecialField.getMethodName()+"()";
|
||||
}
|
||||
static MethodContract specialFieldRangeContract(int index, RelationType type, SpecialField specialField) {
|
||||
return MethodContract.singleConditionContract(ContractValue.argument(index), type.getNegated(),
|
||||
ContractValue.specialField(ContractValue.qualifier(), specialField), THROW_EXCEPTION);
|
||||
}
|
||||
|
||||
private static boolean isJunit(String className) {
|
||||
|
||||
+59
-13
@@ -20,8 +20,8 @@ import com.intellij.codeInspection.dataFlow.value.DfaRelationValue.RelationType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A method contract which states that method will have a concrete return value
|
||||
@@ -31,7 +31,7 @@ import java.util.Objects;
|
||||
*/
|
||||
public abstract class MethodContract {
|
||||
// package private to avoid uncontrolled implementations
|
||||
public MethodContract() {
|
||||
MethodContract() {
|
||||
|
||||
}
|
||||
|
||||
@@ -66,18 +66,60 @@ public abstract class MethodContract {
|
||||
* @return true if this contract result does not depend on arguments
|
||||
*/
|
||||
boolean isTrivial() {
|
||||
return false;
|
||||
return getConditions().isEmpty();
|
||||
}
|
||||
|
||||
protected abstract String getArgumentsPresentation();
|
||||
abstract String getArgumentsPresentation();
|
||||
|
||||
protected abstract List<DfaValue> getConditions(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments);
|
||||
abstract List<ContractValue> getConditions();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getArgumentsPresentation() + " -> " + getReturnValue();
|
||||
}
|
||||
|
||||
public static MethodContract trivialContract(ValueConstraint value) {
|
||||
return new MethodContract() {
|
||||
@Override
|
||||
public ValueConstraint getReturnValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getArgumentsPresentation() {
|
||||
return "(any)";
|
||||
}
|
||||
|
||||
@Override
|
||||
List<ContractValue> getConditions() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static MethodContract singleConditionContract(ContractValue left,
|
||||
RelationType relationType,
|
||||
ContractValue right,
|
||||
ValueConstraint returnValue) {
|
||||
ContractValue condition = ContractValue.condition(left, relationType, right);
|
||||
return new MethodContract() {
|
||||
@Override
|
||||
public ValueConstraint getReturnValue() {
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
String getArgumentsPresentation() {
|
||||
return condition.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
List<ContractValue> getConditions() {
|
||||
return Collections.singletonList(condition);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public enum ValueConstraint {
|
||||
ANY_VALUE("_"), NULL_VALUE("null"), NOT_NULL_VALUE("!null"), TRUE_VALUE("true"), FALSE_VALUE("false"), THROW_EXCEPTION("fail");
|
||||
private final String myPresentableName;
|
||||
@@ -100,17 +142,21 @@ public abstract class MethodContract {
|
||||
/**
|
||||
* Returns a condition value which should be applied to memory state to satisfy this constraint
|
||||
*
|
||||
* @param factory factory to create new values
|
||||
* @param argValue argument value to test
|
||||
* @param argumentIndex argument number to test
|
||||
* @return a condition
|
||||
*/
|
||||
public DfaValue getCondition(DfaValueFactory factory, DfaValue argValue) {
|
||||
if (this == THROW_EXCEPTION || this == ANY_VALUE) {
|
||||
return factory.getBoolean(true);
|
||||
public ContractValue getCondition(int argumentIndex) {
|
||||
ContractValue left;
|
||||
if (this == NULL_VALUE || this == NOT_NULL_VALUE) {
|
||||
left = ContractValue.nullValue();
|
||||
}
|
||||
DfaConstValue expectedValue = Objects.requireNonNull(getComparisonValue(factory));
|
||||
|
||||
return factory.createCondition(argValue, RelationType.equivalence(!shouldUseNonEqComparison()), expectedValue);
|
||||
else if (this == TRUE_VALUE || this == FALSE_VALUE) {
|
||||
left = ContractValue.booleanValue(true);
|
||||
}
|
||||
else {
|
||||
return ContractValue.booleanValue(true);
|
||||
}
|
||||
return ContractValue.condition(left, RelationType.equivalence(!shouldUseNonEqComparison()), ContractValue.argument(argumentIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+10
-35
@@ -13,10 +13,10 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInspection.dataFlow.value;
|
||||
package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.MethodContract;
|
||||
import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet;
|
||||
import com.intellij.codeInspection.dataFlow.value.*;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
@@ -26,7 +26,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -120,39 +119,15 @@ public enum SpecialField {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a list of method contracts which equivalent to checking this special field for zero
|
||||
*/
|
||||
public List<MethodContract> getEmptyContracts() {
|
||||
return Arrays.asList(new MethodContract() {
|
||||
@Override
|
||||
public ValueConstraint getReturnValue() {
|
||||
return ValueConstraint.TRUE_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getArgumentsPresentation() {
|
||||
return "[empty]";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DfaValue> getConditions(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
return Collections.singletonList(factory.createCondition(createValue(factory, qualifier), DfaRelationValue.RelationType.EQ,
|
||||
factory.getConstFactory().createFromValue(0, PsiType.INT, null)));
|
||||
}
|
||||
}, new MethodContract() {
|
||||
@Override
|
||||
public ValueConstraint getReturnValue() {
|
||||
return ValueConstraint.FALSE_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getArgumentsPresentation() {
|
||||
return "[non-empty]";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DfaValue> getConditions(DfaValueFactory factory, DfaValue qualifier, DfaValue[] arguments) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
});
|
||||
ContractValue thisValue = ContractValue.specialField(ContractValue.qualifier(), this);
|
||||
ContractValue zeroValue = ContractValue.constant(0, PsiType.INT);
|
||||
return Arrays.asList(MethodContract.singleConditionContract(thisValue, DfaRelationValue.RelationType.EQ, zeroValue,
|
||||
MethodContract.ValueConstraint.TRUE_VALUE),
|
||||
MethodContract.trivialContract(MethodContract.ValueConstraint.FALSE_VALUE));
|
||||
}
|
||||
|
||||
@Override
|
||||
+1
-1
@@ -467,7 +467,7 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
DfaValueFactory factory,
|
||||
Set<DfaMemoryState> finalStates,
|
||||
DfaValue returnValue) {
|
||||
List<DfaValue> conditions = contract.getConditions(factory, callParameters.myQualifier, callParameters.myArguments);
|
||||
List<DfaValue> conditions = ContainerUtil.map(contract.getConditions(), cv -> cv.makeDfaValue(factory, callParameters.myQualifier, callParameters.myArguments));
|
||||
if (StreamEx.of(conditions).allMatch(factory.getConstFactory().getTrue()::equals)) {
|
||||
for (DfaMemoryState state : states) {
|
||||
state.push(returnValue);
|
||||
|
||||
+4
-6
@@ -15,11 +15,9 @@
|
||||
*/
|
||||
package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValue;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValueFactory;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import one.util.streamex.StreamEx;
|
||||
import one.util.streamex.IntStreamEx;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
@@ -88,9 +86,9 @@ public final class StandardMethodContract extends MethodContract {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<DfaValue> getConditions(DfaValueFactory factory, DfaValue qualifier, DfaValue[] argValues) {
|
||||
return StreamEx.zip(arguments, argValues, (constraint, value) -> constraint.getCondition(factory, value))
|
||||
.without(factory.getConstFactory().getTrue()).toList();
|
||||
protected List<ContractValue> getConditions() {
|
||||
return IntStreamEx.ofIndices(arguments).mapToObj(idx -> arguments[idx].getCondition(idx)).without(ContractValue.booleanValue(true))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public static List<StandardMethodContract> parseContract(String text) throws ParseException {
|
||||
|
||||
-1
@@ -26,7 +26,6 @@ package com.intellij.codeInspection.dataFlow.instructions;
|
||||
|
||||
import com.intellij.codeInspection.dataFlow.*;
|
||||
import com.intellij.codeInspection.dataFlow.value.DfaValue;
|
||||
import com.intellij.codeInspection.dataFlow.value.SpecialField;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
+1
@@ -18,6 +18,7 @@ package com.intellij.codeInspection.dataFlow.value;
|
||||
import com.intellij.codeInsight.AnnotationUtil;
|
||||
import com.intellij.codeInspection.dataFlow.DfaPsiUtil;
|
||||
import com.intellij.codeInspection.dataFlow.Nullness;
|
||||
import com.intellij.codeInspection.dataFlow.SpecialField;
|
||||
import com.intellij.ide.highlighter.JavaFileType;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ import com.intellij.codeInsight.daemon.ImplicitUsageProvider;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.JavaGenericsUtil;
|
||||
import com.intellij.codeInspection.dataFlow.DfaPsiUtil;
|
||||
import com.intellij.codeInspection.dataFlow.Nullness;
|
||||
import com.intellij.codeInspection.dataFlow.SpecialField;
|
||||
import com.intellij.openapi.extensions.Extensions;
|
||||
import com.intellij.openapi.util.Comparing;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
|
||||
Reference in New Issue
Block a user