From 28fcfceaaf1ffee1f3beb44eaf3b60a179515204 Mon Sep 17 00:00:00 2001 From: Daniil Ovchinnikov Date: Mon, 28 Oct 2019 16:46:00 +0300 Subject: [PATCH] [groovy] resolve method references with top level type as receiver Support top-level type for reference expressions and index property expressions. This fixes cycle when operator resolution wanted receiver type and receiver type required inference from context, i.e. from resolved operator. GitOrigin-RevId: 2c2818e2b5689ddf0c65aac2d87b76d11f1f2ebc --- .../resolve/processors/inference/inference.kt | 26 +++++++------- .../plugins/groovy/lang/resolve/receiver.kt | 2 +- .../resolve/SubstitutorInferenceTest.groovy | 36 +++++++++++++++++++ 3 files changed, 51 insertions(+), 13 deletions(-) diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/inference/inference.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/inference/inference.kt index 15d744f467ab..2d7572b1210e 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/inference/inference.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/processors/inference/inference.kt @@ -11,6 +11,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil.getQualifierType import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrTypeConverter @@ -24,22 +25,23 @@ import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint import org.jetbrains.plugins.groovy.lang.typing.devoid fun getTopLevelType(expression: GrExpression): PsiType? { - if (expression is GrMethodCall) { - val resolved = expression.advancedResolve() as? GroovyMethodResult - resolved?.candidate?.let { - val session = GroovyInferenceSessionBuilder(expression, it, resolved.contextSubstitutor) - .resolveMode(false) - .build() - return session.inferSubst().substitute(PsiUtil.getSmartReturnType(it.method).devoid(expression)) - } - return null - } - if (expression is GrFunctionalExpression) { return TypesUtil.createTypeByFQClassName(GroovyCommonClassNames.GROOVY_LANG_CLOSURE, expression) } - return expression.type + val result = when (expression) { + is GrMethodCall -> expression.advancedResolve() as? GroovyMethodResult + is GrReferenceExpression -> expression.rValueReference?.advancedResolve() as? GroovyMethodResult ?: return expression.type + is GrIndexProperty -> expression.rValueReference?.advancedResolve() as? GroovyMethodResult ?: return expression.type + else -> return expression.type + } + + return result?.candidate?.let { + val session = GroovyInferenceSessionBuilder(expression, it, result.contextSubstitutor) + .resolveMode(false) + .build() + session.inferSubst().substitute(PsiUtil.getSmartReturnType(it.method).devoid(expression)) + } } fun buildQualifier(ref: GrReferenceExpression?, state: ResolveState): Argument { diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/receiver.kt b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/receiver.kt index 201942f4b812..45b19d029666 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/receiver.kt +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/resolve/receiver.kt @@ -18,7 +18,7 @@ import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint.STATIC_CONTEXT fun Argument.processReceiver(processor: PsiScopeProcessor, state: ResolveState, place: PsiElement): Boolean { - val receiverType: PsiType = type ?: TypesUtil.getJavaLangObject(place) ?: return true + val receiverType: PsiType = topLevelType ?: TypesUtil.getJavaLangObject(place) ?: return true return receiverType.doProcessReceiverType0(processor, state.put(ClassHint.RECEIVER, this), place) } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/SubstitutorInferenceTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/SubstitutorInferenceTest.groovy index 5abb1c45430d..331d45f99584 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/SubstitutorInferenceTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/resolve/SubstitutorInferenceTest.groovy @@ -9,6 +9,7 @@ import org.jetbrains.plugins.groovy.GroovyProjectDescriptors import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.* +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod import org.jetbrains.plugins.groovy.util.LightProjectTest import org.jetbrains.plugins.groovy.util.ResolveTest @@ -49,6 +50,9 @@ class IdCallable { class GenericPropertyContainer { def I getGenericProperty() {} def void setGenericProperty(I c) {} + + def List getGenericList() {} + def void setGenericList(List l) {} } class Files { @@ -242,6 +246,38 @@ static T ppp(Producer p) {} assertSubstitutor(op.reference.advancedResolve(), 'java.io.File') } + @Test + void 'plus assignment generic property r-value'() { + def ref = elementUnderCaret('new GenericPropertyContainer().genericList += new ArrayList()', GrReferenceExpression) + assertSubstitutor(ref.RValueReference.advancedResolve(), JAVA_LANG_STRING) + } + + @Test + void 'plus assignment generic property'() { + def op = elementUnderCaret('new GenericPropertyContainer().genericList += new ArrayList()', GrAssignmentExpression) + assertSubstitutor(op.reference.advancedResolve(), JAVA_LANG_STRING) + } + + @Ignore("we don't yet infer l-value substitutors") + @Test + void 'plus assignment generic property l-value'() { + def ref = elementUnderCaret('new GenericPropertyContainer().genericList += new ArrayList()', GrReferenceExpression) + assertSubstitutor(ref.LValueReference.advancedResolve(), JAVA_LANG_STRING) + } + + @Test + void 'plus assignment with index r-value'() { + def op = elementUnderCaret('Map mns; mns[42] += "foo"', GrIndexProperty) + assertSubstitutor(op.RValueReference.advancedResolve(), JAVA_LANG_NUMBER, JAVA_LANG_STRING) + } + + @Ignore("we don't yet infer l-value substitutors") + @Test + void 'plus assignment with index l-value'() { + def op = elementUnderCaret('Map mns; mns[42] += "foo"', GrIndexProperty) + assertSubstitutor(op.LValueReference.advancedResolve(), JAVA_LANG_NUMBER, JAVA_LANG_STRING) + } + @Test void 'same method nested'() { def call = elementUnderCaret '''\