diff options
Diffstat (limited to 'java/java-psi-impl/src/com/intellij')
17 files changed, 339 insertions, 315 deletions
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 0de45be17786..77fd0081d161 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 @@ -493,6 +493,13 @@ public class PsiImplUtil { return PsiUtil.captureToplevelWildcards(type, expression); } + final PsiElement parent = toplevel.getParent(); + if (parent instanceof PsiExpressionList && + PsiUtil.isLanguageLevel8OrHigher(parent) && + parent.getParent() instanceof PsiCallExpression) { + return PsiUtil.captureToplevelWildcards(type, expression); + } + final PsiType normalized = doNormalizeWildcardByPosition(type, expression, toplevel); LOG.assertTrue(normalized.isValid(), type); if (normalized instanceof PsiClassType && !PsiUtil.isAccessedForWriting(toplevel)) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java index 36a725aa3135..369ce919f5a1 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java @@ -15,15 +15,18 @@ */ package com.intellij.psi.impl.compiled; +import com.intellij.diagnostic.PluginException; import com.intellij.ide.caches.FileContent; import com.intellij.ide.highlighter.JavaClassFileType; import com.intellij.ide.highlighter.JavaFileType; +import com.intellij.ide.plugins.PluginManagerCore; import com.intellij.lang.ASTNode; import com.intellij.lang.FileASTNode; import com.intellij.lang.java.JavaLanguage; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.progress.NonCancelableSection; import com.intellij.openapi.progress.ProgressIndicatorProvider; @@ -35,6 +38,7 @@ import com.intellij.openapi.util.ModificationTracker; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; +import com.intellij.psi.compiled.ClassFileDecompilers; import com.intellij.psi.impl.JavaPsiImplementationHelper; import com.intellij.psi.impl.PsiFileEx; import com.intellij.psi.impl.java.stubs.PsiClassStub; @@ -324,7 +328,7 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub> setMirror(mirrorTreeElement); } catch (InvalidMirrorException e) { - LOG.error(file.getPath(), e); + LOG.error(file.getPath(), wrapException(e, file)); } finally { section.done(); @@ -337,6 +341,18 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub> return mirrorTreeElement.getPsi(); } + private static Exception wrapException(InvalidMirrorException e, VirtualFile file) { + ClassFileDecompilers.Decompiler decompiler = ClassFileDecompilers.find(file); + if (decompiler instanceof ClassFileDecompilers.Light) { + PluginId pluginId = PluginManagerCore.getPluginByClassName(decompiler.getClass().getName()); + if (pluginId != null) { + return new PluginException(e, pluginId); + } + } + + return e; + } + @Override public PsiFile getDecompiledPsiFile() { return (PsiFile)getMirror(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java index 599f756adbc1..16d971238684 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsTypeElementImpl.java @@ -17,8 +17,7 @@ package com.intellij.psi.impl.compiled; import com.intellij.openapi.util.AtomicNotNullLazyValue; import com.intellij.openapi.util.NotNullLazyValue; -import com.intellij.openapi.util.NullableLazyValue; -import com.intellij.openapi.util.VolatileNullableLazyValue; +import com.intellij.openapi.util.Ref; import com.intellij.psi.*; import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.PsiJavaParserFacadeImpl; @@ -28,7 +27,6 @@ import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.impl.source.tree.TreeElement; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement { @NonNls static final char VARIANCE_NONE = '\0'; @@ -41,18 +39,18 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement private final PsiElement myParent; private final String myTypeText; private final char myVariance; - private final NullableLazyValue<ClsElementImpl> myChild; + private final NotNullLazyValue<Ref<ClsElementImpl>> myChild; private final NotNullLazyValue<PsiType> myCachedType; public ClsTypeElementImpl(@NotNull PsiElement parent, @NotNull String typeText, char variance) { myParent = parent; myTypeText = TypeInfo.internFrequentType(typeText); myVariance = variance; - myChild = new VolatileNullableLazyValue<ClsElementImpl>() { - @Nullable + myChild = new AtomicNotNullLazyValue<Ref<ClsElementImpl>>() { + @NotNull @Override - protected ClsElementImpl compute() { - return calculateChild(); + protected Ref<ClsElementImpl> compute() { + return Ref.create(calculateChild()); } }; myCachedType = new AtomicNotNullLazyValue<PsiType>() { @@ -67,7 +65,7 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement @Override @NotNull public PsiElement[] getChildren() { - ClsElementImpl child = myChild.getValue(); + ClsElementImpl child = myChild.getValue().get(); return child != null ? new PsiElement[]{child} : PsiElement.EMPTY_ARRAY; } @@ -111,7 +109,7 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement public void setMirror(@NotNull TreeElement element) throws InvalidMirrorException { setMirrorCheckingType(element, JavaElementType.TYPE); - ClsElementImpl child = myChild.getValue(); + ClsElementImpl child = myChild.getValue().get(); if (child != null) { child.setMirror(element.getFirstChildNode()); } @@ -157,7 +155,7 @@ public class ClsTypeElementImpl extends ClsElementImpl implements PsiTypeElement PsiType result = PsiJavaParserFacadeImpl.getPrimitiveType(myTypeText); if (result != null) return result; - ClsElementImpl childElement = myChild.getValue(); + ClsElementImpl childElement = myChild.getValue().get(); if (childElement instanceof ClsTypeElementImpl) { if (isArray()) { switch (myVariance) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java index a43c02d8a7a4..f304fe250bae 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiClassReferenceType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -30,16 +30,16 @@ import java.util.List; /** * @author max */ -public class PsiClassReferenceType extends PsiClassType { +public class PsiClassReferenceType extends PsiClassType.Stub { @NotNull private final PsiJavaCodeReferenceElement myReference; - public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel langLevel) { - this(reference, langLevel, collectAnnotations(reference)); + public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level) { + this(reference, level, collectAnnotations(reference)); } - public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel langLevel, @NotNull PsiAnnotation[] annotations) { - super(langLevel, annotations); + public PsiClassReferenceType(@NotNull PsiJavaCodeReferenceElement reference, LanguageLevel level, @NotNull PsiAnnotation[] annotations) { + super(level, annotations); myReference = reference; } @@ -89,7 +89,7 @@ public class PsiClassReferenceType extends PsiClassType { return resolveGenerics().getElement(); } - private static class DelegatingClassResolveResult implements ClassResolveResult { + private static class DelegatingClassResolveResult implements PsiClassType.ClassResolveResult { private final JavaResolveResult myDelegate; private DelegatingClassResolveResult(@NotNull JavaResolveResult delegate) { @@ -182,19 +182,37 @@ public class PsiClassReferenceType extends PsiClassType { @NotNull @Override public String getPresentableText() { - return getAnnotationsTextPrefix(false, false, true) + PsiNameHelper.getPresentableText(myReference); + String presentableText = PsiNameHelper.getPresentableText(myReference); + PsiAnnotation[] annotations = getAnnotations(); + if (annotations.length == 0) return presentableText; + + StringBuilder sb = new StringBuilder(); + PsiNameHelper.appendAnnotations(sb, annotations, false); + sb.append(presentableText); + return sb.toString(); } @NotNull @Override - public String getCanonicalText() { - return myReference.getCanonicalText(); + public String getCanonicalText(boolean annotated) { + return getText(annotated); } @NotNull @Override public String getInternalCanonicalText() { - return getAnnotationsTextPrefix(true, false, true) + getCanonicalText(); + return getText(true); + } + + private String getText(boolean annotated) { + if (myReference instanceof PsiJavaCodeReferenceElementImpl) { + PsiAnnotation[] annotations = getAnnotations(); + if (!annotated || annotations.length == 0) annotations = null; + return ((PsiJavaCodeReferenceElementImpl)myReference).getCanonicalText(annotated, annotations); + } + else { + return myReference.getCanonicalText(); + } } @NotNull diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java index 9456c29f6ceb..77a45011144d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiImmediateClassType.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.source; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; @@ -30,11 +31,12 @@ import java.util.List; /** * @author dsl */ -public class PsiImmediateClassType extends PsiClassType { +public class PsiImmediateClassType extends PsiClassType.Stub { private final PsiClass myClass; private final PsiSubstitutor mySubstitutor; private final PsiManager myManager; private String myCanonicalText; + private String myCanonicalTextAnnotated; private String myPresentableText; private String myInternalCanonicalText; @@ -80,15 +82,15 @@ public class PsiImmediateClassType extends PsiClassType { this(aClass, substitutor, null, PsiAnnotation.EMPTY_ARRAY); } - public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel languageLevel) { - this(aClass, substitutor, languageLevel, PsiAnnotation.EMPTY_ARRAY); + public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @Nullable LanguageLevel level) { + this(aClass, substitutor, level, PsiAnnotation.EMPTY_ARRAY); } public PsiImmediateClassType(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, - @Nullable LanguageLevel languageLevel, - @NotNull PsiAnnotation[] annotations) { - super(languageLevel, annotations); + @Nullable LanguageLevel level, + @NotNull PsiAnnotation... annotations) { + super(level, annotations); myClass = aClass; myManager = aClass.getManager(); mySubstitutor = substitutor; @@ -138,112 +140,119 @@ public class PsiImmediateClassType extends PsiClassType { @Override public String getPresentableText() { if (myPresentableText == null) { - StringBuilder buffer = new StringBuilder(); - buildText(myClass, mySubstitutor, buffer, false, false); - myPresentableText = buffer.toString(); + myPresentableText = getText(TextType.PRESENTABLE, true); } return myPresentableText; } @NotNull @Override - public String getCanonicalText() { - if (myCanonicalText == null) { - assert mySubstitutor.isValid(); - StringBuilder buffer = new StringBuilder(); - buildText(myClass, mySubstitutor, buffer, true, false); - myCanonicalText = buffer.toString(); + public String getCanonicalText(boolean annotated) { + String cached = annotated ? myCanonicalTextAnnotated : myCanonicalText; + if (cached == null) { + cached = getText(TextType.CANONICAL, annotated); + if (annotated) myCanonicalTextAnnotated = cached; + else myCanonicalText = cached; } - return myCanonicalText; + return cached; } @NotNull @Override public String getInternalCanonicalText() { if (myInternalCanonicalText == null) { - StringBuilder buffer = new StringBuilder(); - buildText(myClass, mySubstitutor, buffer, true, true); - myInternalCanonicalText = buffer.toString(); + myInternalCanonicalText = getText(TextType.INT_CANONICAL, true); } return myInternalCanonicalText; } + private enum TextType { PRESENTABLE, CANONICAL, INT_CANONICAL } + + private String getText(@NotNull TextType textType, boolean annotated) { + assert mySubstitutor.isValid(); + StringBuilder buffer = new StringBuilder(); + buildText(myClass, mySubstitutor, buffer, textType, annotated); + return buffer.toString(); + } + private void buildText(@NotNull PsiClass aClass, @NotNull PsiSubstitutor substitutor, @NotNull StringBuilder buffer, - boolean canonical, - boolean internal) { + @NotNull TextType textType, + boolean annotated) { if (aClass instanceof PsiAnonymousClass) { - ClassResolveResult baseResolveResult = ((PsiAnonymousClass) aClass).getBaseClassType().resolveGenerics(); + ClassResolveResult baseResolveResult = ((PsiAnonymousClass)aClass).getBaseClassType().resolveGenerics(); PsiClass baseClass = baseResolveResult.getElement(); - PsiSubstitutor baseSub = baseResolveResult.getSubstitutor(); if (baseClass != null) { - buildText(baseClass, baseSub, buffer, canonical, internal); + buildText(baseClass, baseResolveResult.getSubstitutor(), buffer, textType, false); } return; } - if (canonical == internal) { - buffer.append(getAnnotationsTextPrefix(internal, false, true)); - } + boolean qualified = textType != TextType.PRESENTABLE; PsiClass enclosingClass = null; if (!aClass.hasModifierProperty(PsiModifier.STATIC)) { - final PsiElement parent = aClass.getParent(); + PsiElement parent = aClass.getParent(); if (parent instanceof PsiClass && !(parent instanceof PsiAnonymousClass)) { enclosingClass = (PsiClass)parent; } } if (enclosingClass != null) { - buildText(enclosingClass, substitutor, buffer, canonical, false); + buildText(enclosingClass, substitutor, buffer, textType, false); buffer.append('.'); - buffer.append(aClass.getName()); } - else { - final String name; - if (!canonical) { - name = aClass.getName(); - } - else { - final String qualifiedName = aClass.getQualifiedName(); - if (qualifiedName == null) { - name = aClass.getName(); - } - else { - name = qualifiedName; + else if (qualified) { + String fqn = aClass.getQualifiedName(); + if (fqn != null) { + String prefix = StringUtil.getPackageName(fqn); + if (!StringUtil.isEmpty(prefix)) { + buffer.append(prefix); + buffer.append('.'); } } - buffer.append(name); } + if (annotated) { + PsiNameHelper.appendAnnotations(buffer, getAnnotations(), qualified); + } + + buffer.append(aClass.getName()); + PsiTypeParameter[] typeParameters = aClass.getTypeParameters(); if (typeParameters.length > 0) { - StringBuilder pineBuffer = new StringBuilder(); - pineBuffer.append('<'); + int pos = buffer.length(); + buffer.append('<'); + for (int i = 0; i < typeParameters.length; i++) { PsiTypeParameter typeParameter = typeParameters[i]; PsiUtilCore.ensureValid(typeParameter); - if (i > 0) pineBuffer.append(','); - final PsiType substitutionResult = substitutor.substitute(typeParameter); + + if (i > 0) { + buffer.append(','); + if (textType == TextType.PRESENTABLE) buffer.append(' '); + } + + PsiType substitutionResult = substitutor.substitute(typeParameter); if (substitutionResult == null) { - pineBuffer = null; + buffer.setLength(pos); + pos = -1; break; } PsiUtil.ensureValidType(substitutionResult); - if (canonical) { - if (internal) { - pineBuffer.append(substitutionResult.getInternalCanonicalText()); - } - else { - pineBuffer.append(substitutionResult.getCanonicalText()); - } + + if (textType == TextType.PRESENTABLE) { + buffer.append(substitutionResult.getPresentableText()); + } + else if (textType == TextType.CANONICAL) { + buffer.append(substitutionResult.getCanonicalText(annotated)); } else { - pineBuffer.append(substitutionResult.getPresentableText()); + buffer.append(substitutionResult.getInternalCanonicalText()); } } - if (pineBuffer != null) { - buffer.append(pineBuffer); + + if (pos >= 0) { buffer.append('>'); } } @@ -265,7 +274,6 @@ public class PsiImmediateClassType extends PsiClassType { return false; } return equals(patternType); - } @Override @@ -277,14 +285,12 @@ public class PsiImmediateClassType extends PsiClassType { @Override @NotNull public LanguageLevel getLanguageLevel() { - if (myLanguageLevel != null) return myLanguageLevel; - return PsiUtil.getLanguageLevel(myClass); + return myLanguageLevel != null ? myLanguageLevel : PsiUtil.getLanguageLevel(myClass); } @NotNull @Override - public PsiClassType setLanguageLevel(@NotNull final LanguageLevel languageLevel) { - if (languageLevel.equals(myLanguageLevel)) return this; - return new PsiImmediateClassType(myClass, mySubstitutor, languageLevel,getAnnotations()); + public PsiClassType setLanguageLevel(@NotNull LanguageLevel level) { + return level.equals(myLanguageLevel) ? this : new PsiImmediateClassType(myClass, mySubstitutor, level, getAnnotations()); } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java index 396b750c8c2a..5ee1243b09ce 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiJavaCodeReferenceElementImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -49,6 +49,7 @@ import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Arrays; import java.util.List; public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement implements PsiJavaCodeReferenceElement, SourceJavaCodeReference { @@ -255,36 +256,47 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme @Override @NotNull public String getCanonicalText() { + return getCanonicalText(false, null); + } + + @NotNull + public String getCanonicalText(boolean annotated, @Nullable PsiAnnotation[] annotations) { switch (getKind()) { case CLASS_NAME_KIND: case CLASS_OR_PACKAGE_NAME_KIND: case CLASS_IN_QUALIFIED_NEW_KIND: final PsiElement target = resolve(); if (target instanceof PsiClass) { - final PsiClass aClass = (PsiClass)target; - String name = aClass.getQualifiedName(); - if (name == null) { - name = aClass.getName(); //? + PsiClass aClass = (PsiClass)target; + StringBuilder buffer = new StringBuilder(); + + PsiElement qualifier = getQualifier(); + String prefix = null; + if (qualifier instanceof PsiJavaCodeReferenceElementImpl) { + prefix = ((PsiJavaCodeReferenceElementImpl)qualifier).getCanonicalText(annotated, null); } - final PsiType[] types = getTypeParameters(); - if (types.length == 0) { - final PsiElement qualifier = getQualifier(); - if (qualifier instanceof PsiJavaCodeReferenceElement) { - return StringUtil.getQualifiedName(((PsiJavaCodeReferenceElement)qualifier).getCanonicalText(), aClass.getName()); + else { + String fqn = aClass.getQualifiedName(); + if (fqn != null) { + prefix = StringUtil.getPackageName(fqn); } - return name; } - final StringBuilder buf = new StringBuilder(); - buf.append(name); - buf.append('<'); - for (int i = 0; i < types.length; i++) { - if (i > 0) buf.append(','); - buf.append(types[i].getCanonicalText()); + if (!StringUtil.isEmpty(prefix)) { + buffer.append(prefix); + buffer.append('.'); } - buf.append('>'); - return buf.toString(); + if (annotated) { + List<PsiAnnotation> list = annotations != null ? Arrays.asList(annotations) : getAnnotations(); + PsiNameHelper.appendAnnotations(buffer, list, true); + } + + buffer.append(aClass.getName()); + + PsiNameHelper.appendTypeArgs(buffer, getTypeParameters(), true, annotated); + + return buffer.toString(); } else if (target instanceof PsiPackage) { return ((PsiPackage)target).getQualifiedName(); @@ -293,6 +305,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme LOG.assertTrue(target == null, target); return getNormalizedText(); } + case PACKAGE_NAME_KIND: case CLASS_FQ_NAME_KIND: case CLASS_FQ_OR_PACKAGE_NAME_KIND: @@ -327,7 +340,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme if (incompleteCode && result.length == 0 && kind != CLASS_FQ_NAME_KIND && kind != CLASS_FQ_OR_PACKAGE_NAME_KIND) { VariableResolverProcessor processor = new VariableResolverProcessor(referenceElement, containingFile); - PsiScopesUtil.resolveAndWalk(processor, referenceElement, null, incompleteCode); + PsiScopesUtil.resolveAndWalk(processor, referenceElement, null, true); result = processor.getResult(); if (result.length == 0 && kind == CLASS_NAME_KIND) { result = referenceElement.resolve(PACKAGE_NAME_KIND, containingFile); @@ -457,16 +470,16 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme case CLASS_FQ_OR_PACKAGE_NAME_KIND: case CLASS_OR_PACKAGE_NAME_KIND: { int classKind = kind == CLASS_OR_PACKAGE_NAME_KIND ? CLASS_NAME_KIND : CLASS_FQ_NAME_KIND; - JavaResolveResult[] result = resolve(classKind,containingFile); + JavaResolveResult[] result = resolve(classKind, containingFile); if (result.length == 1 && !result[0].isAccessible()) { - JavaResolveResult[] packageResult = resolve(PACKAGE_NAME_KIND,containingFile); + JavaResolveResult[] packageResult = resolve(PACKAGE_NAME_KIND, containingFile); if (packageResult.length != 0) { result = packageResult; } } else if (result.length == 0) { - result = resolve(PACKAGE_NAME_KIND,containingFile); + result = resolve(PACKAGE_NAME_KIND, containingFile); } return result; @@ -607,7 +620,12 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme for (PsiAnnotation annotation : annotations) { if (annotation.getParent() != newParent) { - newParent.addAfter(annotation, anchor); + if (anchor != null) { + newParent.addAfter(annotation, anchor); + } + else { + newParent.add(annotation); + } annotation.delete(); } } @@ -935,7 +953,6 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme final PsiReferenceParameterList parameterList = getParameterList(); if (parameterList == null) return PsiType.EMPTY_ARRAY; return parameterList.getTypeArguments(); - } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java index 5b76439ef406..20db589bef5c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/JavaResolveUtil.java @@ -225,15 +225,21 @@ public class JavaResolveUtil { return true; } - public static void substituteResults(@NotNull PsiJavaCodeReferenceElement ref, @NotNull JavaResolveResult[] result) { + public static void substituteResults(final @NotNull PsiJavaCodeReferenceElement ref, @NotNull JavaResolveResult[] result) { if (result.length > 0 && result[0].getElement() instanceof PsiClass) { - PsiType[] parameters = ref.getTypeParameters(); for (int i = 0; i < result.length; i++) { - CandidateInfo resolveResult = (CandidateInfo)result[i]; - PsiElement resultElement = resolveResult.getElement(); + final CandidateInfo resolveResult = (CandidateInfo)result[i]; + final PsiElement resultElement = resolveResult.getElement(); if (resultElement instanceof PsiClass && ((PsiClass)resultElement).hasTypeParameters()) { - PsiSubstitutor substitutor = resolveResult.getSubstitutor().putAll((PsiClass)resultElement, parameters); - result[i] = new CandidateInfo(resolveResult, substitutor); + PsiSubstitutor substitutor = resolveResult.getSubstitutor(); + result[i] = new CandidateInfo(resolveResult, substitutor) { + @NotNull + @Override + public PsiSubstitutor getSubstitutor() { + final PsiType[] parameters = ref.getTypeParameters(); + return super.getSubstitutor().putAll((PsiClass)resultElement, parameters); + } + }; } } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java index a52ea73a18d5..b4b188c772cc 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/FunctionalInterfaceParameterizationUtil.java @@ -18,7 +18,6 @@ package com.intellij.psi.impl.source.resolve.graphInference; import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.constraints.TypeEqualityConstraint; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.TypeConversionUtil; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.Nullable; @@ -102,7 +101,7 @@ public class FunctionalInterfaceParameterizationUtil { return null; } - final PsiSubstitutor substitutor = session.resolveDependencies(session.getInferenceVariables()); + final PsiSubstitutor substitutor = session.retrieveNonPrimitiveEqualsBounds(session.getInferenceVariables()); final PsiType[] newTypeParameters = new PsiType[parameters.length]; for (int i = 0; i < typeParameters.length; i++) { PsiTypeParameter typeParameter = typeParameters[i]; @@ -119,14 +118,10 @@ public class FunctionalInterfaceParameterizationUtil { return null; } - if (!TypeConversionUtil.containsWildcards(parameterization)) { + if (!TypeConversionUtil.containsWildcards(parameterization) && psiClassType.isAssignableFrom(parameterization)) { return parameterization; } - if (!psiClassType.isAssignableFrom(parameterization)) { - return null; - } - return getNonWildcardParameterization((PsiClassType)psiClassType); } return null; @@ -169,27 +164,32 @@ public class FunctionalInterfaceParameterizationUtil { for (int i = 0; i < parameters.length; i++) { PsiType paramType = parameters[i]; if (paramType instanceof PsiWildcardType) { - final PsiClassType[] extendsListTypes = typeParameters[i].getExtendsListTypes(); - final PsiClassType Bi = extendsListTypes.length > 0 ? extendsListTypes[0] - : PsiType.getJavaLangObject(psiClass.getManager(), - GlobalSearchScope.allScope(psiClass.getProject())); - if (PsiPolyExpressionUtil.mentionsTypeParameters(Bi, typeParametersSet)) { - return null; + final PsiType bound = GenericsUtil.eliminateWildcards(((PsiWildcardType)paramType).getBound(), false); + if (((PsiWildcardType)paramType).isSuper()) { + newParameters[i] = bound; } - - final PsiType bound = ((PsiWildcardType)paramType).getBound(); - if (bound == null) { - newParameters[i] = Bi; - } else if (((PsiWildcardType)paramType).isExtends()){ - newParameters[i] = GenericsUtil.getGreatestLowerBound(Bi, GenericsUtil.eliminateWildcards(bound, false)); - } else { - newParameters[i] = GenericsUtil.eliminateWildcards(bound, false); + else { + newParameters[i] = bound != null ? bound : PsiType.getJavaLangObject(psiClass.getManager(), psiClassType.getResolveScope()); + for (PsiClassType paramBound : typeParameters[i].getExtendsListTypes()) { + if (!PsiPolyExpressionUtil.mentionsTypeParameters(paramBound, typeParametersSet)) { + newParameters[i] = GenericsUtil.getGreatestLowerBound(paramBound, newParameters[i]); + } + } } } else { newParameters[i] = paramType; } } - return JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, newParameters); + + if (!isWellFormed(psiClass, typeParameters, newParameters)) { + return null; + } + + final PsiClassType parameterization = JavaPsiFacade.getElementFactory(psiClass.getProject()).createType(psiClass, newParameters); + if (!psiClassType.isAssignableFrom(parameterization)) { + return null; + } + return parameterization; } return null; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java index cc666815c2d2..f30c7ae6382c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceIncorporationPhase.java @@ -110,18 +110,6 @@ public class InferenceIncorporationPhase { } } } - - //todo no such a rule in spec?! - for (PsiType lowerBound : lowerBounds) { - if (mySession.isProperType(lowerBound)) { - final PsiSubstitutor substitutor = PsiSubstitutor.EMPTY.put(inferenceVariable.getParameter(), lowerBound); - for (PsiType upperBound : upperBounds) { - if (!mySession.isProperType(upperBound)) { - addConstraint(new StrictSubtypingConstraint(substitutor.substitute(upperBound), lowerBound)); - } - } - } - } } for (Pair<PsiTypeParameter[], PsiClassType> capture : myCaptures) { @@ -389,21 +377,4 @@ public class InferenceIncorporationPhase { } } } - - public PsiSubstitutor checkIncorporated(PsiSubstitutor substitutor, Collection<InferenceVariable> variables) { - for (InferenceVariable variable : variables) { //todo equals bounds? - for (PsiType lowerBound : variable.getBounds(InferenceBound.LOWER)) { - lowerBound = substitutor.substitute(lowerBound); - if (mySession.isProperType(lowerBound)) { - for (PsiType upperBound : variable.getBounds(InferenceBound.UPPER)) { - upperBound = substitutor.substitute(upperBound); - if (mySession.isProperType(upperBound) && !TypeConversionUtil.isAssignable(upperBound, lowerBound)) { - return null; - } - } - } - } - } - return substitutor; - } } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java index abde4616fe77..53911011bc17 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceSession.java @@ -20,15 +20,8 @@ import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Pair; import com.intellij.psi.*; -import com.intellij.psi.impl.PsiImplUtil; import com.intellij.psi.impl.source.resolve.graphInference.constraints.*; import com.intellij.psi.infos.MethodCandidateInfo; -import com.intellij.psi.scope.MethodProcessorSetupFailedException; -import com.intellij.psi.scope.PsiConflictResolver; -import com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver; -import com.intellij.psi.scope.processor.MethodCandidatesProcessor; -import com.intellij.psi.scope.processor.MethodResolverProcessor; -import com.intellij.psi.scope.util.PsiScopesUtil; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTypesUtil; @@ -174,7 +167,8 @@ public class InferenceSession { return true; } - private static PsiType getParameterType(PsiParameter[] parameters, PsiExpression[] args, int i, PsiSubstitutor substitutor) { + private static PsiType getParameterType(PsiParameter[] parameters, PsiExpression[] args, int i, @Nullable PsiSubstitutor substitutor) { + if (substitutor == null) return null; PsiType parameterType = substitutor.substitute(parameters[i < parameters.length ? i : parameters.length - 1].getType()); if (parameterType instanceof PsiEllipsisType) { final PsiExpression arg = args[i]; @@ -213,7 +207,7 @@ public class InferenceSession { PsiMethod parentMethod) { if (!repeatInferencePhases(true)) { //inferred result would be checked as candidate won't be applicable - return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false); + return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor); } if (parentMethod != null) { @@ -299,17 +293,17 @@ public class InferenceSession { } } } else { - return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor, false); + return resolveSubset(myInferenceVariables.values(), mySiteSubstitutor); } return prepareSubstitution(); } - public PsiSubstitutor resolveDependencies(Collection<InferenceVariable> variables) { + public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) { PsiSubstitutor substitutor = mySiteSubstitutor; for (InferenceVariable variable : variables) { final PsiType equalsBound = getEqualsBound(variable, substitutor); - if (equalsBound != PsiType.NULL) { + if (!(equalsBound instanceof PsiPrimitiveType)) { substitutor = substitutor.put(variable.getParameter(), equalsBound); } } @@ -340,9 +334,13 @@ public class InferenceSession { return false; } - public void initBounds(PsiTypeParameter... typeParameters) { + public boolean initBounds(PsiTypeParameter... typeParameters) { + boolean sameMethodCall = false; for (PsiTypeParameter parameter : typeParameters) { - if (myInferenceVariables.containsKey(parameter)) continue; + if (myInferenceVariables.containsKey(parameter)) { + sameMethodCall = true; + continue; + } InferenceVariable variable = new InferenceVariable(parameter); boolean added = false; final PsiClassType[] extendsListTypes = parameter.getExtendsListTypes(); @@ -359,29 +357,19 @@ public class InferenceSession { } myInferenceVariables.put(parameter, variable); } - } - - public void addCapturedVariable(PsiTypeParameter param) { - initBounds(param); + return sameMethodCall; } private void initReturnTypeConstraint(PsiMethod method, final PsiCallExpression context) { - if (PsiPolyExpressionUtil.isMethodCallPolyExpression(context, method) || - context instanceof PsiNewExpression && PsiDiamondType.ourDiamondGuard.currentStack().contains(context)) { + if (PsiPolyExpressionUtil.isMethodCallPolyExpression(context, method)) { PsiType returnType = method.getReturnType(); if (!PsiType.VOID.equals(returnType) && returnType != null) { - returnType = PsiImplUtil.normalizeWildcardTypeByPosition(returnType, context); PsiType targetType = PsiTypesUtil.getExpectedTypeByParent(context); if (targetType == null) { - targetType = PsiResolveHelper.ourGraphGuard.doPreventingRecursion(context, false, new Computable<PsiType>() { - @Override - public PsiType compute() { - return getTargetType(context); - } - }); + targetType = getTargetType(context); } if (targetType != null) { - registerConstraints(returnType, targetType); + registerConstraints(PsiUtil.isRawSubstitutor(method, mySiteSubstitutor) ? returnType : mySiteSubstitutor.substitute(returnType), targetType); } } } @@ -397,7 +385,7 @@ public class InferenceSession { public void registerConstraints(PsiType returnType, PsiType targetType) { final InferenceVariable inferenceVariable = shouldResolveAndInstantiate(returnType, targetType); if (inferenceVariable != null) { - final PsiSubstitutor substitutor = resolveSubset(Collections.singletonList(inferenceVariable), mySiteSubstitutor, true); + final PsiSubstitutor substitutor = resolveSubset(Collections.singletonList(inferenceVariable), mySiteSubstitutor); myConstraints.add(new TypeCompatibilityConstraint(targetType, PsiUtil.captureToplevelWildcards(substitutor.substitute(inferenceVariable.getParameter()), myContext))); } else { @@ -412,7 +400,7 @@ public class InferenceSession { PsiTypeParameter[] copy = new PsiTypeParameter[typeParameters.length]; for (int i = 0; i < typeParameters.length; i++) { PsiTypeParameter typeParameter = typeParameters[i]; - copy[i] = elementFactory.createTypeParameterFromText(typeParameter.getName(), null); + copy[i] = elementFactory.createTypeParameterFromText("rCopy" + typeParameter.getName(), null); initBounds(copy[i]); subst = subst.put(typeParameter, elementFactory.createType(copy[i])); } @@ -495,7 +483,7 @@ public class InferenceSession { return false; } - private PsiType getTargetType(final PsiExpression context) { + private static PsiType getTargetType(final PsiExpression context) { final PsiElement parent = PsiUtil.skipParenthesizedExprUp(context.getParent()); if (parent instanceof PsiExpressionList) { PsiElement gParent = parent.getParent(); @@ -505,28 +493,8 @@ public class InferenceSession { if (gParent instanceof PsiCallExpression) { final PsiExpressionList argumentList = ((PsiCallExpression)gParent).getArgumentList(); if (argumentList != null) { - final Pair<PsiMethod, PsiSubstitutor> pair = MethodCandidateInfo.getCurrentMethod(argumentList); - final PsiFile placeFile = context.getContainingFile(); - final JavaMethodsConflictResolver conflictResolver = new JavaMethodsConflictResolver(argumentList, PsiUtil.getLanguageLevel(placeFile)){ - @Override - protected PsiType[] getArgumentTypes() { - return InferenceSession.getArgumentTypes(argumentList, context); - } - }; - final MethodCandidatesProcessor processor = new MethodResolverProcessor((PsiCallExpression)gParent, placeFile, new PsiConflictResolver[]{conflictResolver}) { - @Override - protected PsiType[] getExpressionTypes(PsiExpressionList argumentList) { - return getArgumentTypes(argumentList, context); - } - }; - try { - PsiScopesUtil.setupAndRunProcessor(processor, (PsiCallExpression)gParent, false); - } - catch (MethodProcessorSetupFailedException e) { - return null; - } - final JavaResolveResult[] results = processor.getResult(); - return results.length == 1 ? getTypeByMethod(context, argumentList, pair, results[0], results[0].getElement()) : null; + final JavaResolveResult result = ((PsiCallExpression)gParent).resolveMethodGenerics(); + return getTypeByMethod(context, argumentList, result, result.getElement()); } } } else if (parent instanceof PsiConditionalExpression) { @@ -546,30 +514,9 @@ public class InferenceSession { return null; } - private static PsiType[] getArgumentTypes(PsiExpressionList argumentList, PsiExpression context) { - if (argumentList != null) { - final PsiExpression[] expressions = argumentList.getExpressions(); - final int idx = LambdaUtil.getLambdaIdx(argumentList, context); - final PsiType[] types = PsiType.createArray(expressions.length); - for (int i = 0; i < expressions.length; i++) { - if (i != idx) { - types[i] = expressions[i].getType(); - } - else { - types[i] = PsiType.NULL; - } - } - return types; - } - else { - return null; - } - } - - private PsiType getTypeByMethod(PsiExpression context, - PsiExpressionList argumentList, - Pair<PsiMethod, PsiSubstitutor> pair, - JavaResolveResult result, PsiElement parentMethod) { + private static PsiType getTypeByMethod(PsiExpression context, + PsiExpressionList argumentList, + final JavaResolveResult result, PsiElement parentMethod) { if (parentMethod instanceof PsiMethod) { final PsiParameter[] parameters = ((PsiMethod)parentMethod).getParameterList().getParameters(); if (parameters.length == 0) return null; @@ -581,23 +528,13 @@ public class InferenceSession { } final int i = ArrayUtilRt.find(args, arg); if (i < 0) return null; - final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(argumentList, PsiCallExpression.class); - if (callExpression != null && callExpression.getTypeArguments().length > 0) { - return getParameterType(parameters, args, i, ((MethodCandidateInfo)result).typeArgumentsSubstitutor()); - } - final PsiType parameterType = getParameterType(parameters, args, i, pair != null ? pair.second : PsiSubstitutor.EMPTY); - args[i] = null; - final PsiTypeParameter[] typeParameters = ((PsiMethod)parentMethod).getTypeParameters(); - final InferenceSession session = new InferenceSession(typeParameters, ((MethodCandidateInfo)result).getSiteSubstitutor(), myManager, argumentList); - session.initExpressionConstraints(parameters, args, argumentList, (PsiMethod)parentMethod); - if (session.tryToInfer(parameters, args, callExpression, (PsiMethod)parentMethod) != null) { - return null; - } - final Collection<PsiTypeParameter> params = session.getTypeParams(); - initBounds(params.toArray(new PsiTypeParameter[params.size()])); - liftBounds(session.getInferenceVariables()); - final PsiSubstitutor substitutor = ((MethodCandidateInfo)result).getSiteSubstitutor(); - return substitutor.substitute(parameterType); + return getParameterType(parameters, args, i, PsiResolveHelper.ourGraphGuard.doPreventingRecursion(argumentList.getParent(), false, + new Computable<PsiSubstitutor>() { + @Override + public PsiSubstitutor compute() { + return result.getSubstitutor(); + } + })); } return null; } @@ -720,7 +657,7 @@ public class InferenceSession { while (!allVars.isEmpty()) { final List<InferenceVariable> vars = InferenceVariablesOrder.resolveOrder(allVars, this); if (!myIncorporationPhase.hasCaptureConstraints(vars)) { - final PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor, true); + final PsiSubstitutor firstSubstitutor = resolveSubset(vars, substitutor); if (firstSubstitutor != null) { substitutor = firstSubstitutor; allVars.removeAll(vars); @@ -731,7 +668,7 @@ public class InferenceSession { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject()); for (InferenceVariable var : vars) { final PsiTypeParameter parameter = var.getParameter(); - final PsiTypeParameter copy = elementFactory.createTypeParameterFromText(parameter.getName(), null); + final PsiTypeParameter copy = elementFactory.createTypeParameterFromText("z" + parameter.getName(), null); final PsiType lub = getLowerBound(var, substitutor); final PsiType glb = getUpperBound(var, substitutor); final InferenceVariable zVariable = new InferenceVariable(copy); @@ -744,6 +681,8 @@ public class InferenceSession { zVariable.addBound(lub, InferenceBound.LOWER); } myInferenceVariables.put(copy, zVariable); + allVars.add(zVariable); + var.addBound(elementFactory.createType(copy), InferenceBound.EQ); } myIncorporationPhase.forgetCaptures(vars); if (!myIncorporationPhase.incorporate()) { @@ -762,7 +701,7 @@ public class InferenceSession { }, substitutor); } - private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars, PsiSubstitutor substitutor, boolean checkResult) { + private PsiSubstitutor resolveSubset(Collection<InferenceVariable> vars, PsiSubstitutor substitutor) { for (InferenceVariable var : vars) { LOG.assertTrue(var.getInstantiation() == PsiType.NULL); final PsiTypeParameter typeParameter = var.getParameter(); @@ -781,7 +720,7 @@ public class InferenceSession { } } - return checkResult ? myIncorporationPhase.checkIncorporated(substitutor, vars) : substitutor; + return substitutor; } private PsiType getUpperBound(InferenceVariable var, PsiSubstitutor substitutor) { @@ -872,7 +811,7 @@ public class InferenceSession { } //resolve input variables - PsiSubstitutor substitutor = resolveSubset(varsToResolve, mySiteSubstitutor, true); + PsiSubstitutor substitutor = resolveSubset(varsToResolve, mySiteSubstitutor); if (substitutor == null) { return false; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java index a67b64eea669..a629175b9d48 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/CheckedExceptionCompatibilityConstraint.java @@ -48,17 +48,6 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai if (!PsiPolyExpressionUtil.isPolyExpression(myExpression)) { return true; } - if (myExpression instanceof PsiCallExpression) { - final PsiExpressionList argumentList = ((PsiCallExpression)myExpression).getArgumentList(); - if (argumentList != null) { - for (PsiExpression expression : argumentList.getExpressions()) { - if (PsiPolyExpressionUtil.isPolyExpression(expression)) { - //todo additional constraints [JDK-8033488] - } - } - } - return true; - } if (myExpression instanceof PsiParenthesizedExpression) { constraints.add(new CheckedExceptionCompatibilityConstraint(((PsiParenthesizedExpression)myExpression).getExpression(), myT)); return true; @@ -122,7 +111,7 @@ public class CheckedExceptionCompatibilityConstraint extends InputOutputConstrai final PsiSubstitutor psiSubstitutor = qualifierResolveResult.getSubstitutor(); final PsiMethod method; if (((PsiMethodReferenceExpression)myExpression).isExact()) { - final PsiElement resolve = ((PsiMethodReferenceExpression)myExpression).resolve(); + final PsiElement resolve = ((PsiMethodReferenceExpression)myExpression).getPotentiallyApplicableMember(); if (resolve instanceof PsiMethod) { method = (PsiMethod)resolve; } else { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java index 30628e36beb6..ebcbda6a2926 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/ExpressionCompatibilityConstraint.java @@ -21,10 +21,13 @@ import com.intellij.psi.impl.source.resolve.graphInference.InferenceVariable; import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; import com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl; import com.intellij.psi.infos.MethodCandidateInfo; +import com.intellij.psi.util.PsiUtil; import com.intellij.psi.util.TypeConversionUtil; +import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; import java.util.Collection; +import java.util.Iterator; import java.util.List; import java.util.Set; @@ -99,22 +102,51 @@ public class ExpressionCompatibilityConstraint extends InputOutputConstraintForm if (typeParams != null) { - for (PsiTypeParameter typeParam : typeParams) { - session.addCapturedVariable(typeParam); - } + final HashSet<PsiTypeParameter> oldBounds = new HashSet<PsiTypeParameter>(session.getTypeParams()); + final boolean sameMethodCall = session.initBounds(typeParams); PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; + final HashSet<InferenceVariable> variables = new HashSet<InferenceVariable>(); + session.collectDependencies(returnType, variables); + final PsiTypeParameter[] params = new PsiTypeParameter[typeParams.length]; + for (int i = 0; i < typeParams.length; i++) { + if (variables.contains(session.getInferenceVariable(typeParams[i]))) { + params[i] = JavaPsiFacade.getElementFactory(myExpression.getProject()).createTypeParameterFromText("copyOf" + myExpression.hashCode() + typeParams[i].getName(), null); + substitutor = substitutor.put(typeParams[i], JavaPsiFacade.getElementFactory(myExpression.getProject()).createType(params[i])); + } + else { + params[i] = typeParams[i]; + } + } + final PsiSubstitutor siteSubstitutor = resolveResult instanceof MethodCandidateInfo && method != null && !method.isConstructor() + ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() : PsiSubstitutor.EMPTY; + for (PsiTypeParameter typeParameter : siteSubstitutor.getSubstitutionMap().keySet()) { + substitutor = substitutor.put(typeParameter, substitutor.substitute(siteSubstitutor.substitute(typeParameter))); + } + + final Collection<PsiTypeParameter> params1 = session.getTypeParams(); + final InferenceSession callSession = new InferenceSession(params1.toArray(new PsiTypeParameter[params1.size()]), substitutor, myExpression.getManager(), myExpression); + callSession.initBounds(params); if (method != null) { - //typeParams are already included - final Collection<PsiTypeParameter> params = session.getTypeParams(); - InferenceSession callSession = new InferenceSession(params.toArray(new PsiTypeParameter[params.size()]), resolveResult instanceof MethodCandidateInfo ? ((MethodCandidateInfo)resolveResult).getSiteSubstitutor() - : PsiSubstitutor.EMPTY, myExpression.getManager(), myExpression); final PsiExpression[] args = argumentList.getExpressions(); final PsiParameter[] parameters = method.getParameterList().getParameters(); callSession.initExpressionConstraints(parameters, args, myExpression, method); - callSession.registerConstraints(returnType, myT); - if (callSession.repeatInferencePhases(true)) { - session.liftBounds(callSession.getInferenceVariables()); + } + final boolean accepted = callSession.repeatInferencePhases(true); + if (!accepted) { + //todo return false; + } + callSession.registerConstraints(method != null && !PsiUtil.isRawSubstitutor(method, siteSubstitutor) ? siteSubstitutor.substitute(returnType) : returnType, substitutor.substitute(returnType)); + if (callSession.repeatInferencePhases(true)) { + final Collection<InferenceVariable> inferenceVariables = callSession.getInferenceVariables(); + if (sameMethodCall) { + for (Iterator<InferenceVariable> iterator = inferenceVariables.iterator(); iterator.hasNext(); ) { + InferenceVariable variable = iterator.next(); + if (oldBounds.contains(variable.getParameter())) { + iterator.remove(); + } + } } + session.liftBounds(inferenceVariables); } final PsiType capturedReturnType = myExpression instanceof PsiMethodCallExpression ? PsiMethodCallExpressionImpl.captureReturnType((PsiMethodCallExpression)myExpression, method, returnType, substitutor) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java index 7e2443a8232f..cbb1db809c4a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/TypeEqualityConstraint.java @@ -109,6 +109,11 @@ public class TypeEqualityConstraint implements ConstraintFormula { return true; } + if (myT instanceof PsiCapturedWildcardType && myS instanceof PsiCapturedWildcardType) { + return new TypeEqualityConstraint(((PsiCapturedWildcardType)myT).getWildcard(), + ((PsiCapturedWildcardType)myS).getWildcard()).reduce(session, constraints); + } + return false; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java index 58c29706c1a3..18ff2d110ad9 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaSharedImplUtil.java @@ -25,7 +25,6 @@ import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiUtil; import com.intellij.util.CharTable; import com.intellij.util.IncorrectOperationException; -import com.intellij.util.SmartList; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -55,18 +54,19 @@ public class JavaSharedImplUtil { return type; } + // collects annotations bound to C-style arrays private static List<PsiAnnotation[]> collectAnnotations(PsiElement anchor, PsiAnnotation stopAt) { - List<PsiAnnotation[]> annotations = new SmartList<PsiAnnotation[]>(); + List<PsiAnnotation[]> annotations = ContainerUtil.newSmartList(); List<PsiAnnotation> current = null; - boolean stop = false; + boolean found = (stopAt == null), stop = false; for (PsiElement child = anchor.getNextSibling(); child != null; child = child.getNextSibling()) { if (child instanceof PsiComment || child instanceof PsiWhiteSpace) continue; if (child instanceof PsiAnnotation) { - if (current == null) current = new SmartList<PsiAnnotation>(); + if (current == null) current = ContainerUtil.newSmartList(); current.add((PsiAnnotation)child); - if (child == stopAt) stop = true; + if (child == stopAt) found = stop = true; continue; } @@ -80,8 +80,8 @@ public class JavaSharedImplUtil { } } - // stop == true means annotation is misplaced - return stop ? null : annotations; + // annotation is misplaced (either located before the anchor or has no following brackets) + return !found || stop ? null : annotations; } public static void normalizeBrackets(@NotNull PsiVariable variable) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaTreeGenerator.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaTreeGenerator.java index f6ba9fdf5af4..918d7fed7237 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaTreeGenerator.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/JavaTreeGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2013 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -131,7 +131,7 @@ public class JavaTreeGenerator implements TreeGenerator { type = PsiType.getJavaLangObject(manager, GlobalSearchScope.projectScope(manager.getProject())); } - String text = type.getPresentableText(); + String text = type.getCanonicalText(true); PsiJavaParserFacade parserFacade = JavaPsiFacade.getInstance(original.getProject()).getParserFacade(); PsiTypeElement element = parserFacade.createTypeElementFromText(text, original); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ExpressionPsiElement.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ExpressionPsiElement.java index cf40d04ca427..1d8693efc55c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ExpressionPsiElement.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/ExpressionPsiElement.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2014 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. @@ -38,7 +38,8 @@ public class ExpressionPsiElement extends CompositePsiElement { @Override public void replaceChildInternal(@NotNull ASTNode child, @NotNull TreeElement newElement) { - if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType())) { + if (ElementType.EXPRESSION_BIT_SET.contains(child.getElementType()) && + ElementType.EXPRESSION_BIT_SET.contains(newElement.getElementType())) { boolean needParenth = ReplaceExpressionUtil.isNeedParenthesis(child, newElement); if (needParenth) { newElement = SourceUtil.addParenthToReplacedChild(JavaElementType.PARENTH_EXPRESSION, newElement, getManager()); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java index fdd02e86ebb3..084be88d7428 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiMethodReferenceExpressionImpl.java @@ -499,6 +499,7 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase final PsiClass pClass = pResult.getElement(); final PsiSubstitutor receiverSubstitutor = pClass != null ? TypeConversionUtil.getClassSubstitutor(containingClass, pClass, pResult.getSubstitutor()) : null; if (receiverSubstitutor != null) { + if (!method.hasTypeParameters() && signature.getParameterTypes().length == 1) return receiverSubstitutor; psiSubstitutor = receiverSubstitutor; } } @@ -638,20 +639,26 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase } } - checkSpecifics(firstCandidates, - varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel); - - checkSpecifics(secondCandidates, - varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel); - if (myQualifierResolveResult.isReferenceTypeQualified() && getReferenceNameElement() instanceof PsiIdentifier) { //If the first search produces a static method, and no non-static method is applicable for the second search, then the result of the first search is the compile-time declaration. - filterStaticCorrectCandidates(firstCandidates, true); + CandidateInfo candidateInfo = filterStaticCorrectCandidates(firstCandidates, secondCandidates, true); + if (candidateInfo != null) { + return candidateInfo; + } //If the second search produces a non-static method, and no static method is applicable for the first search, then the result of the second search is the compile-time declaration. - filterStaticCorrectCandidates(secondCandidates, false); + candidateInfo = filterStaticCorrectCandidates(secondCandidates, firstCandidates, false); + if (candidateInfo != null) { + return candidateInfo; + } } + checkSpecifics(firstCandidates, + varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel); + + checkSpecifics(secondCandidates, + varargs ? MethodCandidateInfo.ApplicabilityLevel.VARARGS : MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY, myLanguageLevel); + final int acceptedCount = firstCandidates.size() + secondCandidates.size(); if (acceptedCount == 1) { return !firstCandidates.isEmpty() ? firstCandidates.get(0) : secondCandidates.get(0); @@ -684,17 +691,29 @@ public class PsiMethodReferenceExpressionImpl extends PsiReferenceExpressionBase /** * 15.13.1 */ - private void filterStaticCorrectCandidates(List<CandidateInfo> firstCandidates, + private CandidateInfo filterStaticCorrectCandidates(List<CandidateInfo> firstCandidates, + List<CandidateInfo> secondCandidates, boolean shouldBeStatic) { - for (Iterator<CandidateInfo> iterator = firstCandidates.iterator(); iterator.hasNext(); ) { - final PsiElement element = iterator.next().getElement(); + if (firstCandidates.size() == 1) { + final CandidateInfo candidateInfo = firstCandidates.get(0); + final PsiElement element = candidateInfo.getElement(); if (element instanceof PsiMethod) { final boolean isStatic = ((PsiMethod)element).hasModifierProperty(PsiModifier.STATIC); - if (shouldBeStatic && !isStatic || !shouldBeStatic && isStatic) { - iterator.remove(); + if (shouldBeStatic && isStatic || !shouldBeStatic && !isStatic) { + for (CandidateInfo secondCandidate : secondCandidates) { + final PsiElement psiElement = secondCandidate.getElement(); + if (psiElement instanceof PsiMethod) { + final boolean oppositeStatic = ((PsiMethod)psiElement).hasModifierProperty(PsiModifier.STATIC); + if (shouldBeStatic && !oppositeStatic || !shouldBeStatic && oppositeStatic) { + return null; + } + } + } + return candidateInfo; } } } + return null; } private boolean isCorrectAssignment(PsiType[] signatureParameterTypes2, |