mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-21 22:11:40 +07:00
cache diamond inference results
This commit is contained in:
@@ -33,8 +33,7 @@ import com.intellij.psi.scope.PsiConflictResolver;
|
||||
import com.intellij.psi.scope.conflictResolvers.JavaMethodsConflictResolver;
|
||||
import com.intellij.psi.scope.processor.MethodCandidatesProcessor;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.*;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
@@ -152,27 +151,31 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
|
||||
if (psiClass == null) return DiamondInferenceResult.NULL_RESULT;
|
||||
final PsiExpressionList argumentList = newExpression.getArgumentList();
|
||||
if (argumentList == null) return DiamondInferenceResult.NULL_RESULT;
|
||||
final Ref<PsiMethod> staticFactoryRef = new Ref<PsiMethod>();
|
||||
final Ref<MethodCandidateInfo> staticFactoryRef = new Ref<MethodCandidateInfo>();
|
||||
final PsiSubstitutor inferredSubstitutor = ourDiamondGuard.doPreventingRecursion(context, false, new Computable<PsiSubstitutor>() {
|
||||
@Override
|
||||
public PsiSubstitutor compute() {
|
||||
final PsiMethod staticFactory = findConstructorStaticFactory(psiClass, newExpression);
|
||||
if (staticFactory == null) {
|
||||
return null;
|
||||
}
|
||||
staticFactoryRef.set(staticFactory);
|
||||
|
||||
return inferTypeParametersForStaticFactory(staticFactory, newExpression, context, false);
|
||||
final MethodCandidateInfo staticFactoryCandidateInfo = CachedValuesManager.getCachedValue(newExpression,
|
||||
new CachedValueProvider<MethodCandidateInfo>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<MethodCandidateInfo> compute() {
|
||||
return new Result<MethodCandidateInfo>(getStaticFactoryCandidateInfo(psiClass, newExpression, context, argumentList), PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
|
||||
}
|
||||
});
|
||||
staticFactoryRef.set(staticFactoryCandidateInfo);
|
||||
return staticFactoryCandidateInfo != null ? staticFactoryCandidateInfo.getSubstitutor() : null;
|
||||
}
|
||||
});
|
||||
if (inferredSubstitutor == null) {
|
||||
return DiamondInferenceResult.NULL_RESULT;
|
||||
}
|
||||
final PsiMethod staticFactory = staticFactoryRef.get();
|
||||
if (staticFactory == null) {
|
||||
final MethodCandidateInfo staticFactoryInfo = staticFactoryRef.get();
|
||||
if (staticFactoryInfo == null) {
|
||||
LOG.error(inferredSubstitutor);
|
||||
return DiamondInferenceResult.NULL_RESULT;
|
||||
}
|
||||
final PsiMethod staticFactory = staticFactoryInfo.getElement();
|
||||
final PsiTypeParameter[] parameters = staticFactory.getTypeParameters();
|
||||
final PsiTypeParameter[] classParameters = psiClass.getTypeParameters();
|
||||
final PsiJavaCodeReferenceElement classOrAnonymousClassReference = newExpression.getClassOrAnonymousClassReference();
|
||||
@@ -200,6 +203,30 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MethodCandidateInfo getStaticFactoryCandidateInfo(PsiClass psiClass,
|
||||
PsiNewExpression newExpression,
|
||||
PsiElement context,
|
||||
PsiExpressionList argumentList) {
|
||||
final PsiMethod staticFactory = findConstructorStaticFactory(psiClass, newExpression);
|
||||
if (staticFactory == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final MethodCandidateInfo staticFactoryCandidateInfo = createMethodCandidate(staticFactory, context, false, argumentList);
|
||||
if (staticFactory.isVarArgs()) {
|
||||
final Computable<Integer> computable = new Computable<Integer>() {
|
||||
@Override
|
||||
public Integer compute() {
|
||||
return staticFactoryCandidateInfo.getPertinentApplicabilityLevel();
|
||||
}
|
||||
};
|
||||
final Integer applicability = MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(newExpression, true, computable);
|
||||
if ((applicability != null ? applicability : staticFactoryCandidateInfo.getApplicabilityLevel()) < MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY) {
|
||||
return createMethodCandidate(staticFactory, context, true, argumentList);
|
||||
}
|
||||
}
|
||||
return staticFactoryCandidateInfo;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiMethod findConstructorStaticFactory(final PsiClass containingClass, PsiNewExpression newExpression) {
|
||||
@@ -370,60 +397,40 @@ public class PsiDiamondTypeImpl extends PsiDiamondType {
|
||||
}
|
||||
|
||||
|
||||
private static PsiSubstitutor inferTypeParametersForStaticFactory(@NotNull PsiMethod staticFactoryMethod,
|
||||
PsiNewExpression expression,
|
||||
final PsiElement parent,
|
||||
final boolean varargs) {
|
||||
final PsiExpressionList argumentList = expression.getArgumentList();
|
||||
if (argumentList != null) {
|
||||
final MethodCandidateInfo staticFactoryCandidateInfo =
|
||||
new MethodCandidateInfo(staticFactoryMethod, PsiSubstitutor.EMPTY, false, false, argumentList, parent, null, null) {
|
||||
private PsiType[] myExpressionTypes;
|
||||
private static MethodCandidateInfo createMethodCandidate(@NotNull final PsiMethod staticFactoryMethod,
|
||||
final PsiElement parent,
|
||||
final boolean varargs,
|
||||
final PsiExpressionList argumentList) {
|
||||
return new MethodCandidateInfo(staticFactoryMethod, PsiSubstitutor.EMPTY, false, false, argumentList, parent, null, null) {
|
||||
private PsiType[] myExpressionTypes;
|
||||
|
||||
@Override
|
||||
public boolean isVarargs() {
|
||||
return varargs;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiElement getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiType[] getArgumentTypes() {
|
||||
if (myExpressionTypes == null) {
|
||||
final PsiType[] expressionTypes = argumentList.getExpressionTypes();
|
||||
if (MethodCandidateInfo.isOverloadCheck()) {
|
||||
return expressionTypes;
|
||||
}
|
||||
myExpressionTypes = expressionTypes;
|
||||
}
|
||||
return myExpressionTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiElement getMarkerList() {
|
||||
return parent instanceof PsiNewExpression ? ((PsiNewExpression)parent).getArgumentList() : super.getMarkerList();
|
||||
}
|
||||
};
|
||||
if (!varargs && staticFactoryMethod.isVarArgs()) {
|
||||
final Computable<Integer> computable = new Computable<Integer>() {
|
||||
@Override
|
||||
public Integer compute() {
|
||||
return staticFactoryCandidateInfo.getPertinentApplicabilityLevel();
|
||||
}
|
||||
};
|
||||
final Integer applicability = MethodCandidateInfo.ourOverloadGuard.doPreventingRecursion(expression, true, computable);
|
||||
if ((applicability != null ? applicability : staticFactoryCandidateInfo.getApplicabilityLevel()) < MethodCandidateInfo.ApplicabilityLevel.FIXED_ARITY) {
|
||||
return inferTypeParametersForStaticFactory(staticFactoryMethod, expression, parent, true);
|
||||
}
|
||||
@Override
|
||||
public boolean isVarargs() {
|
||||
return varargs;
|
||||
}
|
||||
return staticFactoryCandidateInfo.getSubstitutor();
|
||||
}
|
||||
else {
|
||||
return PsiSubstitutor.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiElement getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiType[] getArgumentTypes() {
|
||||
if (myExpressionTypes == null) {
|
||||
final PsiType[] expressionTypes = argumentList.getExpressionTypes();
|
||||
if (MethodCandidateInfo.isOverloadCheck()) {
|
||||
return expressionTypes;
|
||||
}
|
||||
myExpressionTypes = expressionTypes;
|
||||
}
|
||||
return myExpressionTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiElement getMarkerList() {
|
||||
return parent instanceof PsiNewExpression ? ((PsiNewExpression)parent).getArgumentList() : super.getMarkerList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean hasDefaultConstructor(@NotNull final PsiClass psiClass) {
|
||||
|
||||
@@ -442,16 +442,22 @@ public class InferenceSession {
|
||||
: PsiResolveHelper.ourGraphGuard.doPreventingRecursion(expression, false, computableResolve);
|
||||
}
|
||||
|
||||
public static JavaResolveResult getResolveResult(PsiCall callExpression, PsiExpressionList argumentList) {
|
||||
public static JavaResolveResult getResolveResult(final PsiCall callExpression, final PsiExpressionList argumentList) {
|
||||
if (callExpression instanceof PsiNewExpression) {
|
||||
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)callExpression).getClassOrAnonymousClassReference();
|
||||
final JavaResolveResult resolveResult = classReference != null ? classReference.advancedResolve(false) : null;
|
||||
final PsiElement psiClass = resolveResult != null ? resolveResult.getElement() : null;
|
||||
if (psiClass instanceof PsiClass) {
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(callExpression.getProject());
|
||||
final JavaResolveResult constructor = facade.getResolveHelper()
|
||||
.resolveConstructor(facade.getElementFactory().createType((PsiClass)psiClass).rawType(), argumentList, callExpression);
|
||||
return constructor.getElement() == null ? resolveResult : constructor;
|
||||
return CachedValuesManager.getCachedValue(classReference, new CachedValueProvider<JavaResolveResult>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Result<JavaResolveResult> compute() {
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(callExpression.getProject());
|
||||
final JavaResolveResult constructor = facade.getResolveHelper()
|
||||
.resolveConstructor(facade.getElementFactory().createType((PsiClass)psiClass).rawType(), argumentList, callExpression);
|
||||
return new Result<JavaResolveResult>(constructor.getElement() == null ? resolveResult : constructor, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
return JavaResolveResult.EMPTY;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
class Test {
|
||||
static class C<U> {
|
||||
U u;
|
||||
C(C<U> other) {
|
||||
u = other.u;
|
||||
}
|
||||
|
||||
C(U u) {
|
||||
this.u = u;
|
||||
}
|
||||
}
|
||||
|
||||
static <U> C<U> foo(C<U> c) { return new C<U>(c); }
|
||||
|
||||
{
|
||||
C<String> c = foo(new C<>(foo(new C<>(foo(new C<>(foo(new C<>(foo(null)))))))));
|
||||
}
|
||||
}
|
||||
@@ -102,6 +102,15 @@ public class OverloadResolutionTest extends LightDaemonAnalyzerTestCase {
|
||||
}).assertTiming();
|
||||
}
|
||||
|
||||
public void testConstructorOverloadsWithDiamonds() throws Exception {
|
||||
PlatformTestUtil.startPerformanceTest("Overload resolution with chain constructor calls with diamonds", 10000, new ThrowableRunnable() {
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
doTest(false);
|
||||
}
|
||||
}).assertTiming();
|
||||
}
|
||||
|
||||
public void testMultipleOverloadsWithNestedGeneric() throws Exception {
|
||||
doTest(false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user