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 dfaa2b21a17b..3f7575827d00 100644 --- a/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java +++ b/java/java-psi-api/src/com/intellij/psi/GenericsUtil.java @@ -297,7 +297,7 @@ public class GenericsUtil { } else if (substituted instanceof PsiCapturedWildcardType) { final PsiType extendsBound = ((PsiCapturedWildcardType)substituted).getUpperBound(); - if (acceptExtendsBound(extendsType, extendsBound) || extendsType.equals(substitutor.substitute(extendsBound))) { + if (acceptExtendsBound(extendsType, extendsBound) || extendsType.equals(extendsBound)) { return null; } } 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 cac9ce7241ca..b342f601b6fb 100644 --- a/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java +++ b/java/java-psi-api/src/com/intellij/psi/PsiCapturedWildcardType.java @@ -49,21 +49,6 @@ public class PsiCapturedWildcardType extends PsiType.Stub { myExistential = existential; myContext = context; myParameter = parameter; - if (parameter != null) { - final PsiClassType[] boundTypes = parameter.getExtendsListTypes(); - if (boundTypes.length > 0) { - PsiType result = null; - for (PsiType type : boundTypes) { - if (result == null) { - result = type; - } - else { - result = GenericsUtil.getGreatestLowerBound(result, type); - } - } - myUpperBound = result; - } - } } @Override 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 ab20c7c053c8..909117c17b14 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 @@ -719,16 +719,22 @@ public final class PsiUtil extends PsiUtilCore { final PsiClass aClass = result.getElement(); if (aClass != null) { final PsiSubstitutor substitutor = result.getSubstitutor(); + + PsiSubstitutor captureSubstitutor = substitutor; + for (PsiTypeParameter typeParameter : typeParametersIterable(aClass)) { + final PsiType substituted = substitutor.substitute(typeParameter); + if (substituted instanceof PsiWildcardType) { + captureSubstitutor = captureSubstitutor.put(typeParameter, PsiCapturedWildcardType.create((PsiWildcardType)substituted, context, typeParameter)); + } + } + Map substitutionMap = null; for (PsiTypeParameter typeParameter : typeParametersIterable(aClass)) { final PsiType substituted = substitutor.substitute(typeParameter); if (substituted instanceof PsiWildcardType) { if (substitutionMap == null) substitutionMap = new HashMap(substitutor.getSubstitutionMap()); substitutionMap.put(typeParameter, - captureTypeParameterBounds(typeParameter, substituted, context, - substitutor.put(typeParameter, - PsiCapturedWildcardType - .create((PsiWildcardType)substituted, context, typeParameter)))); + captureTypeParameterBounds(typeParameter, substituted, context, captureSubstitutor)); } } @@ -748,7 +754,7 @@ public final class PsiUtil extends PsiUtilCore { public static PsiType captureTypeParameterBounds(@NotNull PsiTypeParameter typeParameter, PsiType substituted, PsiElement context, - PsiSubstitutor substitutor) { + PsiSubstitutor captureSubstitutor) { PsiType oldSubstituted = substituted; PsiElement captureContext = context; if (substituted instanceof PsiCapturedWildcardType) { @@ -756,66 +762,63 @@ public final class PsiUtil extends PsiUtilCore { substituted = captured.getWildcard(); captureContext = captured.getContext(); } - if (substituted instanceof PsiWildcardType && !((PsiWildcardType)substituted).isSuper()) { - PsiType originalBound = ((PsiWildcardType)substituted).getBound(); - PsiManager manager = typeParameter.getManager(); + PsiType glb = null; + if (substituted instanceof PsiWildcardType) { final PsiType[] boundTypes = typeParameter.getExtendsListTypes(); + PsiManager manager = typeParameter.getManager(); + PsiType originalBound = !((PsiWildcardType)substituted).isSuper() ? ((PsiWildcardType)substituted).getBound() : null; + glb = originalBound; for (PsiType boundType : boundTypes) { - PsiType substitutedBoundType = substitutor.substitute(boundType); - PsiWildcardType wildcardType = (PsiWildcardType)substituted; + PsiType substitutedBoundType = captureSubstitutor.substitute(boundType); if (substitutedBoundType != null && !(substitutedBoundType instanceof PsiWildcardType) && !substitutedBoundType.equalsToText(CommonClassNames.JAVA_LANG_OBJECT)) { + if (originalBound instanceof PsiArrayType && + substitutedBoundType instanceof PsiArrayType && + !originalBound.isAssignableFrom(substitutedBoundType) && + !substitutedBoundType.isAssignableFrom(originalBound)) { + continue; + } + if (originalBound == null || !TypeConversionUtil.erasure(substitutedBoundType).isAssignableFrom(TypeConversionUtil.erasure(originalBound)) && !TypeConversionUtil.erasure(substitutedBoundType).isAssignableFrom(originalBound)) { //erasure is essential to avoid infinite recursion - if (wildcardType.isExtends()) { - final PsiType bound = wildcardType.getBound(); - if (bound instanceof PsiArrayType && substitutedBoundType instanceof PsiArrayType && - !bound.isAssignableFrom(substitutedBoundType) && !substitutedBoundType.isAssignableFrom(bound)) { - continue; - } - final PsiType glb = GenericsUtil.getGreatestLowerBound(bound, substitutedBoundType); - if (glb != null) { - substituted = PsiWildcardType.createExtends(manager, glb); - } + + if (glb == null) { + glb = substitutedBoundType; } else { - //unbounded - substituted = substitutedBoundType instanceof PsiCapturedWildcardType - ? ((PsiCapturedWildcardType)substitutedBoundType).getWildcard() - : PsiWildcardType.createExtends(manager, substitutedBoundType); + glb = GenericsUtil.getGreatestLowerBound(glb, substitutedBoundType); } } } } - } else if (substituted instanceof PsiWildcardType && ((PsiWildcardType)substituted).isSuper()) { - final PsiType[] boundTypes = typeParameter.getExtendsListTypes(); - PsiType glb = null; - for (PsiType boundType : boundTypes) { - final PsiType substitutedBound = substitutor.substitute(boundType); - if (substitutedBound != null) { - if (glb == null) { - glb = substitutedBound; - } - else { - glb = GenericsUtil.getGreatestLowerBound(glb, substitutedBound); + + if (glb != null) { + if (!((PsiWildcardType)substituted).isSuper()) { + substituted = glb instanceof PsiCapturedWildcardType ? ((PsiCapturedWildcardType)glb).getWildcard() + : PsiWildcardType.createExtends(manager, glb); + } + else { + if (captureContext != null) { + final PsiCapturedWildcardType capturedWildcardType = oldSubstituted instanceof PsiCapturedWildcardType + ? (PsiCapturedWildcardType)oldSubstituted + : (PsiCapturedWildcardType)captureSubstitutor.substitute(typeParameter); + LOG.assertTrue(capturedWildcardType != null); + capturedWildcardType.setUpperBound(glb); + return capturedWildcardType; } } } - if (glb != null && captureContext != null) { - final PsiCapturedWildcardType capturedWildcardType = oldSubstituted instanceof PsiCapturedWildcardType - ? (PsiCapturedWildcardType)oldSubstituted - : PsiCapturedWildcardType.create((PsiWildcardType)substituted, captureContext, typeParameter); - capturedWildcardType.setUpperBound(glb); - return capturedWildcardType; - } } if (captureContext != null) { LOG.assertTrue(substituted instanceof PsiWildcardType, substituted); - substituted = oldSubstituted instanceof PsiCapturedWildcardType && substituted == ((PsiCapturedWildcardType)oldSubstituted).getWildcard() + substituted = oldSubstituted instanceof PsiCapturedWildcardType && substituted.equals(((PsiCapturedWildcardType)oldSubstituted).getWildcard()) ? oldSubstituted : PsiCapturedWildcardType.create((PsiWildcardType)substituted, captureContext, typeParameter); + if (glb != null) { + ((PsiCapturedWildcardType)substituted).setUpperBound(glb); + } } return substituted; } diff --git a/java/java-psi-impl/src/com/intellij/psi/PsiTypeMapper.java b/java/java-psi-impl/src/com/intellij/psi/PsiTypeMapper.java index a828306e9f7f..12ebc76f1afa 100644 --- a/java/java-psi-impl/src/com/intellij/psi/PsiTypeMapper.java +++ b/java/java-psi-impl/src/com/intellij/psi/PsiTypeMapper.java @@ -67,7 +67,14 @@ public abstract class PsiTypeMapper extends PsiTypeVisitorEx { @Override public PsiType visitCapturedWildcardType(final PsiCapturedWildcardType type) { PsiWildcardType mapped = mapType(type.getWildcard()); - return mapped == null ? null : PsiCapturedWildcardType.create(mapped, type.getContext(), type.getTypeParameter()); + if (mapped == null) { + return null; + } + else { + final PsiCapturedWildcardType capturedWildcardType = PsiCapturedWildcardType.create(mapped, type.getContext(), type.getTypeParameter()); + capturedWildcardType.setUpperBound(mapType(type.getUpperBound())); + return capturedWildcardType; + } } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java index 4b9c20fc45fa..540c62867fd6 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/PsiImplUtil.java @@ -423,12 +423,7 @@ public class PsiImplUtil { return wildcardType.isSuper() ? wildcardType.getBound() : PsiCapturedWildcardType.create(wildcardType, expression); } else { - if (wildcardType.isExtends()) { - return wildcardType.getBound(); - } - else { - return ((PsiCapturedWildcardType)type).getUpperBound(); - } + return ((PsiCapturedWildcardType)type).getUpperBound(); } } diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/PreserveCaptureWildcardsInUpperBounds.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/PreserveCaptureWildcardsInUpperBounds.java new file mode 100644 index 000000000000..8b448c590042 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/genericsHighlighting/PreserveCaptureWildcardsInUpperBounds.java @@ -0,0 +1,24 @@ + +class C56 { + + class A {} + + class C { + void foo(A x){ + bar(x); + } + void bar(A x){} + } +} + +class C57 { + class B {} + class A extends B {} + + class C { + void foo(A x){ + bar(x); + } + void bar(B x){} + } +} 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 c38c571ee451..a76f320ed0cb 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInsight/daemon/GenericsHighlightingTest.java @@ -496,6 +496,10 @@ public class GenericsHighlightingTest extends LightDaemonAnalyzerTestCase { doTest(LanguageLevel.JDK_1_8, JavaSdkVersion.JDK_1_8, true); } + public void testPreserveCaptureWildcardsInUpperBounds() 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);