[FIR-IDE] Hack for checking single candidate resolver in tests
This commit is contained in:
@@ -187,6 +187,7 @@ dependencies {
|
|||||||
testRuntime(intellijPluginDep("smali"))
|
testRuntime(intellijPluginDep("smali"))
|
||||||
testRuntime(intellijPluginDep("testng"))
|
testRuntime(intellijPluginDep("testng"))
|
||||||
|
|
||||||
|
testRuntime(project(":idea:idea-fir"))
|
||||||
testRuntime(project(":idea:idea-frontend-fir"))
|
testRuntime(project(":idea:idea-frontend-fir"))
|
||||||
|
|
||||||
if (Ide.AS36.orHigher()) {
|
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
|
||||||
+11
@@ -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
|
||||||
+15
@@ -85,6 +85,11 @@ public class JSBasicCompletionTestGenerated extends AbstractJSBasicCompletionTes
|
|||||||
runTest("idea/idea-completion/testData/basic/common/ComponentFunction.kt");
|
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")
|
@TestMetadata("CoroutineContext.kt")
|
||||||
public void testCoroutineContext() throws Exception {
|
public void testCoroutineContext() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/CoroutineContext.kt");
|
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");
|
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")
|
@TestMetadata("FromImports.kt")
|
||||||
public void testFromImports() throws Exception {
|
public void testFromImports() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/FromImports.kt");
|
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");
|
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")
|
@TestMetadata("GenericExtensionFunReceiver1.kt")
|
||||||
public void testGenericExtensionFunReceiver1() throws Exception {
|
public void testGenericExtensionFunReceiver1() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/GenericExtensionFunReceiver1.kt");
|
runTest("idea/idea-completion/testData/basic/common/GenericExtensionFunReceiver1.kt");
|
||||||
|
|||||||
+15
@@ -85,6 +85,11 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
|
|||||||
runTest("idea/idea-completion/testData/basic/common/ComponentFunction.kt");
|
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")
|
@TestMetadata("CoroutineContext.kt")
|
||||||
public void testCoroutineContext() throws Exception {
|
public void testCoroutineContext() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/CoroutineContext.kt");
|
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");
|
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")
|
@TestMetadata("FromImports.kt")
|
||||||
public void testFromImports() throws Exception {
|
public void testFromImports() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/FromImports.kt");
|
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");
|
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")
|
@TestMetadata("GenericExtensionFunReceiver1.kt")
|
||||||
public void testGenericExtensionFunReceiver1() throws Exception {
|
public void testGenericExtensionFunReceiver1() throws Exception {
|
||||||
runTest("idea/idea-completion/testData/basic/common/GenericExtensionFunReceiver1.kt");
|
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}" }
|
check(this is KtSymbolBasedReference) { "To get reference symbol the one should be KtSymbolBasedReference but was ${this::class}" }
|
||||||
return resolveToSymbols().singleOrNull()
|
return resolveToSymbols().singleOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract fun resolveAndCheckReceivers(
|
||||||
|
firSymbolForCandidate: KtCallableSymbol,
|
||||||
|
originalFile: KtFile,
|
||||||
|
nameExpression: KtSimpleNameExpression,
|
||||||
|
possibleReceiver: KtExpression?,
|
||||||
|
): Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
+60
@@ -5,6 +5,9 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.frontend.api.fir
|
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.fir.resolve.firSymbolProvider
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveState
|
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveState
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
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.KtSmartCastProvider
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeProvider
|
import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeProvider
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.components.*
|
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.symbols.KtFirSymbolProvider
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.threadLocal
|
import org.jetbrains.kotlin.idea.frontend.api.fir.utils.threadLocal
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbolProvider
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbolProvider
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
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
|
internal class KtFirAnalysisSession
|
||||||
private constructor(
|
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 {
|
companion object {
|
||||||
@Deprecated("Please use org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSessionProviderKt.analyze")
|
@Deprecated("Please use org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSessionProviderKt.analyze")
|
||||||
internal fun createForElement(element: KtElement): KtFirAnalysisSession {
|
internal fun createForElement(element: KtElement): KtFirAnalysisSession {
|
||||||
|
|||||||
+2
-4
@@ -13,10 +13,7 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
|||||||
import org.jetbrains.kotlin.fir.resolve.scope
|
import org.jetbrains.kotlin.fir.resolve.scope
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
import org.jetbrains.kotlin.fir.scopes.FirScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractSimpleImportingScope
|
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||||
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.unsubstitutedScope
|
import org.jetbrains.kotlin.fir.scopes.unsubstitutedScope
|
||||||
import org.jetbrains.kotlin.idea.fir.getOrBuildFirOfType
|
import org.jetbrains.kotlin.idea.fir.getOrBuildFirOfType
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.FirModuleResolveState
|
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 FirAbstractStarImportingScope -> KtFirStarImportingScope(firScope, builder, project, token)
|
||||||
is FirPackageMemberScope -> KtFirPackageScope(firScope, project, builder, token)
|
is FirPackageMemberScope -> KtFirPackageScope(firScope, project, builder, token)
|
||||||
is FirContainingNamesAwareScope -> KtFirDelegatingScopeImpl(firScope, builder, token)
|
is FirContainingNamesAwareScope -> KtFirDelegatingScopeImpl(firScope, builder, token)
|
||||||
|
is FirMemberTypeParameterScope -> KtFirMemberTypeParameterStubbingScope(firScope, token)
|
||||||
else -> TODO(firScope::class.toString())
|
else -> TODO(firScope::class.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user