From cdb50293f2c800dd067f84731a4c8fa1b59b04de Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Thu, 28 May 2015 19:22:33 +0200 Subject: [PATCH] capture conversion: ensure captured wildcards are not replaced after creation, so substitution is consistent; at the same time ensure that "?" with upper bound Runnable is equivalent to "? extends Runnable" --- .../src/com/intellij/psi/GenericsUtil.java | 2 +- .../intellij/psi/PsiCapturedWildcardType.java | 28 +++++++++++++++---- .../src/com/intellij/psi/util/PsiUtil.java | 11 +++++--- .../intellij/psi/impl/PsiSubstitutorImpl.java | 6 ++-- .../CapturedBoundOfCapture.java | 10 +++++++ .../genericsHighlighting/IDEA57533.java | 2 +- .../genericsHighlighting/IDEA67677.java | 2 +- .../genericsHighlighting/IDEADEV14006.java | 2 +- .../genericsHighlighting/IDEADEV15534.java | 2 +- .../genericsHighlighting8/IDEA57533.java | 2 +- .../genericsHighlighting8/IDEA67677.java | 2 +- .../genericsHighlighting8/IDEADEV14006.java | 2 +- .../genericsHighlighting8/IDEADEV15534.java | 2 +- .../daemon/GenericsHighlightingTest.java | 4 +++ 14 files changed, 57 insertions(+), 20 deletions(-) create mode 100644 java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CapturedBoundOfCapture.java diff --git a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java index 3f7575827d00..e2a7f417fb62 100644 --- a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java @@ -509,7 +509,7 @@ public class GenericsUtil { final PsiType bound = ((PsiWildcardType)type).getBound(); return eliminateWildcards(bound != null ? bound : ((PsiWildcardType)type).getExtendsBound(), false);//object } else if (type instanceof PsiCapturedWildcardType && !eliminateInTypeArguments) { - return eliminateWildcards(((PsiCapturedWildcardType)type).getWildcard(), eliminateInTypeArguments); + return ((PsiCapturedWildcardType)type).getUpperBound(); } return type; } diff --git a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java index b342f601b6fb..4c522a785bb6 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java @@ -16,6 +16,9 @@ package com.intellij.psi; import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.RecursionGuard; +import com.intellij.openapi.util.RecursionManager; import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -49,8 +52,11 @@ public class PsiCapturedWildcardType extends PsiType.Stub { myExistential = existential; myContext = context; myParameter = parameter; + myUpperBound = PsiType.getJavaLangObject(myContext.getManager(), getResolveScope()); } + private static RecursionGuard guard = RecursionManager.createGuard("captureGuard"); + @Override public boolean equals(Object o) { if (!(o instanceof PsiCapturedWildcardType)) { @@ -58,7 +64,7 @@ public class PsiCapturedWildcardType extends PsiType.Stub { } final PsiCapturedWildcardType captured = (PsiCapturedWildcardType)o; - if (!myContext.equals(captured.myContext) || !myExistential.equals(captured.myExistential)) { + if (!myContext.equals(captured.myContext) || myExistential.isSuper() && !myExistential.equals(captured.myExistential)) { return false; } @@ -66,12 +72,24 @@ public class PsiCapturedWildcardType extends PsiType.Stub { return false; } - return true; + if (myParameter != null) { + final Boolean sameUpperBounds = guard.doPreventingRecursion(myContext, true, new Computable() { + @Override + public Boolean compute() { + return Comparing.equal(myUpperBound, captured.myUpperBound); + } + }); + + if (sameUpperBounds != null && sameUpperBounds) { + return true; + } + } + return myExistential.equals(captured.myExistential); } @Override public int hashCode() { - return myExistential.hashCode() + 31 * myContext.hashCode(); + return myUpperBound.hashCode() + 31 * myContext.hashCode(); } @NotNull @@ -125,14 +143,14 @@ public class PsiCapturedWildcardType extends PsiType.Stub { public PsiType getUpperBound () { final PsiType bound = myExistential.getBound(); - if (myExistential.isExtends()) { + if (myExistential.isExtends() && myParameter == null) { return bound; } else if (bound instanceof PsiCapturedWildcardType) { return PsiWildcardType.createSuper(myContext.getManager(), ((PsiCapturedWildcardType)bound).getUpperBound()); } else { - return myUpperBound != null ? myUpperBound : PsiType.getJavaLangObject(myContext.getManager(), getResolveScope()); + return myUpperBound; } } diff --git a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java index 909117c17b14..97be24624827 100644 --- a/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/util/PsiUtil.java @@ -763,10 +763,11 @@ public final class PsiUtil extends PsiUtilCore { captureContext = captured.getContext(); } PsiType glb = null; + PsiType originalBound = PsiType.NULL; if (substituted instanceof PsiWildcardType) { final PsiType[] boundTypes = typeParameter.getExtendsListTypes(); PsiManager manager = typeParameter.getManager(); - PsiType originalBound = !((PsiWildcardType)substituted).isSuper() ? ((PsiWildcardType)substituted).getBound() : null; + originalBound = !((PsiWildcardType)substituted).isSuper() ? ((PsiWildcardType)substituted).getBound() : null; glb = originalBound; for (PsiType boundType : boundTypes) { PsiType substitutedBoundType = captureSubstitutor.substitute(boundType); @@ -813,9 +814,11 @@ public final class PsiUtil extends PsiUtilCore { if (captureContext != null) { LOG.assertTrue(substituted instanceof PsiWildcardType, substituted); - substituted = oldSubstituted instanceof PsiCapturedWildcardType && substituted.equals(((PsiCapturedWildcardType)oldSubstituted).getWildcard()) - ? oldSubstituted - : PsiCapturedWildcardType.create((PsiWildcardType)substituted, captureContext, typeParameter); + substituted = + oldSubstituted instanceof PsiCapturedWildcardType && substituted.equals(((PsiCapturedWildcardType)oldSubstituted).getWildcard()) + ? oldSubstituted + : captureSubstitutor.substitute(typeParameter); + LOG.assertTrue(substituted instanceof PsiCapturedWildcardType); if (glb != null) { ((PsiCapturedWildcardType)substituted).setUpperBound(glb); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java index 5164ba1623ea..97945bc63dec 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiSubstitutorImpl.java @@ -257,8 +257,10 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { } else { PsiType substituted = substituteInternal(original); if (original instanceof PsiWildcardType && substituted instanceof PsiCapturedWildcardType) { - substituted = PsiCapturedWildcardType.create(((PsiCapturedWildcardType)substituted).getWildcard(), - ((PsiCapturedWildcardType)substituted).getContext(), param); + final PsiCapturedWildcardType capturedWildcardType = PsiCapturedWildcardType.create(((PsiCapturedWildcardType)substituted).getWildcard(), + ((PsiCapturedWildcardType)substituted).getContext(), param); + capturedWildcardType.setUpperBound(((PsiCapturedWildcardType)substituted).getUpperBound()); + substituted = capturedWildcardType; } //if (substituted == null) return false; substMap.put(param, substituted); diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CapturedBoundOfCapture.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CapturedBoundOfCapture.java new file mode 100644 index 000000000000..a51689ea9cdb --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/CapturedBoundOfCapture.java @@ -0,0 +1,10 @@ + +interface A { + K get(); +} + +class Test { + void f(A a) { + String s = a.get(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA57533.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA57533.java index 0c0628e14aa8..4e37c9763b2e 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA57533.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA57533.java @@ -1,6 +1,6 @@ class C>>{ void foo(C x){ - bar(x); + bar(x); } > void bar(C x){} } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67677.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67677.java index 691a352f8d7d..1c41f96722dd 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67677.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEA67677.java @@ -6,6 +6,6 @@ interface B { class D { void bar(B x, List y) { - x.foo(y); + x.foo(y); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV14006.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV14006.java index f73206bd35cb..1efc6d8ca930 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV14006.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV14006.java @@ -13,6 +13,6 @@ class Test2 {} class Test { public void test(TestIF testIF) { - testIF.run(); + testIF.run(); } } \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV15534.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV15534.java index 4365e40ad1c3..bf1f2d907681 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV15534.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/IDEADEV15534.java @@ -19,7 +19,7 @@ class SortTest> implements Comparable> { SortTest t2 = new SortTest(0); list.add(t2); Collections.sort(list); - t1.compareTo(t2); + t1.compareTo(t2); //this should be OK SortTest[] arr = new SortTest[0]; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java index d7ffd7e49641..476897f1e9e4 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA57533.java @@ -1,6 +1,6 @@ class C>>{ void foo(C x){ - bar(x); + bar(x); } > void bar(C x){} } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java index 7f206bbee52b..e62d31a5113b 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEA67677.java @@ -6,6 +6,6 @@ interface B { class D { void bar(B x, List y) { - x.foo(y); + x.foo(y); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java index 77cf1dbfaea8..502e323be476 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV14006.java @@ -13,6 +13,6 @@ class Test2 {} class Test { public void test(TestIF testIF) { - testIF.run(); + testIF.run(); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java index acc225a324cc..5039a4225286 100644 --- a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting8/IDEADEV15534.java @@ -19,7 +19,7 @@ class SortTest> implements Comparable> { SortTest t2 = new SortTest(0); list.add(t2); Collections.sort(list); - t1.compareTo(t2); + t1.compareTo(t2); //this should be OK SortTest[] arr = new SortTest[0]; 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 29a47dbc8e14..a6104dc70901 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java @@ -508,6 +508,10 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); } + public void testCapturedBoundOfCapture() throws Exception { + doTest(LanguageLevel.JDK_1_7, JavaSdkVersion.JDK_1_7, false); + } + public void testJavaUtilCollections_NoVerify() throws Exception { PsiClass collectionsClass = getJavaFacade().findClass("java.util.Collections", GlobalSearchScope.moduleWithLibrariesScope(getModule())); assertNotNull(collectionsClass);