diff options
Diffstat (limited to 'java/java-psi-impl/src/com/intellij')
18 files changed, 345 insertions, 163 deletions
diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java index f4154bc4fe1a..9b6c23e79b00 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java @@ -625,6 +625,11 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem } int leftStart = method.getParameterList().getTextRange().getEndOffset(); + int bodyStart = body.getTextRange().getStartOffset(); + if (bodyStart > leftStart && !StringUtil.isEmptyOrSpaces(document.getCharsSequence().subSequence(leftStart + 1, bodyStart))) { + return false; + } + int leftEnd = statement.getTextRange().getStartOffset(); int rightStart = statement.getTextRange().getEndOffset(); int rightEnd = body.getTextRange().getEndOffset(); diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java index 1f642b18d1b1..67b1ef813de8 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/javadoc/JavaDocInfoGenerator.java @@ -501,6 +501,7 @@ public class JavaDocInfoGenerator { buffer.append("<b>"); buffer.append(field.getName()); appendInitializer(buffer, field); + enumConstantOrdinal(buffer, field, field.getContainingClass(), "\n"); buffer.append("</b>"); } @@ -638,7 +639,7 @@ public class JavaDocInfoGenerator { String text = o.toString(); PsiType type = variable.getType(); if (type.equalsToText(CommonClassNames.JAVA_LANG_STRING)) { - text = "\"" + StringUtil.shortenPathWithEllipsis(text, 120) + "\""; + text = "\"" + StringUtil.escapeLineBreak(StringUtil.shortenPathWithEllipsis(text, 120)) + "\""; } else if (type.equalsToText("char")) text = "'" + text + "'"; try { @@ -754,7 +755,20 @@ public class JavaDocInfoGenerator { } final PsiAnnotationMemberValue value = pair.getValue(); if (value != null) { - buffer.append(XmlStringUtil.escapeString(value.getText())); + if (value instanceof PsiArrayInitializerMemberValue) { + buffer.append("{"); + boolean firstMember = true; + + for(PsiAnnotationMemberValue memberValue:((PsiArrayInitializerMemberValue)value).getInitializers()) { + if (!firstMember) buffer.append(","); + firstMember = false; + + appendLinkOrText(buffer, memberValue, generateLink); + } + buffer.append("}"); + } else { + appendLinkOrText(buffer, value, generateLink); + } } } buffer.append(")"); @@ -778,6 +792,32 @@ public class JavaDocInfoGenerator { } } + private static void appendLinkOrText(StringBuilder buffer, + PsiAnnotationMemberValue memberValue, + boolean generateLink) { + if (generateLink && memberValue instanceof PsiQualifiedReferenceElement) { + String text = ((PsiQualifiedReferenceElement)memberValue).getCanonicalText(); + PsiElement resolve = ((PsiQualifiedReferenceElement)memberValue).resolve(); + + if (resolve instanceof PsiField) { + PsiField field = (PsiField)resolve; + PsiClass aClass = field.getContainingClass(); + int startOfPropertyNamePosition = text.lastIndexOf('.'); + + if (startOfPropertyNamePosition != -1) { + text = text.substring(0, startOfPropertyNamePosition) + '#' + text.substring(startOfPropertyNamePosition + 1); + } + else { + if (aClass != null) text = aClass.getQualifiedName() + '#' + field.getName(); + } + generateLink(buffer, text, aClass != null? aClass.getName() + '.' + field.getName():null, memberValue, false); + return; + } + } + + buffer.append(XmlStringUtil.escapeString(memberValue.getText())); + } + public static boolean isDocumentedAnnotationType(@Nullable PsiElement annotationType) { return annotationType instanceof PsiClass && AnnotationUtil.isAnnotated((PsiClass)annotationType, "java.lang.annotation.Documented", false); } diff --git a/java/java-psi-impl/src/com/intellij/core/CorePsiPackageImplementationHelper.java b/java/java-psi-impl/src/com/intellij/core/CorePsiPackageImplementationHelper.java index 5a97f596d983..51e010e05d29 100644 --- a/java/java-psi-impl/src/com/intellij/core/CorePsiPackageImplementationHelper.java +++ b/java/java-psi-impl/src/com/intellij/core/CorePsiPackageImplementationHelper.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. @@ -20,6 +20,7 @@ import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiPackage; import com.intellij.psi.impl.file.PsiPackageImplementationHelper; import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; /** * @author yole @@ -27,31 +28,34 @@ import com.intellij.psi.search.GlobalSearchScope; public class CorePsiPackageImplementationHelper extends PsiPackageImplementationHelper { private static final ModificationTracker[] EMPTY_DEPENDENCY = {ModificationTracker.NEVER_CHANGED}; + @NotNull @Override - public GlobalSearchScope adjustAllScope(PsiPackage psiPackage, GlobalSearchScope globalSearchScope) { + public GlobalSearchScope adjustAllScope(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope globalSearchScope) { return globalSearchScope; } + @NotNull @Override - public VirtualFile[] occursInPackagePrefixes(PsiPackage psiPackage) { + public VirtualFile[] occursInPackagePrefixes(@NotNull PsiPackage psiPackage) { return VirtualFile.EMPTY_ARRAY; } @Override - public void handleQualifiedNameChange(PsiPackage psiPackage, String newQualifiedName) { + public void handleQualifiedNameChange(@NotNull PsiPackage psiPackage, @NotNull String newQualifiedName) { } @Override - public void navigate(PsiPackage psiPackage, boolean requestFocus) { + public void navigate(@NotNull PsiPackage psiPackage, boolean requestFocus) { } @Override - public boolean packagePrefixExists(PsiPackage psiPackage) { + public boolean packagePrefixExists(@NotNull PsiPackage psiPackage) { return false; } + @NotNull @Override - public Object[] getDirectoryCachedValueDependencies(PsiPackage cachedValueProvider) { + public Object[] getDirectoryCachedValueDependencies(@NotNull PsiPackage cachedValueProvider) { return EMPTY_DEPENDENCY; } } diff --git a/java/java-psi-impl/src/com/intellij/psi/NonClasspathClassFinder.java b/java/java-psi-impl/src/com/intellij/psi/NonClasspathClassFinder.java index 59a4e10d40fe..7fc4a2245941 100644 --- a/java/java-psi-impl/src/com/intellij/psi/NonClasspathClassFinder.java +++ b/java/java-psi-impl/src/com/intellij/psi/NonClasspathClassFinder.java @@ -248,7 +248,7 @@ public abstract class NonClasspathClassFinder extends PsiElementFinder { } @NotNull - public static GlobalSearchScope addNonClasspathScope(Project project, GlobalSearchScope base) { + public static GlobalSearchScope addNonClasspathScope(@NotNull Project project, @NotNull GlobalSearchScope base) { GlobalSearchScope scope = base; for (PsiElementFinder finder : Extensions.getExtensions(EP_NAME, project)) { if (finder instanceof NonClasspathClassFinder) { 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 9c9525aef859..d53bb2e26820 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 @@ -389,7 +389,7 @@ public class PsiSubstitutorImpl implements PsiSubstitutor { } else { //unbounded - substituted = PsiWildcardType.createExtends(manager, substitutedBoundType); + substituted = substitutedBoundType instanceof PsiCapturedWildcardType ? ((PsiCapturedWildcardType)substitutedBoundType).getWildcard() : PsiWildcardType.createExtends(manager, substitutedBoundType); } } } 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 6ab8174ce28a..20c11a7ccb39 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 @@ -27,8 +27,7 @@ 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; +import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.DefaultProjectFactory; import com.intellij.openapi.roots.FileIndexFacade; import com.intellij.openapi.ui.Queryable; @@ -323,7 +322,7 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub> synchronized (myMirrorLock) { mirrorTreeElement = myMirrorFileElement; if (mirrorTreeElement == null) { - VirtualFile file = getVirtualFile(); + final VirtualFile file = getVirtualFile(); CharSequence mirrorText = ClassFileDecompiler.decompileText(file); String ext = JavaFileType.INSTANCE.getDefaultExtension(); @@ -335,16 +334,18 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub> mirrorTreeElement = SourceTreeToPsiMap.psiToTreeNotNull(mirror); // IMPORTANT: do not take lock too early - FileDocumentManager.saveToString() can run write action - NonCancelableSection section = ProgressIndicatorProvider.startNonCancelableSectionIfSupported(); - try { - setMirror(mirrorTreeElement); - } - catch (InvalidMirrorException e) { - LOG.error(file.getPath(), wrapException(e, file)); - } - finally { - section.done(); - } + final TreeElement finalMirrorTreeElement = mirrorTreeElement; + ProgressManager.getInstance().executeNonCancelableSection(new Runnable() { + @Override + public void run() { + try { + setMirror(finalMirrorTreeElement); + } + catch (InvalidMirrorException e) { + LOG.error(file.getPath(), wrapException(e, file)); + } + } + }); myMirrorFileElement = mirrorTreeElement; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java index 9129052bf74f..93fd1ebbd935 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImpl.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 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. @@ -23,6 +23,7 @@ import com.intellij.navigation.ItemPresentationProviders; import com.intellij.openapi.project.DumbService; import com.intellij.openapi.ui.Queryable; import com.intellij.openapi.util.Condition; +import com.intellij.openapi.util.Conditions; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.JavaPsiFacadeImpl; @@ -46,7 +47,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Queryable { - public static boolean DEBUG = false; private volatile CachedValue<PsiModifierList> myAnnotationList; private volatile CachedValue<Collection<PsiDirectory>> myDirectories; private volatile CachedValue<Collection<PsiDirectory>> myDirectoriesWithLibSources; @@ -72,6 +72,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya } } + @NotNull private CachedValue<Collection<PsiDirectory>> createCachedDirectories(final boolean includeLibrarySources) { return CachedValuesManager.getManager(myManager.getProject()).createCachedValue(new CachedValueProvider<Collection<PsiDirectory>>() { @Override @@ -131,6 +132,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya } } + @Override public String toString() { return "PsiPackage:" + getQualifiedName(); } @@ -141,6 +143,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya return getClasses(allScope()); } + @NotNull protected GlobalSearchScope allScope() { return PsiPackageImplementationHelper.getInstance().adjustAllScope(this, GlobalSearchScope.allScope(getProject())); } @@ -177,7 +180,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya } @NotNull - private PsiClass[] getCachedClassesByName(String name) { + private PsiClass[] getCachedClassesByName(@NotNull String name) { if (DumbService.getInstance(getProject()).isDumb()) { return getCachedClassInDumbMode(name); } @@ -215,7 +218,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya } @Override - public boolean containsClassNamed(String name) { + public boolean containsClassNamed(@NotNull String name) { return getCachedClassesByName(name).length > 0; } @@ -247,7 +250,7 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya } @Nullable - private PsiPackage findSubPackageByName(String name) { + private PsiPackage findSubPackageByName(@NotNull String name) { final String qName = getQualifiedName(); final String subpackageQName = qName.isEmpty() ? name : qName + "." + name; return getFacade().findPackage(subpackageQName); @@ -270,11 +273,11 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya if (nameHint != null) { final String shortName = nameHint.getName(state); final PsiClass[] classes = findClassByShortName(shortName, scope); - if (!processClasses(processor, state, classes, Condition.TRUE)) return false; + if (!processClasses(processor, state, classes, Conditions.<String>alwaysTrue())) return false; } else { PsiClass[] classes = getClasses(scope); - if (!processClasses(processor, state, classes, nameCondition != null ? nameCondition : Condition.TRUE)) return false; + if (!processClasses(processor, state, classes, nameCondition != null ? nameCondition : Conditions.<String>alwaysTrue())) return false; } } if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.PACKAGE)) { @@ -302,7 +305,9 @@ public class PsiPackageImpl extends PsiPackageBase implements PsiPackage, Querya return true; } - private static boolean processClasses(PsiScopeProcessor processor, ResolveState state, PsiClass[] classes, + private static boolean processClasses(@NotNull PsiScopeProcessor processor, + @NotNull ResolveState state, + @NotNull PsiClass[] classes, @NotNull Condition<String> nameCondition) { for (PsiClass aClass : classes) { String name = aClass.getName(); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelper.java b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelper.java index 050786c617f0..4ca3f1fead43 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelper.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/file/PsiPackageImplementationHelper.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 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. @@ -19,22 +19,26 @@ import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiPackage; import com.intellij.psi.search.GlobalSearchScope; +import org.jetbrains.annotations.NotNull; /** * @author yole */ public abstract class PsiPackageImplementationHelper { - public abstract GlobalSearchScope adjustAllScope(PsiPackage psiPackage, GlobalSearchScope globalSearchScope); + @NotNull + public abstract GlobalSearchScope adjustAllScope(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope globalSearchScope); - public abstract VirtualFile[] occursInPackagePrefixes(PsiPackage psiPackage); + @NotNull + public abstract VirtualFile[] occursInPackagePrefixes(@NotNull PsiPackage psiPackage); - public abstract void handleQualifiedNameChange(PsiPackage psiPackage, String newQualifiedName); + public abstract void handleQualifiedNameChange(@NotNull PsiPackage psiPackage, @NotNull String newQualifiedName); - public abstract void navigate(PsiPackage psiPackage, boolean requestFocus); + public abstract void navigate(@NotNull PsiPackage psiPackage, boolean requestFocus); - public abstract boolean packagePrefixExists(PsiPackage psiPackage); + public abstract boolean packagePrefixExists(@NotNull PsiPackage psiPackage); - public abstract Object[] getDirectoryCachedValueDependencies(PsiPackage cachedValueProvider); + @NotNull + public abstract Object[] getDirectoryCachedValueDependencies(@NotNull PsiPackage cachedValueProvider); public static PsiPackageImplementationHelper getInstance() { return ServiceManager.getService(PsiPackageImplementationHelper.class); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java index 78c5c2d8fdc8..fd38e3ddaf56 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiFieldImpl.java @@ -399,9 +399,14 @@ public class PsiFieldImpl extends JavaStubPsiElement<PsiFieldStub> implements Ps @Override public PsiElement getOriginalElement() { - PsiClass originalClass = (PsiClass)getContainingClass().getOriginalElement(); - PsiField originalField = originalClass.findFieldByName(getName(), false); - return originalField != null ? originalField : this; + PsiClass containingClass = getContainingClass(); + if (containingClass != null) { + PsiField originalField = ((PsiClass)containingClass.getOriginalElement()).findFieldByName(getName(), false); + if (originalField != null) { + return originalField; + } + } + return this; } @Override diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java index e77e7ad01f5e..799f9b459e69 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/PsiParameterImpl.java @@ -324,4 +324,24 @@ public class PsiParameterImpl extends JavaStubPsiElement<PsiParameterStub> imple final PsiElement declarationScope = getDeclarationScope(); return new LocalSearchScope(declarationScope); } + + @Override + public PsiElement getOriginalElement() { + PsiElement parent = getParent(); + if (parent instanceof PsiParameterList) { + PsiElement gParent = parent.getParent(); + if (gParent instanceof PsiMethod) { + PsiElement originalMethod = gParent.getOriginalElement(); + if (originalMethod instanceof PsiMethod) { + int index = ((PsiParameterList)parent).getParameterIndex(this); + PsiParameter[] originalParameters = ((PsiMethod)originalMethod).getParameterList().getParameters(); + if (index < originalParameters.length) { + return originalParameters[index]; + } + } + } + } + return this; + } + } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java index 556bf7152b68..a27dfe5adb83 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/PsiResolveHelperImpl.java @@ -15,7 +15,6 @@ */ package com.intellij.psi.impl.source.resolve; -import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; @@ -211,16 +210,8 @@ public class PsiResolveHelperImpl implements PsiResolveHelper { .getSubstitutionForTypeParameter(typeParam, param, arg, isContraVariantPosition, languageLevel); } - private PsiInferenceHelper myTestHelper; - - public void setTestHelper(PsiInferenceHelper testHelper) { - myTestHelper = testHelper; - } - - public PsiInferenceHelper getInferenceHelper(LanguageLevel languageLevel) { - if (ApplicationManager.getApplication().isUnitTestMode() && myTestHelper != null) { - return myTestHelper; - } + @NotNull + public PsiInferenceHelper getInferenceHelper(@NotNull LanguageLevel languageLevel) { if (languageLevel.isAtLeast(LanguageLevel.JDK_1_8)) { return new PsiGraphInferenceHelper(myManager); } 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 35db6c29bc0c..a1b4570e5361 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 @@ -174,7 +174,6 @@ public class InferenceSession { } } } - return true; } if (expr instanceof PsiLambdaExpression) { if (!((PsiLambdaExpression)expr).hasFormalParameterTypes()) { @@ -234,7 +233,7 @@ public class InferenceSession { !MethodCandidateInfo.ourOverloadGuard.currentStack().contains(PsiUtil.skipParenthesizedExprUp(parent.getParent()))) { final Set<ConstraintFormula> additionalConstraints = new LinkedHashSet<ConstraintFormula>(); if (parameters.length > 0) { - collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs(), true); + collectAdditionalConstraints(parameters, args, properties.getMethod(), PsiSubstitutor.EMPTY, additionalConstraints, properties.isVarargs()); } if (!additionalConstraints.isEmpty() && !proceedWithAdditionalConstraints(additionalConstraints)) { @@ -264,67 +263,113 @@ public class InferenceSession { PsiMethod parentMethod, PsiSubstitutor siteSubstitutor, Set<ConstraintFormula> additionalConstraints, - boolean varargs, boolean toplevel) { + boolean varargs) { for (int i = 0; i < args.length; i++) { - if (args[i] != null) { - InferenceSession session = myNestedSessions.get(PsiTreeUtil.getParentOfType(args[i], PsiCallExpression.class)); - if (session == null) { - session = this; - } - PsiType parameterType = session.substituteWithInferenceVariables(getParameterType(parameters, i, siteSubstitutor, varargs)); - if (!isPertinentToApplicability(args[i], parentMethod)) { - additionalConstraints.add(new ExpressionCompatibilityConstraint(args[i], parameterType)); + final PsiExpression arg = PsiUtil.skipParenthesizedExprDown(args[i]); + if (arg != null) { + final InferenceSession nestedCallSession = findNestedCallSession(arg); + final PsiType parameterType = + nestedCallSession.substituteWithInferenceVariables(getParameterType(parameters, i, siteSubstitutor, varargs)); + if (!isPertinentToApplicability(arg, parentMethod)) { + additionalConstraints.add(new ExpressionCompatibilityConstraint(arg, parameterType)); } - additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(args[i], parameterType)); - if (args[i] instanceof PsiCallExpression && PsiPolyExpressionUtil.isPolyExpression(args[i])) { + additionalConstraints.add(new CheckedExceptionCompatibilityConstraint(arg, parameterType)); + if (arg instanceof PsiCallExpression) { //If the expression is a poly class instance creation expression (15.9) or a poly method invocation expression (15.12), //the set contains all constraint formulas that would appear in the set C when determining the poly expression's invocation type. - final PsiCallExpression callExpression = (PsiCallExpression)args[i]; - collectAdditionalConstraints(additionalConstraints, callExpression); - } else if (args[i] instanceof PsiLambdaExpression && toplevel) { - final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType); - if (interfaceReturnType != null) { - final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)args[i]); - for (PsiExpression returnExpression : returnExpressions) { - if (returnExpression instanceof PsiCallExpression) { - final PsiCallExpression callExpression = (PsiCallExpression)returnExpression; - collectAdditionalConstraints(additionalConstraints, callExpression); - } - } + final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)arg); + if (PsiPolyExpressionUtil.isMethodCallPolyExpression(arg, calledMethod)) { + collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)arg); } + } else if (arg instanceof PsiLambdaExpression) { + collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)arg, parameterType); } } } } + private static PsiMethod getCalledMethod(PsiCallExpression arg) { + final PsiExpressionList argumentList = arg.getArgumentList(); + if (argumentList == null || argumentList.getExpressions().length == 0) { + return null; + } + + MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList); + if (properties != null) { + return properties.getMethod(); + } + final JavaResolveResult resolveResult = getMethodResult(arg); + return resolveResult instanceof MethodCandidateInfo ? (PsiMethod)resolveResult.getElement() : null; + } + + private void collectLambdaReturnExpression(Set<ConstraintFormula> additionalConstraints, + PsiLambdaExpression lambdaExpression, + PsiType parameterType) { + final PsiType interfaceReturnType = LambdaUtil.getFunctionalInterfaceReturnType(parameterType); + if (interfaceReturnType != null) { + final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions(lambdaExpression); + for (PsiExpression returnExpression : returnExpressions) { + processReturnExpression(additionalConstraints, returnExpression, interfaceReturnType); + } + } + } + + private void processReturnExpression(Set<ConstraintFormula> additionalConstraints, + PsiExpression returnExpression, + PsiType functionalType) { + if (returnExpression instanceof PsiCallExpression) { + final PsiMethod calledMethod = getCalledMethod((PsiCallExpression)returnExpression); + if (PsiPolyExpressionUtil.isMethodCallPolyExpression(returnExpression, calledMethod)) { + collectAdditionalConstraints(additionalConstraints, (PsiCallExpression)returnExpression); + } + } + else if (returnExpression instanceof PsiParenthesizedExpression) { + processReturnExpression(additionalConstraints, ((PsiParenthesizedExpression)returnExpression).getExpression(), functionalType); + } + else if (returnExpression instanceof PsiConditionalExpression) { + processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getThenExpression(), functionalType); + processReturnExpression(additionalConstraints, ((PsiConditionalExpression)returnExpression).getElseExpression(), functionalType); + } + else if (returnExpression instanceof PsiLambdaExpression) { + collectLambdaReturnExpression(additionalConstraints, (PsiLambdaExpression)returnExpression, functionalType); + } + } + private void collectAdditionalConstraints(final Set<ConstraintFormula> additionalConstraints, final PsiCallExpression callExpression) { PsiExpressionList argumentList = callExpression.getArgumentList(); if (argumentList != null) { - final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(argumentList, PsiLambdaExpression.class); - final Computable<JavaResolveResult> computableResolve = new Computable<JavaResolveResult>() { - @Override - public JavaResolveResult compute() { - return callExpression.resolveMethodGenerics(); - } - }; + final JavaResolveResult result = getMethodResult(callExpression); MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList); - final JavaResolveResult result = properties != null ? null : - expression == null - ? computableResolve.compute() - : PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve); final PsiMethod method = result instanceof MethodCandidateInfo ? ((MethodCandidateInfo)result).getElement() : properties != null ? properties.getMethod() : null; if (method != null) { final PsiExpression[] newArgs = argumentList.getExpressions(); final PsiParameter[] newParams = method.getParameterList().getParameters(); if (newParams.length > 0) { collectAdditionalConstraints(newParams, newArgs, method, result != null ? ((MethodCandidateInfo)result).getSiteSubstitutor() : properties.getSubstitutor(), - additionalConstraints, result != null ? ((MethodCandidateInfo)result).isVarargs() : properties.isVarargs(), false); + additionalConstraints, result != null ? ((MethodCandidateInfo)result).isVarargs() : properties.isVarargs()); } } } } + private static JavaResolveResult getMethodResult(final PsiCallExpression callExpression) { + final PsiExpressionList argumentList = callExpression.getArgumentList(); + + final PsiLambdaExpression expression = PsiTreeUtil.getParentOfType(argumentList, PsiLambdaExpression.class); + final Computable<JavaResolveResult> computableResolve = new Computable<JavaResolveResult>() { + @Override + public JavaResolveResult compute() { + return callExpression.resolveMethodGenerics(); + } + }; + MethodCandidateInfo.CurrentCandidateProperties properties = MethodCandidateInfo.getCurrentMethod(argumentList); + return properties != null ? null : + expression == null + ? computableResolve.compute() + : PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve); + } + public PsiSubstitutor retrieveNonPrimitiveEqualsBounds(Collection<InferenceVariable> variables) { PsiSubstitutor substitutor = mySiteSubstitutor; for (InferenceVariable variable : variables) { @@ -702,7 +747,7 @@ public class InferenceSession { } final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject()); - final PsiTypeParameter[] freshParameters = createFreshVariables(vars); + final PsiTypeParameter[] freshParameters = createFreshVariables(vars, substitutor); for (int i = 0; i < freshParameters.length; i++) { PsiTypeParameter parameter = freshParameters[i]; final InferenceVariable var = vars.get(i); @@ -725,7 +770,7 @@ public class InferenceSession { return substitutor; } - private PsiTypeParameter[] createFreshVariables(final List<InferenceVariable> vars) { + private PsiTypeParameter[] createFreshVariables(final List<InferenceVariable> vars, final PsiSubstitutor siteSubstitutor) { final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(getManager().getProject()); PsiSubstitutor substitutor = PsiSubstitutor.EMPTY; @@ -742,7 +787,7 @@ public class InferenceSession { final String classText = "class I<" + StringUtil.join(vars, new Function<InferenceVariable, String>() { @Override public String fun(InferenceVariable variable) { - final PsiType glb = composeBound(variable, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor, true); + final PsiType glb = composeBound(variable, InferenceBound.UPPER, UPPER_BOUND_FUNCTION, ySubstitutor.putAll(siteSubstitutor), true); return getFreshVariableName(variable) + " extends " + glb.getInternalCanonicalText(); } }, ", ") + ">{}"; @@ -860,46 +905,67 @@ public class InferenceSession { //extract subset of constraints final Set<ConstraintFormula> subset = buildSubset(additionalConstraints); - //collect all input variables of selection + //collect all input variables of selection final Set<InferenceVariable> varsToResolve = new LinkedHashSet<InferenceVariable>(); for (ConstraintFormula formula : subset) { if (formula instanceof InputOutputConstraintFormula) { - final Set<InferenceVariable> inputVariables = ((InputOutputConstraintFormula)formula).getInputVariables(this); - if (inputVariables != null) { - for (InferenceVariable inputVariable : inputVariables) { - varsToResolve.addAll(inputVariable.getDependencies(this)); - } - varsToResolve.addAll(inputVariables); - } + collectVarsToResolve(varsToResolve, (InputOutputConstraintFormula)formula); } } - //resolve input variables - PsiSubstitutor substitutor = resolveSubset(varsToResolve, siteSubstitutor); - if (substitutor == null) { - return false; + for (ConstraintFormula formula : subset) { + if (!processOneConstraint(formula, siteSubstitutor, varsToResolve)) return false; } + } + return true; + } - if (myContext instanceof PsiCallExpression) { - PsiExpressionList argumentList = ((PsiCallExpression)myContext).getArgumentList(); - LOG.assertTrue(argumentList != null); - MethodCandidateInfo.updateSubstitutor(argumentList, substitutor); + private void collectVarsToResolve(Set<InferenceVariable> varsToResolve, InputOutputConstraintFormula formula) { + final Set<InferenceVariable> inputVariables = formula.getInputVariables(this); + if (inputVariables != null) { + for (InferenceVariable inputVariable : inputVariables) { + varsToResolve.addAll(inputVariable.getDependencies(this)); } + varsToResolve.addAll(inputVariables); + } + } - try { - for (ConstraintFormula additionalConstraint : subset) { - additionalConstraint.apply(substitutor, true); - } - - myConstraints.addAll(subset); - if (!repeatInferencePhases(true)) { - return false; + private boolean processOneConstraint(ConstraintFormula formula, PsiSubstitutor siteSubstitutor, Set<InferenceVariable> varsToResolve) { + if (formula instanceof ExpressionCompatibilityConstraint) { + final PsiExpression expression = ((ExpressionCompatibilityConstraint)formula).getExpression(); + final PsiCallExpression callExpression = PsiTreeUtil.getParentOfType(expression, PsiCallExpression.class, false); + if (callExpression != null) { + final InferenceSession session = myNestedSessions.get(callExpression); + if (session != null) { + formula.apply(session.myInferenceSubstitution, true); + collectVarsToResolve(varsToResolve, (InputOutputConstraintFormula)formula); } } - finally { - LambdaUtil.ourFunctionTypes.set(null); + } + + //resolve input variables + PsiSubstitutor substitutor = resolveSubset(varsToResolve, siteSubstitutor); + if (substitutor == null) { + return false; + } + + if (myContext instanceof PsiCallExpression) { + PsiExpressionList argumentList = ((PsiCallExpression)myContext).getArgumentList(); + LOG.assertTrue(argumentList != null); + MethodCandidateInfo.updateSubstitutor(argumentList, substitutor); + } + + try { + formula.apply(substitutor, true); + + myConstraints.add(formula); + if (!repeatInferencePhases(true)) { + return false; } } + finally { + LambdaUtil.ourFunctionTypes.set(null); + } return true; } @@ -1139,9 +1205,6 @@ public class InferenceSession { } final List<PsiExpression> returnExpressions = LambdaUtil.getReturnExpressions((PsiLambdaExpression)arg); - if (sReturnType == PsiType.VOID) { - return returnExpressions.isEmpty() && session == null; - } if (LambdaUtil.isFunctionalType(sReturnType) && LambdaUtil.isFunctionalType(tReturnType) && !TypeConversionUtil.isAssignable(TypeConversionUtil.erasure(sReturnType), TypeConversionUtil.erasure(tReturnType)) && @@ -1197,10 +1260,6 @@ public class InferenceSession { return true; } - if (sReturnType == PsiType.VOID && session != null) { - return false; - } - final boolean sPrimitive = sReturnType instanceof PsiPrimitiveType && sReturnType != PsiType.VOID; final boolean tPrimitive = tReturnType instanceof PsiPrimitiveType && tReturnType != PsiType.VOID; @@ -1295,6 +1354,14 @@ public class InferenceSession { return myInferenceSubstitution.substitute(type); } + public InferenceSession findNestedCallSession(PsiExpression arg) { + InferenceSession session = myNestedSessions.get(PsiTreeUtil.getParentOfType(arg, PsiCallExpression.class)); + if (session == null) { + session = this; + } + return session; + } + public PsiType startWithFreshVars(PsiType type) { PsiSubstitutor s = PsiSubstitutor.EMPTY; for (InferenceVariable variable : myInferenceVariables) { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java index 8d91b620f798..da7b4b78930a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/InferenceVariable.java @@ -17,6 +17,7 @@ package com.intellij.psi.impl.source.resolve.graphInference; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightTypeParameter; +import com.intellij.psi.util.PsiUtil; import java.util.*; @@ -49,6 +50,10 @@ public class InferenceVariable extends LightTypeParameter { } public boolean addBound(PsiType classType, InferenceBound inferenceBound) { + if (inferenceBound == InferenceBound.EQ && + PsiUtil.resolveClassInClassTypeOnly(classType) == this) { + return false; + } List<PsiType> list = myBounds.get(inferenceBound); if (list == null) { list = new ArrayList<PsiType>(); @@ -77,20 +82,18 @@ public class InferenceVariable extends LightTypeParameter { } } + if (!session.hasCapture(this) && dependencies.isEmpty()) { + return dependencies; + } + next: for (InferenceVariable variable : session.getInferenceVariables()) { if (!dependencies.contains(variable) && variable != this) { - nextBound: - for (List<PsiType> bounds : myBounds.values()) { //todo + for (List<PsiType> bounds : variable.myBounds.values()) { //todo if (bounds != null) { for (PsiType bound : bounds) { - final Set<InferenceVariable> deps = new HashSet<InferenceVariable>(); - session.collectDependencies(bound, deps); - if (deps.isEmpty()) { - continue nextBound; - } - - if (deps.contains(this)) { + final InferenceVariable inferenceVariable = session.getInferenceVariable(bound); + if (inferenceVariable == this) { dependencies.add(variable); continue next; } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java index c282481e79c0..f7e9badfa33c 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/LambdaExpressionCompatibilityConstraint.java @@ -3,6 +3,7 @@ package com.intellij.psi.impl.source.resolve.graphInference.constraints; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.graphInference.FunctionalInterfaceParameterizationUtil; import com.intellij.psi.impl.source.resolve.graphInference.InferenceSession; +import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; import java.util.List; @@ -62,8 +63,9 @@ public class LambdaExpressionCompatibilityConstraint implements ConstraintFormul if (returnExpressions.isEmpty() && !myExpression.isValueCompatible()) { //not value-compatible return false; } - returnType = session.substituteWithInferenceVariables(substitutor.substitute(returnType)); - if (!session.isProperType(returnType)) { + InferenceSession callsession = session.findNestedCallSession(myExpression); + returnType = callsession.substituteWithInferenceVariables(substitutor.substitute(returnType)); + if (!callsession.isProperType(returnType)) { for (PsiExpression returnExpression : returnExpressions) { constraints.add(new ExpressionCompatibilityConstraint(returnExpression, returnType)); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java index fbfd8195fc11..b5e4188e1644 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/PsiMethodReferenceCompatibilityConstraint.java @@ -169,11 +169,11 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm } LOG.assertTrue(referencedMethodReturnType != null, method); - session.initBounds(method.getTypeParameters()); + session.initBounds(myExpression, method.getTypeParameters()); if (!PsiTreeUtil.isContextAncestor(containingClass, myExpression, false) || PsiUtil.getEnclosingStaticElement(myExpression, containingClass) != null) { - session.initBounds(containingClass.getTypeParameters()); + session.initBounds(myExpression, containingClass.getTypeParameters()); } //if i) the method reference elides NonWildTypeArguments, @@ -243,7 +243,7 @@ public class PsiMethodReferenceCompatibilityConstraint implements ConstraintForm final PsiClass qualifierClass = PsiUtil.resolveClassInType(qualifierType); if (qualifierClass != null) { - session.initBounds(qualifierClass.getTypeParameters()); + session.initBounds(myExpression, qualifierClass.getTypeParameters()); constraints.add(new StrictSubtypingConstraint(session.substituteWithInferenceVariables(qualifierType), session.substituteWithInferenceVariables(substitutor.substitute(targetParameters[0].getType())))); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java index 412b09eadec3..6b3c104aab35 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/resolve/graphInference/constraints/StrictSubtypingConstraint.java @@ -92,8 +92,22 @@ public class StrictSubtypingConstraint implements ConstraintFormula { return false; } - if (!(myS instanceof PsiClassType)) return false; - PsiClassType.ClassResolveResult SResult = ((PsiClassType)myS).resolveGenerics(); + PsiClassType.ClassResolveResult SResult = null; + if (myS instanceof PsiIntersectionType) { + for (PsiType conjunct : ((PsiIntersectionType)myS).getConjuncts()) { + if (conjunct instanceof PsiClassType) { + final PsiClassType.ClassResolveResult conjunctResult = ((PsiClassType)conjunct).resolveGenerics(); + if (InheritanceUtil.isInheritorOrSelf(conjunctResult.getElement(), CClass, true)) { + SResult = conjunctResult; + break; + } + } + } + } else if (myS instanceof PsiClassType) { + SResult = ((PsiClassType)myS).resolveGenerics(); + } + + if (SResult == null) return false; PsiClass SClass = SResult.getElement(); if (((PsiClassType)myT).isRaw()) { return SClass != null && InheritanceUtil.isInheritorOrSelf(SClass, CClass, true); diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java index 069f667d92cf..9d35ace98cf4 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/source/tree/java/PsiLambdaExpressionImpl.java @@ -30,7 +30,6 @@ import com.intellij.psi.scope.PsiScopeProcessor; import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiUtil; -import com.intellij.util.containers.IntArrayList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -78,16 +77,11 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi @Override public boolean isVoidCompatible() { final PsiElement body = getBody(); - if (body != null) { - try { - ControlFlow controlFlow = ControlFlowFactory.getInstance(getProject()).getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy - .getInstance()); - int startOffset = controlFlow.getStartOffset(body); - int endOffset = controlFlow.getEndOffset(body); - return startOffset != -1 && endOffset != -1 && !ControlFlowUtil.canCompleteNormally(controlFlow, startOffset, endOffset); - } - catch (AnalysisCanceledException e) { - return true; + if (body instanceof PsiCodeBlock) { + for (PsiReturnStatement statement : PsiUtil.findReturnStatements((PsiCodeBlock)body)) { + if (statement.getReturnValue() != null) { + return false; + } } } return true; @@ -96,18 +90,25 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi @Override public boolean isValueCompatible() { final PsiElement body = getBody(); - if (body != null) { + if (body instanceof PsiCodeBlock) { try { - final ControlFlow controlFlow = - ControlFlowFactory.getInstance(getProject()).getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy.getInstance(), false); - if (ControlFlowUtil.findExitPointsAndStatements(controlFlow, 0, controlFlow.getSize(), new IntArrayList(), - PsiReturnStatement.class, - PsiThrowStatement.class).isEmpty()) { + ControlFlow controlFlow = + ControlFlowFactory.getInstance(getProject()).getControlFlow(body, LocalsOrMyInstanceFieldsControlFlowPolicy + .getInstance()); + int startOffset = controlFlow.getStartOffset(body); + int endOffset = controlFlow.getEndOffset(body); + if (startOffset != -1 && endOffset != -1 && ControlFlowUtil.canCompleteNormally(controlFlow, startOffset, endOffset)) { return false; } } catch (AnalysisCanceledException e) { - return true; + return false; + } + + for (PsiReturnStatement statement : PsiUtil.findReturnStatements((PsiCodeBlock)body)) { + if (statement.getReturnValue() == null) { + return false; + } } } return true; @@ -200,17 +201,36 @@ public class PsiLambdaExpressionImpl extends ExpressionPsiElement implements Psi } } + + //A lambda expression (§15.27) is potentially compatible with a functional interface type (§9.8) if all of the following are true: + // The arity of the target type's function type is the same as the arity of the lambda expression. + // If the target type's function type has a void return, then the lambda body is either a statement expression (§14.8) or a void-compatible block (§15.27.2). + // If the target type's function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (§15.27.2). + PsiType methodReturnType = interfaceMethod.getReturnType(); if (checkReturnType) { final String uniqueVarName = JavaCodeStyleManager.getInstance(getProject()).suggestUniqueVariableName("l", this, true); final String canonicalText = toArray(leftType).getCanonicalText(); final PsiStatement assignmentFromText = JavaPsiFacade.getElementFactory(getProject()) .createStatementFromText(canonicalText + " " + uniqueVarName + " = " + getText(), this); final PsiLocalVariable localVariable = (PsiLocalVariable)((PsiDeclarationStatement)assignmentFromText).getDeclaredElements()[0]; - PsiType methodReturnType = interfaceMethod.getReturnType(); if (methodReturnType != null) { return LambdaHighlightingUtil.checkReturnTypeCompatible((PsiLambdaExpression)localVariable.getInitializer(), substitutor.substitute(methodReturnType)) == null; } + } else { + final PsiElement body = getBody(); + if (methodReturnType == PsiType.VOID) { + if (body instanceof PsiCodeBlock) { + return isVoidCompatible(); + } else { + return LambdaUtil.isExpressionStatementExpression(body); + } + } else { + if (body instanceof PsiCodeBlock) { + return isValueCompatible(); + } + return body instanceof PsiExpression; + } } return true; } diff --git a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java index 3d9ea08125a8..6bb33be05ea5 100644 --- a/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java +++ b/java/java-psi-impl/src/com/intellij/psi/scope/conflictResolvers/JavaMethodsConflictResolver.java @@ -158,7 +158,8 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ // A lambda expression or a method reference expression is potentially compatible with a type variable if the type variable is a type parameter of the candidate method. final PsiClass paramClass = PsiUtil.resolveClassInType(paramType); if (paramClass instanceof PsiTypeParameter && ((PsiTypeParameter)paramClass).getOwner() == method) continue; - if (!lambdaExpression.isAcceptable(((MethodCandidateInfo)conflict).getSubstitutor(false).substitute(paramType), lambdaExpression.hasFormalParameterTypes())) { + if (!lambdaExpression.isAcceptable(((MethodCandidateInfo)conflict).getSubstitutor(false).substitute(paramType), + InferenceSession.isPertinentToApplicability(lambdaExpression, method))) { iterator.remove(); } } @@ -397,7 +398,7 @@ public class JavaMethodsConflictResolver implements PsiConflictResolver{ } @MethodCandidateInfo.ApplicabilityLevelConstant - protected int checkApplicability(@NotNull List<CandidateInfo> conflicts) { + public int checkApplicability(@NotNull List<CandidateInfo> conflicts) { @MethodCandidateInfo.ApplicabilityLevelConstant int maxApplicabilityLevel = 0; boolean toFilter = false; for (CandidateInfo conflict : conflicts) { |