mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
honor vararg calls when inferring contracts (IDEA-148862)
This commit is contained in:
+14
-3
@@ -17,6 +17,7 @@ package com.intellij.codeInspection.dataFlow;
|
||||
|
||||
import com.intellij.codeInsight.NullableNotNullManager;
|
||||
import com.intellij.codeInspection.dataFlow.MethodContract.ValueConstraint;
|
||||
import com.intellij.codeInspection.dataFlow.instructions.MethodCallInstruction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.Condition;
|
||||
@@ -158,10 +159,14 @@ class ContractInferenceInterpreter {
|
||||
}
|
||||
|
||||
private List<MethodContract> handleCallDelegation(PsiMethodCallExpression expression, final boolean negated) {
|
||||
final PsiMethod targetMethod = expression.resolveMethod();
|
||||
JavaResolveResult result = expression.resolveMethodGenerics();
|
||||
final PsiMethod targetMethod = (PsiMethod)result.getElement();
|
||||
if (targetMethod == null) return Collections.emptyList();
|
||||
|
||||
|
||||
final PsiParameter[] parameters = targetMethod.getParameterList().getParameters();
|
||||
final PsiExpression[] arguments = expression.getArgumentList().getExpressions();
|
||||
final boolean varArgCall = MethodCallInstruction.isVarArgCall(targetMethod, result.getSubstitutor(), arguments, parameters);
|
||||
|
||||
final boolean notNull = NullableNotNullManager.isNotNull(targetMethod);
|
||||
List<MethodContract> fromDelegate = ContainerUtil.mapNotNull(ControlFlowAnalyzer.getMethodContracts(targetMethod), new NullableFunction<MethodContract, MethodContract>() {
|
||||
@Nullable
|
||||
@@ -170,9 +175,15 @@ class ContractInferenceInterpreter {
|
||||
ValueConstraint[] answer = myEmptyConstraints;
|
||||
for (int i = 0; i < delegateContract.arguments.length; i++) {
|
||||
if (i >= arguments.length) return null;
|
||||
|
||||
ValueConstraint argConstraint = delegateContract.arguments[i];
|
||||
if (argConstraint != ANY_VALUE) {
|
||||
if (varArgCall && i >= parameters.length - 1) {
|
||||
if (argConstraint == NULL_VALUE) {
|
||||
return null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
int paramIndex = resolveParameter(arguments[i]);
|
||||
if (paramIndex < 0) {
|
||||
if (argConstraint != getLiteralConstraint(arguments[i])) {
|
||||
|
||||
+3
-2
@@ -200,11 +200,12 @@ public class StandardInstructionVisitor extends InstructionVisitor {
|
||||
if (method == null || instruction.getContracts().isEmpty()) {
|
||||
argValues = null;
|
||||
} else {
|
||||
int paramCount = method.getParameterList().getParametersCount();
|
||||
PsiParameterList paramList = method.getParameterList();
|
||||
int paramCount = paramList.getParametersCount();
|
||||
if (paramCount == args.length || method.isVarArgs() && args.length >= paramCount - 1) {
|
||||
argValues = new DfaValue[paramCount];
|
||||
if (varargCall) {
|
||||
argValues[paramCount - 1] = DfaUnknownValue.getInstance();
|
||||
argValues[paramCount - 1] = runner.getFactory().createTypeValue(paramList.getParameters()[paramCount - 1].getType(), Nullness.NOT_NULL);
|
||||
}
|
||||
} else {
|
||||
argValues = null;
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ public class MethodCallInstruction extends Instruction {
|
||||
return map;
|
||||
}
|
||||
|
||||
private static boolean isVarArgCall(PsiMethod method, PsiSubstitutor substitutor, PsiExpression[] args, PsiParameter[] parameters) {
|
||||
public static boolean isVarArgCall(PsiMethod method, PsiSubstitutor substitutor, PsiExpression[] args, PsiParameter[] parameters) {
|
||||
if (!method.isVarArgs()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
class Test {
|
||||
private String wrap(final String wrapWith, final String token) {
|
||||
return join(wrapWith, token, wrapWith);
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.Contract("null->null; !null->!null")
|
||||
native static <T> String join(T... elements);
|
||||
}
|
||||
@@ -44,4 +44,6 @@ public class ContractCheckTest extends LightCodeInsightFixtureTestCase {
|
||||
public void testVarargInferred() { doTest(); }
|
||||
public void testDoubleParameter() { doTest(); }
|
||||
public void testReturnPrimitiveArray() { doTest(); }
|
||||
|
||||
public void testPassingVarargsToDelegate() { doTest(); }
|
||||
}
|
||||
|
||||
+12
@@ -519,6 +519,18 @@ class Foo {{
|
||||
assert ContractInference.inferContracts(method).collect { it as String } == [' -> fail']
|
||||
}
|
||||
|
||||
public void "test vararg delegation"() {
|
||||
def c = inferContracts("""
|
||||
boolean delegating(Object o, Object o1) {
|
||||
return smth(o, o1);
|
||||
}
|
||||
boolean smth(Object o, Object... o1) {
|
||||
return o == null && o1 != null;
|
||||
}
|
||||
""")
|
||||
assert c == ['!null, _ -> false', 'null, _ -> true']
|
||||
}
|
||||
|
||||
private String inferContract(String method) {
|
||||
return assertOneElement(inferContracts(method))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user