[FIR-IDE] Hack for checking single candidate resolver in tests

This commit is contained in:
Pavel Kirpichenkov
2020-08-19 13:18:53 +03:00
parent 2c816d8911
commit ec072798b1
10 changed files with 191 additions and 4 deletions
+1
View File
@@ -187,6 +187,7 @@ dependencies {
testRuntime(intellijPluginDep("smali"))
testRuntime(intellijPluginDep("testng"))
testRuntime(project(":idea:idea-fir"))
testRuntime(project(":idea:idea-frontend-fir"))
if (Ide.AS36.orHigher()) {
@@ -0,0 +1,20 @@
class A
open class B
class C : B()
interface D
fun <T> T.ext1() where T : B {}
fun B.ext2() {}
fun A.ext3() {}
fun <T> T.ext4() where T : B, T : D {}
fun usage() {
val c = C()
c.ext<caret>
}
// EXIST: ext1
// EXIST: ext2
// ABSENT: ext3
// ABSENT: ext4
@@ -0,0 +1,11 @@
fun <T : Int> T.ext1() {}
fun <T : String> T.ext2() {}
fun test() {
with(42) {
ext<caret>
}
}
// EXIST: ext1
// ABSENT: ext2
@@ -0,0 +1,24 @@
class A<T1, T2> {
fun foo1() {}
class B<T3, T4> {
fun foo2() {}
fun foo3() {
foo<caret>
}
}
class C
companion object {
fun <T7, T8> B<T7, T8>.foo4() {}
fun C.foo5() {}
}
}
// ABSENT: foo1
// EXIST: foo2
// EXIST: foo3
// EXIST: foo4
// ABSENT: foo5
@@ -85,6 +85,11 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
runTest("idea/idea-completion/testData/basic/common/ComponentFunction.kt");
}
@TestMetadata("ConsiderExtensionType.kt")
public void testConsiderExtensionType() throws Exception {
runTest("idea/idea-completion/testData/basic/common/ConsiderExtensionType.kt");
}
@TestMetadata("CoroutineContext.kt")
public void testCoroutineContext() throws Exception {
runTest("idea/idea-completion/testData/basic/common/CoroutineContext.kt");
@@ -185,6 +190,11 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
runTest("idea/idea-completion/testData/basic/common/ExtensionWithManyTypeParamsInReceiver.kt");
}
@TestMetadata("ExtensionsWithTypeParameterConstraints.kt")
public void testExtensionsWithTypeParameterConstraints() throws Exception {
runTest("idea/idea-completion/testData/basic/common/ExtensionsWithTypeParameterConstraints.kt");
}
@TestMetadata("FromImports.kt")
public void testFromImports() throws Exception {
runTest("idea/idea-completion/testData/basic/common/FromImports.kt");
@@ -200,6 +210,11 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
runTest("idea/idea-completion/testData/basic/common/FunctionVariableCallArgument.kt");
}
@TestMetadata("GenericCompanionExtension.kt")
public void testGenericCompanionExtension() throws Exception {
runTest("idea/idea-completion/testData/basic/common/GenericCompanionExtension.kt");
}
@TestMetadata("GenericExtensionFunReceiver1.kt")
public void testGenericExtensionFunReceiver1() throws Exception {
runTest("idea/idea-completion/testData/basic/common/GenericExtensionFunReceiver1.kt");
@@ -85,6 +85,11 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
runTest("idea/idea-completion/testData/basic/common/ComponentFunction.kt");
}
@TestMetadata("ConsiderExtensionType.kt")
public void testConsiderExtensionType() throws Exception {
runTest("idea/idea-completion/testData/basic/common/ConsiderExtensionType.kt");
}
@TestMetadata("CoroutineContext.kt")
public void testCoroutineContext() throws Exception {
runTest("idea/idea-completion/testData/basic/common/CoroutineContext.kt");
@@ -185,6 +190,11 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
runTest("idea/idea-completion/testData/basic/common/ExtensionWithManyTypeParamsInReceiver.kt");
}
@TestMetadata("ExtensionsWithTypeParameterConstraints.kt")
public void testExtensionsWithTypeParameterConstraints() throws Exception {
runTest("idea/idea-completion/testData/basic/common/ExtensionsWithTypeParameterConstraints.kt");
}
@TestMetadata("FromImports.kt")
public void testFromImports() throws Exception {
runTest("idea/idea-completion/testData/basic/common/FromImports.kt");
@@ -200,6 +210,11 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
runTest("idea/idea-completion/testData/basic/common/FunctionVariableCallArgument.kt");
}
@TestMetadata("GenericCompanionExtension.kt")
public void testGenericCompanionExtension() throws Exception {
runTest("idea/idea-completion/testData/basic/common/GenericCompanionExtension.kt");
}
@TestMetadata("GenericExtensionFunReceiver1.kt")
public void testGenericExtensionFunReceiver1() throws Exception {
runTest("idea/idea-completion/testData/basic/common/GenericExtensionFunReceiver1.kt");
@@ -118,4 +118,11 @@ abstract class KtAnalysisSession(override val token: ValidityToken) : ValidityTo
check(this is KtSymbolBasedReference) { "To get reference symbol the one should be KtSymbolBasedReference but was ${this::class}" }
return resolveToSymbols().singleOrNull()
}
abstract fun resolveAndCheckReceivers(
firSymbolForCandidate: KtCallableSymbol,
originalFile: KtFile,
nameExpression: KtSimpleNameExpression,
possibleReceiver: KtExpression?,
): Boolean
}
@@ -5,6 +5,9 @@
package org.jetbrains.kotlin.idea.frontend.api.fir
import com.jetbrains.rd.util.getOrCreate
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
@@ -17,10 +20,20 @@ import org.jetbrains.kotlin.idea.frontend.api.components.KtDiagnosticProvider
import org.jetbrains.kotlin.idea.frontend.api.components.KtSmartCastProvider
import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeProvider
import org.jetbrains.kotlin.idea.frontend.api.fir.components.*
import org.jetbrains.kotlin.idea.fir.*
import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.SingleCandidateResolver
import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.SingleCandidateResolutionMode
import org.jetbrains.kotlin.idea.fir.low.level.api.resolver.ResolutionParameters
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirFunctionSymbol
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbolProvider
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.threadLocal
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbolProvider
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
import org.jetbrains.kotlin.idea.util.getElementTextInContext
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal class KtFirAnalysisSession
private constructor(
@@ -58,6 +71,53 @@ private constructor(
)
}
private val completionContextCache = HashMap<Pair<FirFile, KtNamedFunction>, LowLevelFirApiFacade.FirCompletionContext>()
// Temporary kludge to check single candidate resolver in tests
override fun resolveAndCheckReceivers(
firSymbolForCandidate: KtCallableSymbol,
originalFile: KtFile,
nameExpression: KtSimpleNameExpression,
possibleReceiver: KtExpression?,
): Boolean {
firSymbolForCandidate.safeAs<KtFirFunctionSymbol>()?.firRef?.withFir { firFunction ->
val file = originalFile.getOrBuildFirOfType<FirFile>(firResolveState)
val explicitReceiverExpression = possibleReceiver?.getOrBuildFirOfType<FirExpression>(firResolveState)
val resolver = SingleCandidateResolver(firResolveState.firIdeSourcesSession, file)
val enclosingFunction = nameExpression.getNonStrictParentOfType<KtNamedFunction>()
?: error("Cannot find enclosing function for ${nameExpression.getElementTextInContext()}")
val completionContext = completionContextCache.getOrCreate(file to enclosingFunction) {
LowLevelFirApiFacade.buildCompletionContextForFunction(
file,
enclosingFunction,
enclosingFunction,
state = firResolveState
)
}
val towerDataContext = completionContext.getTowerDataContext(nameExpression)
val implicitReceivers = sequence {
yield(null)
yieldAll(towerDataContext.implicitReceiverStack)
}
for (implicitReceiverValue in implicitReceivers) {
val resolutionParameters = ResolutionParameters(
singleCandidateResolutionMode = SingleCandidateResolutionMode.CHECK_EXTENSION_FOR_COMPLETION,
callableSymbol = firFunction.symbol,
implicitReceiver = implicitReceiverValue,
explicitReceiver = explicitReceiverExpression
)
resolver.resolveSingleCandidate(resolutionParameters)?.let {
// not null if resolved and completed successfully
return true
}
}
}
return false
}
companion object {
@Deprecated("Please use org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSessionProviderKt.analyze")
internal fun createForElement(element: KtElement): KtFirAnalysisSession {
@@ -13,10 +13,7 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.scope
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractSimpleImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractStarImportingScope
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
import org.jetbrains.kotlin.fir.scopes.impl.*
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
import org.jetbrains.kotlin.idea.fir.getOrBuildFirOfType
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveState
@@ -155,6 +152,7 @@ internal class KtFirScopeProvider(
is FirAbstractStarImportingScope -> KtFirStarImportingScope(firScope, builder, project, token)
is FirPackageMemberScope -> KtFirPackageScope(firScope, project, builder, token)
is FirContainingNamesAwareScope -> KtFirDelegatingScopeImpl(firScope, builder, token)
is FirMemberTypeParameterScope -> KtFirMemberTypeParameterStubbingScope(firScope, token)
else -> TODO(firScope::class.toString())
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.frontend.api.fir.scopes
import org.jetbrains.kotlin.fir.scopes.impl.FirMemberTypeParameterScope
import org.jetbrains.kotlin.idea.frontend.api.ValidityToken
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScope
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.name.Name
// Does nothing, it is used to close the hole in KtFirScopeProvider
// TODO: check if this scope should provide something useful
class KtFirMemberTypeParameterStubbingScope(
val firMemberTypeParameterScope: FirMemberTypeParameterScope,
override val token: ValidityToken,
) : KtScope {
override fun getCallableNames(): Set<Name> {
return emptySet()
}
override fun getClassLikeSymbolNames(): Set<Name> {
return emptySet()
}
override fun getCallableSymbols(): Sequence<KtCallableSymbol> {
return emptySequence()
}
override fun getClassClassLikeSymbols(): Sequence<KtClassLikeSymbol> {
return emptySequence()
}
}