From 9fce6c0640f9f2ba7edc73b95c4cb4cb388597c2 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 17 Oct 2014 19:58:06 +0200 Subject: [PATCH] erasure method call type if unchecked assignment was applied during applicability check (IDEA-67862) (cherry picked from commit f106f813559768f90952caac6a2eec4cfeed7103) --- .../java/PsiMethodCallExpressionImpl.java | 26 ++++++++++++++++--- ...ionWasAppliedDuringApplicabilityCheck.java | 22 ++++++++++++++++ .../daemon/GenericsHighlightingTest.java | 4 +++ 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/MethodCallTypeErasedWhenUncheckedConversionWasAppliedDuringApplicabilityCheck.java diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java index dc204b4ae315..d57fbf207830 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodCallExpressionImpl.java @@ -28,6 +28,7 @@ import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; import com.intellij.psi.impl.source.tree.ChildRole; import com.intellij.psi.impl.source.tree.ElementType; import com.intellij.psi.impl.source.tree.JavaElementType; +import com.intellij.psi.infos.MethodCandidateInfo; import com.intellij.psi.tree.ChildRoleBase; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTypesUtil; @@ -197,7 +198,7 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements ret = ((PsiClassType)ret).setLanguageLevel(languageLevel); } if (is15OrHigher) { - return captureReturnType(call, method, ret, result.getSubstitutor()); + return captureReturnType(call, method, ret, result, languageLevel); } return TypeConversionUtil.erasure(ret); } @@ -206,15 +207,34 @@ public class PsiMethodCallExpressionImpl extends ExpressionPsiElement implements public static PsiType captureReturnType(PsiMethodCallExpression call, PsiMethod method, PsiType ret, - PsiSubstitutor substitutor) { + JavaResolveResult result, + LanguageLevel languageLevel) { + PsiSubstitutor substitutor = result.getSubstitutor(); PsiType substitutedReturnType = substitutor.substitute(ret); - if (substitutedReturnType == null) return TypeConversionUtil.erasure(ret); + if (substitutedReturnType == null) { + return TypeConversionUtil.erasure(ret); + } + if (InferenceSession.wasUncheckedConversionPerformed(call)) { // 18.5.2 // if unchecked conversion was necessary, then this substitution provides the parameter types of the invocation type, // while the return type and thrown types are given by the erasure of m's type (without applying θ'). return TypeConversionUtil.erasure(substitutedReturnType); } + + //15.12.2.6. Method Invocation Type + // If unchecked conversion was necessary for the method to be applicable, + // the parameter types of the invocation type are the parameter types of the method's type, + // and the return type and thrown types are given by the erasures of the return type and thrown types of the method's type. + if (result instanceof MethodCandidateInfo && ((MethodCandidateInfo)result).isApplicable()) { + final PsiType[] args = call.getArgumentList().getExpressionTypes(); + final boolean allowUncheckedConversion = false; + final int applicabilityLevel = PsiUtil.getApplicabilityLevel(method, substitutor, args, languageLevel, allowUncheckedConversion, true); + if (applicabilityLevel == MethodCandidateInfo.ApplicabilityLevel.NOT_APPLICABLE) { + return TypeConversionUtil.erasure(substitutedReturnType); + } + } + if (PsiUtil.isRawSubstitutor(method, substitutor)) { final PsiType returnTypeErasure = TypeConversionUtil.erasure(ret); if (Comparing.equal(TypeConversionUtil.erasure(substitutedReturnType), returnTypeErasure)) { diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/MethodCallTypeErasedWhenUncheckedConversionWasAppliedDuringApplicabilityCheck.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/MethodCallTypeErasedWhenUncheckedConversionWasAppliedDuringApplicabilityCheck.java new file mode 100644 index 000000000000..2a30c0ec79e9 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/MethodCallTypeErasedWhenUncheckedConversionWasAppliedDuringApplicabilityCheck.java @@ -0,0 +1,22 @@ +import java.util.Collection; +import java.util.List; + +class Main1 { + static Collection> foo(Collection> x) { return x; } + + public static void main(String[] args) { + List x = null; + foo(x).iterator().next().iterator(); + } +} + +class Main { + static List foo(Collection x) { return null; } + + public static void main(String[] args) { + List x = null; + String s = foo(x).get(0); + foo(x).iterator().next().toLowerCase(); + } +} + diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java index f169b461bc38..e957e7a9a19c 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java @@ -410,6 +410,10 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); } + public void testMethodCallTypeErasedWhenUncheckedConversionWasAppliedDuringApplicabilityCheck() { + doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); + } + public void testInferredParameterInBoundsInRecursiveGenerics() { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); }