From 41f5d82cda9260fe6c5a2e62338b279c4bc08f39 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Wed, 17 Oct 2018 21:26:34 +0300 Subject: [PATCH] [groovy] extract GrConstructorReference from GrNewExpressionImpl --- .../expressions/GrNewExpressionImpl.java | 128 ++---------------- .../references/GrConstructorReference.kt | 62 +++++++++ 2 files changed, 70 insertions(+), 120 deletions(-) create mode 100644 plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/references/GrConstructorReference.kt diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java index 42fb3300f003..7a038e1116a6 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrNewExpressionImpl.java @@ -2,10 +2,10 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; import com.intellij.lang.ASTNode; -import com.intellij.openapi.util.TextRange; -import com.intellij.psi.*; -import com.intellij.psi.impl.source.resolve.ResolveCache; -import com.intellij.psi.util.InheritanceUtil; +import com.intellij.psi.PsiClass; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiErrorElement; +import com.intellij.psi.PsiWhiteSpace; import com.intellij.util.IncorrectOperationException; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; @@ -13,6 +13,7 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor; import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; import org.jetbrains.plugins.groovy.lang.psi.api.GrArrayInitializer; +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyReference; import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument; @@ -23,27 +24,19 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrAnonymousC import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement; -import org.jetbrains.plugins.groovy.lang.psi.dataFlow.types.TypeInferenceHelper; -import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType; import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path.GrCallExpressionImpl; -import org.jetbrains.plugins.groovy.lang.psi.util.GrInnerClassConstructorUtil; -import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; +import org.jetbrains.plugins.groovy.lang.resolve.references.GrConstructorReference; import java.util.ArrayList; import java.util.List; -import static org.jetbrains.plugins.groovy.lang.resolve.processors.inference.InferenceKt.buildTopLevelArgumentTypes; - /** * @author ilyas */ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewExpression { - private static final ResolveCache.PolyVariantResolver RESOLVER = - (reference, incompleteCode) -> reference.getElement().resolveImpl(incompleteCode); - - private final MyFakeReference myFakeReference = new MyFakeReference(); + private final GroovyReference myConstructorReference = new GrConstructorReference(this); public GrNewExpressionImpl(@NotNull ASTNode node) { super(node); @@ -171,111 +164,6 @@ public class GrNewExpressionImpl extends GrCallExpressionImpl implements GrNewEx if (getArrayCount() > 0 || getReferenceElement() == null) { return GroovyResolveResult.EMPTY_ARRAY; } - - return TypeInferenceHelper.getCurrentContext().multiResolve(myFakeReference, incompleteCode, RESOLVER); - } - - private GroovyResolveResult[] resolveImpl(boolean incompleteCode) { - GrCodeReferenceElement ref = getReferenceElement(); - if (ref == null) return GroovyResolveResult.EMPTY_ARRAY; - - GroovyResolveResult classCandidate = inferClassCandidate(ref); - if (classCandidate == null) return GroovyResolveResult.EMPTY_ARRAY; - assert classCandidate.getElement() instanceof PsiClass; - - if (incompleteCode) { - return PsiUtil.getConstructorCandidates(ref, classCandidate, null); - } - - final GrArgumentList argumentList = getArgumentList(); - if (argumentList == null) return GroovyResolveResult.EMPTY_ARRAY; - - if (argumentList.getNamedArguments().length > 0 && argumentList.getExpressionArguments().length == 0) { - PsiType mapType = GrMapType.createFromNamedArgs(argumentList, getNamedArguments()); - GroovyResolveResult[] constructorResults = - PsiUtil.getConstructorCandidates(ref, classCandidate, new PsiType[]{mapType}); //one Map parameter, actually - for (GroovyResolveResult result : constructorResults) { - final PsiElement resolved = result.getElement(); - if (resolved instanceof PsiMethod) { - PsiMethod constructor = (PsiMethod)resolved; - final PsiParameter[] parameters = constructor.getParameterList().getParameters(); - if (parameters.length == 1 && InheritanceUtil.isInheritor(parameters[0].getType(), CommonClassNames.JAVA_UTIL_MAP)) { - return constructorResults; - } - } - } - final GroovyResolveResult[] emptyConstructors = PsiUtil.getConstructorCandidates(ref, classCandidate, PsiType.EMPTY_ARRAY); - if (emptyConstructors.length > 0) { - return emptyConstructors; - } - } - - PsiType[] types = buildTopLevelArgumentTypes(ref); - - types = GrInnerClassConstructorUtil.addEnclosingArgIfNeeded(types, this, (PsiClass)classCandidate.getElement()); - return PsiUtil.getConstructorCandidates(ref, classCandidate, types); - } - - @Nullable - private static GroovyResolveResult inferClassCandidate(@NotNull GrCodeReferenceElement ref) { - final GroovyResolveResult[] classResults = ref.multiResolve(false); - for (GroovyResolveResult result : classResults) { - if (result.getElement() instanceof PsiClass) { - return result; - } - } - return null; - } - - private class MyFakeReference implements PsiPolyVariantReference { - @NotNull - @Override - public ResolveResult[] multiResolve(boolean incompleteCode) { - return GrNewExpressionImpl.this.multiResolve(incompleteCode); - } - - @NotNull - @Override - public GrNewExpressionImpl getElement() { - return GrNewExpressionImpl.this; - } - - @NotNull - @Override - public TextRange getRangeInElement() { - return TextRange.EMPTY_RANGE; - } - - @Nullable - @Override - public PsiElement resolve() { - return resolveMethod(); - } - - @NotNull - @Override - public String getCanonicalText() { - return "new expression"; - } - - @Override - public PsiElement handleElementRename(@NotNull String newElementName) throws IncorrectOperationException { - throw new UnsupportedOperationException("unsupported!"); - } - - @Override - public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException { - throw new UnsupportedOperationException("unsupported!"); - } - - @Override - public boolean isReferenceTo(@NotNull PsiElement element) { - return getManager().areElementsEquivalent(element, resolve()); - } - - @Override - public boolean isSoft() { - return false; - } + return myConstructorReference.multiResolve(incompleteCode); } } diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/references/GrConstructorReference.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/references/GrConstructorReference.kt new file mode 100644 index 000000000000..bc1794b63c32 --- /dev/null +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/references/GrConstructorReference.kt @@ -0,0 +1,62 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package org.jetbrains.plugins.groovy.lang.resolve.references + +import com.intellij.psi.CommonClassNames +import com.intellij.psi.PsiClass +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiType +import com.intellij.psi.util.InheritanceUtil +import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression +import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement +import org.jetbrains.plugins.groovy.lang.psi.impl.GrMapType +import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyReferenceBase +import org.jetbrains.plugins.groovy.lang.psi.util.GrInnerClassConstructorUtil +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil.getConstructorCandidates +import org.jetbrains.plugins.groovy.lang.resolve.processors.inference.buildTopLevelArgumentTypes + +class GrConstructorReference(element: GrNewExpression) : GroovyReferenceBase(element) { + + override fun doResolve(incomplete: Boolean): Collection { + val ref = element.referenceElement ?: return emptyList() + val classCandidate = inferClassCandidate(ref) ?: return emptyList() + assert(classCandidate.element is PsiClass) + if (incomplete) { + return getConstructorCandidates(ref, classCandidate, null).toList() + } + val argumentList = element.argumentList ?: return emptyList() + + if (argumentList.namedArguments.isNotEmpty() && argumentList.expressionArguments.isEmpty()) { + val mapType = GrMapType.createFromNamedArgs(argumentList, element.namedArguments) + val constructorResults = getConstructorCandidates(ref, classCandidate, arrayOf(mapType)) //one Map parameter, actually + for (result in constructorResults) { + val resolved = result.element + if (resolved is PsiMethod) { + val constructor = resolved as PsiMethod? + val parameters = constructor!!.parameterList.parameters + if (parameters.size == 1 && InheritanceUtil.isInheritor(parameters[0].type, CommonClassNames.JAVA_UTIL_MAP)) { + return constructorResults.toList() + } + } + } + val emptyConstructors = getConstructorCandidates(ref, classCandidate, PsiType.EMPTY_ARRAY) + if (emptyConstructors.isNotEmpty()) { + return emptyConstructors.toList() + } + } + + var types = buildTopLevelArgumentTypes(ref) + types = GrInnerClassConstructorUtil.addEnclosingArgIfNeeded(types, element, classCandidate.element as PsiClass) + return getConstructorCandidates(ref, classCandidate, types).toList() + } + + private fun inferClassCandidate(ref: GrCodeReferenceElement): GroovyResolveResult? { + val classResults = ref.multiResolve(false) + for (result in classResults) { + if (result.element is PsiClass) { + return result + } + } + return null + } +}