FIR IDE: introduce HL API for creating class types
This commit is contained in:
committed by
TeamCityServer
parent
8094a5448d
commit
e2cfd933f1
+5
-2
@@ -44,8 +44,8 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali
|
|||||||
KtSymbolDeclarationRendererMixIn,
|
KtSymbolDeclarationRendererMixIn,
|
||||||
KtVisibilityCheckerMixIn,
|
KtVisibilityCheckerMixIn,
|
||||||
KtMemberSymbolProviderMixin,
|
KtMemberSymbolProviderMixin,
|
||||||
KtInheritorsProviderMixIn
|
KtInheritorsProviderMixIn,
|
||||||
{
|
KtTypeCreatorMixIn {
|
||||||
|
|
||||||
override val analysisSession: KtAnalysisSession get() = this
|
override val analysisSession: KtAnalysisSession get() = this
|
||||||
|
|
||||||
@@ -107,4 +107,7 @@ abstract class KtAnalysisSession(final override val token: ValidityToken) : Vali
|
|||||||
|
|
||||||
internal val inheritorsProvider: KtInheritorsProvider get() = inheritorsProviderImpl
|
internal val inheritorsProvider: KtInheritorsProvider get() = inheritorsProviderImpl
|
||||||
protected abstract val inheritorsProviderImpl: KtInheritorsProvider
|
protected abstract val inheritorsProviderImpl: KtInheritorsProvider
|
||||||
|
|
||||||
|
@PublishedApi internal val typesCreator: KtTypeCreator get() = typesCreatorImpl
|
||||||
|
protected abstract val typesCreatorImpl: KtTypeCreator
|
||||||
}
|
}
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* 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.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtTypeNullability
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
|
||||||
|
abstract class KtTypeCreator : KtAnalysisSessionComponent() {
|
||||||
|
abstract fun buildClassType(builder: KtClassTypeBuilder): KtClassType
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KtTypeCreatorMixIn : KtAnalysisSessionMixIn
|
||||||
|
|
||||||
|
|
||||||
|
inline fun KtTypeCreatorMixIn.buildClassType(
|
||||||
|
classId: ClassId,
|
||||||
|
build: KtClassTypeBuilder.() -> Unit = {}
|
||||||
|
): KtClassType =
|
||||||
|
analysisSession.typesCreator.buildClassType(KtClassTypeBuilder.ByClassId(classId).apply(build))
|
||||||
|
|
||||||
|
inline fun KtTypeCreatorMixIn.buildClassType(
|
||||||
|
symbol: KtClassOrObjectSymbol,
|
||||||
|
build: KtClassTypeBuilder.() -> Unit = {}
|
||||||
|
): KtClassType =
|
||||||
|
analysisSession.typesCreator.buildClassType(KtClassTypeBuilder.BySymbol(symbol).apply(build))
|
||||||
|
|
||||||
|
|
||||||
|
sealed class KtTypeBuilder
|
||||||
|
|
||||||
|
sealed class KtClassTypeBuilder : KtTypeBuilder() {
|
||||||
|
private val _arguments = mutableListOf<KtType>()
|
||||||
|
|
||||||
|
var nullability: KtTypeNullability = KtTypeNullability.NON_NULLABLE
|
||||||
|
|
||||||
|
val arguments: List<KtType> get() = _arguments
|
||||||
|
|
||||||
|
fun argument(argument: KtType) {
|
||||||
|
_arguments += argument
|
||||||
|
}
|
||||||
|
|
||||||
|
class ByClassId(val classId: ClassId) : KtClassTypeBuilder()
|
||||||
|
class BySymbol(val symbol: KtClassOrObjectSymbol) : KtClassTypeBuilder()
|
||||||
|
}
|
||||||
|
|
||||||
+3
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
|||||||
import org.jetbrains.kotlin.idea.frontend.api.components.KtInheritorsProvider
|
import org.jetbrains.kotlin.idea.frontend.api.components.KtInheritorsProvider
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.components.KtVisibilityChecker
|
import org.jetbrains.kotlin.idea.frontend.api.components.KtVisibilityChecker
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.components.KtSymbolDeclarationRendererProvider
|
import org.jetbrains.kotlin.idea.frontend.api.components.KtSymbolDeclarationRendererProvider
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeCreator
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.components.*
|
import org.jetbrains.kotlin.idea.frontend.api.fir.components.*
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirOverrideInfoProvider
|
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirOverrideInfoProvider
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbolProvider
|
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbolProvider
|
||||||
@@ -83,6 +84,8 @@ private constructor(
|
|||||||
|
|
||||||
override val inheritorsProviderImpl: KtInheritorsProvider = KtFirInheritorsProvider(this, token)
|
override val inheritorsProviderImpl: KtInheritorsProvider = KtFirInheritorsProvider(this, token)
|
||||||
|
|
||||||
|
override val typesCreatorImpl: KtTypeCreator = KtFirTypeCreator(this, token)
|
||||||
|
|
||||||
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession {
|
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession {
|
||||||
check(mode == AnalysisSessionMode.REGULAR) {
|
check(mode == AnalysisSessionMode.REGULAR) {
|
||||||
"Cannot create context-dependent copy of KtAnalysis session from a context dependent one"
|
"Cannot create context-dependent copy of KtAnalysis session from a context dependent one"
|
||||||
|
|||||||
+8
@@ -20,6 +20,8 @@ import org.jetbrains.kotlin.idea.frontend.api.diagnostics.KtDiagnosticWithPsi
|
|||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KT_DIAGNOSTIC_CONVERTER
|
import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KT_DIAGNOSTIC_CONVERTER
|
||||||
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
import org.jetbrains.kotlin.load.kotlin.TypeMappingMode
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||||
|
|
||||||
internal interface KtFirAnalysisSessionComponent {
|
internal interface KtFirAnalysisSessionComponent {
|
||||||
val analysisSession: KtFirAnalysisSession
|
val analysisSession: KtFirAnalysisSession
|
||||||
@@ -42,6 +44,12 @@ internal interface KtFirAnalysisSessionComponent {
|
|||||||
return firDiagnostic.asKtDiagnostic()
|
return firDiagnostic.asKtDiagnostic()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val KtType.coneType: ConeKotlinType
|
||||||
|
get() {
|
||||||
|
require(this is KtFirType)
|
||||||
|
return coneType
|
||||||
|
}
|
||||||
|
|
||||||
fun createTypeCheckerContext() = ConeTypeCheckerContext(
|
fun createTypeCheckerContext() = ConeTypeCheckerContext(
|
||||||
isErrorTypeEqualsToAnything = true,
|
isErrorTypeEqualsToAnything = true,
|
||||||
isStubTypeEqualsToAnything = true,
|
isStubTypeEqualsToAnything = true,
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.components
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirClassLikeDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedSymbolError
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.symbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.typeContext
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeClassErrorType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.components.KtClassTypeBuilder
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeCreator
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbol
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.tokens.ValidityToken
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.withValidityAssertion
|
||||||
|
|
||||||
|
internal class KtFirTypeCreator(
|
||||||
|
override val analysisSession: KtFirAnalysisSession,
|
||||||
|
override val token: ValidityToken
|
||||||
|
) : KtTypeCreator(), KtFirAnalysisSessionComponent {
|
||||||
|
|
||||||
|
override fun buildClassType(builder: KtClassTypeBuilder): KtClassType = withValidityAssertion {
|
||||||
|
val lookupTag = when (builder) {
|
||||||
|
is KtClassTypeBuilder.ByClassId -> {
|
||||||
|
val classSymbol = rootModuleSession.symbolProvider.getClassLikeSymbolByFqName(builder.classId)
|
||||||
|
?: return ConeClassErrorType(ConeUnresolvedSymbolError(builder.classId)).asKtType() as KtClassType
|
||||||
|
classSymbol.toLookupTag()
|
||||||
|
}
|
||||||
|
is KtClassTypeBuilder.BySymbol -> {
|
||||||
|
val symbol = builder.symbol
|
||||||
|
check(symbol is KtFirSymbol<*>)
|
||||||
|
symbol.firRef.withFir { (it as FirClassLikeDeclaration<*>).symbol.toLookupTag() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val coneType = rootModuleSession.typeContext.createSimpleType(
|
||||||
|
lookupTag,
|
||||||
|
builder.arguments.map { it.coneType },
|
||||||
|
builder.nullability.isNullable
|
||||||
|
) as ConeClassLikeType
|
||||||
|
|
||||||
|
return coneType.asKtType() as KtClassType
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-16
@@ -20,10 +20,8 @@ import org.jetbrains.kotlin.name.ClassId
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
internal interface KtFirType : KtType, ValidityTokenOwner {
|
internal interface KtFirType : ValidityTokenOwner {
|
||||||
val coneType: ConeKotlinType
|
val coneType: ConeKotlinType
|
||||||
|
|
||||||
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class KtFirUsualClassType(
|
internal class KtFirUsualClassType(
|
||||||
@@ -45,10 +43,7 @@ internal class KtFirUsualClassType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val nullability: KtTypeNullability get() = withValidityAssertion { KtTypeNullability.create(coneType.isNullable) }
|
override val nullability: KtTypeNullability get() = withValidityAssertion { KtTypeNullability.create(coneType.isNullable) }
|
||||||
|
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||||
override fun asString(): String = withValidityAssertion {
|
|
||||||
coneType.render() //todo
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class KtFirFunctionalType(
|
internal class KtFirFunctionalType(
|
||||||
@@ -93,18 +88,17 @@ internal class KtFirFunctionalType(
|
|||||||
override val returnType: KtType
|
override val returnType: KtType
|
||||||
get() = withValidityAssertion { (typeArguments.last() as KtTypeArgumentWithVariance).type }
|
get() = withValidityAssertion { (typeArguments.last() as KtTypeArgumentWithVariance).type }
|
||||||
|
|
||||||
override fun asString(): String = withValidityAssertion {
|
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||||
coneType.render() //todo
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class KtFirErrorType(
|
internal class KtFirClassErrorType(
|
||||||
coneType: ConeClassErrorType,
|
coneType: ConeClassErrorType,
|
||||||
override val token: ValidityToken,
|
override val token: ValidityToken,
|
||||||
) : KtErrorType(), KtFirType {
|
) : KtClassErrorType(), KtFirType {
|
||||||
override val coneType by weakRef(coneType)
|
override val coneType by weakRef(coneType)
|
||||||
|
|
||||||
override val error: String get() = withValidityAssertion { coneType.diagnostic.reason }
|
override val error: String get() = withValidityAssertion { coneType.diagnostic.reason }
|
||||||
|
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class KtFirTypeParameterType(
|
internal class KtFirTypeParameterType(
|
||||||
@@ -121,10 +115,7 @@ internal class KtFirTypeParameterType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override val nullability: KtTypeNullability get() = withValidityAssertion { KtTypeNullability.create(coneType.isNullable) }
|
override val nullability: KtTypeNullability get() = withValidityAssertion { KtTypeNullability.create(coneType.isNullable) }
|
||||||
|
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||||
override fun asString(): String = withValidityAssertion {
|
|
||||||
coneType.render() //todo
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class KtFirFlexibleType(
|
internal class KtFirFlexibleType(
|
||||||
@@ -136,6 +127,7 @@ internal class KtFirFlexibleType(
|
|||||||
|
|
||||||
override val lowerBound: KtType by cached { firBuilder.typeBuilder.buildKtType(coneType.lowerBound) }
|
override val lowerBound: KtType by cached { firBuilder.typeBuilder.buildKtType(coneType.lowerBound) }
|
||||||
override val upperBound: KtType by cached { firBuilder.typeBuilder.buildKtType(coneType.upperBound) }
|
override val upperBound: KtType by cached { firBuilder.typeBuilder.buildKtType(coneType.upperBound) }
|
||||||
|
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class KtFirIntersectionType(
|
internal class KtFirIntersectionType(
|
||||||
@@ -148,6 +140,8 @@ internal class KtFirIntersectionType(
|
|||||||
override val conjuncts: List<KtType> by cached {
|
override val conjuncts: List<KtType> by cached {
|
||||||
coneType.intersectedTypes.map { conjunct -> firBuilder.typeBuilder.buildKtType(conjunct) }
|
coneType.intersectedTypes.map { conjunct -> firBuilder.typeBuilder.buildKtType(conjunct) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class KtFirTypeArgumentWithVariance(
|
internal class KtFirTypeArgumentWithVariance(
|
||||||
|
|||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.fir.frontend.api.components
|
||||||
|
|
||||||
|
import com.intellij.testFramework.LightProjectDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.fir.executeOnPooledThreadInReadAction
|
||||||
|
import org.jetbrains.kotlin.idea.fir.invalidateCaches
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.analyse
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeRendererOptions
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.components.buildClassType
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtType
|
||||||
|
import org.jetbrains.kotlin.idea.frontend.api.types.KtTypeNullability
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
internal class TypeCreatorTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||||
|
override fun isFirPlugin() = true
|
||||||
|
|
||||||
|
override fun tearDown() {
|
||||||
|
project.invalidateCaches(file as? KtFile)
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doTest(
|
||||||
|
expected: String,
|
||||||
|
buildType: KtAnalysisSession.() -> KtType,
|
||||||
|
) {
|
||||||
|
val fakeKtFile = myFixture.configureByText("file.kt", "val a = 10") as KtFile
|
||||||
|
val renderedType = executeOnPooledThreadInReadAction {
|
||||||
|
analyse(fakeKtFile) {
|
||||||
|
val ktType = buildType()
|
||||||
|
ktType.render(RENDERING_OPTIONS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals(expected, renderedType)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testClassTypeByClassId() {
|
||||||
|
doTest("List<Int?>") {
|
||||||
|
buildClassType(StandardClassIds.List) {
|
||||||
|
argument(buildClassType(StandardClassIds.Int) { nullability = KtTypeNullability.NULLABLE })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testClassTypeBySymbolClassId() {
|
||||||
|
doTest("MutableList<Int>") {
|
||||||
|
val listSymbol = StandardClassIds.MutableList.getCorrespondingToplevelClassOrObjectSymbol()!!
|
||||||
|
buildClassType(listSymbol) {
|
||||||
|
argument(buildClassType(StandardClassIds.Int))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testClassTypeByUnresolvedClassId() {
|
||||||
|
doTest("ERROR_TYPE <Symbol not found for /NonExistingListClass>") {
|
||||||
|
buildClassType(ClassId.fromString("NonExistingListClass")) {
|
||||||
|
argument(buildClassType(StandardClassIds.Int) { nullability = KtTypeNullability.NULLABLE })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val RENDERING_OPTIONS = KtTypeRendererOptions.SHORT_NAMES
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user