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,
|
||||
KtVisibilityCheckerMixIn,
|
||||
KtMemberSymbolProviderMixin,
|
||||
KtInheritorsProviderMixIn
|
||||
{
|
||||
KtInheritorsProviderMixIn,
|
||||
KtTypeCreatorMixIn {
|
||||
|
||||
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
|
||||
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.KtVisibilityChecker
|
||||
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.symbols.KtFirOverrideInfoProvider
|
||||
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 typesCreatorImpl: KtTypeCreator = KtFirTypeCreator(this, token)
|
||||
|
||||
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession {
|
||||
check(mode == AnalysisSessionMode.REGULAR) {
|
||||
"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.diagnostics.KT_DIAGNOSTIC_CONVERTER
|
||||
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 {
|
||||
val analysisSession: KtFirAnalysisSession
|
||||
@@ -42,6 +44,12 @@ internal interface KtFirAnalysisSessionComponent {
|
||||
return firDiagnostic.asKtDiagnostic()
|
||||
}
|
||||
|
||||
val KtType.coneType: ConeKotlinType
|
||||
get() {
|
||||
require(this is KtFirType)
|
||||
return coneType
|
||||
}
|
||||
|
||||
fun createTypeCheckerContext() = ConeTypeCheckerContext(
|
||||
isErrorTypeEqualsToAnything = 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.types.Variance
|
||||
|
||||
internal interface KtFirType : KtType, ValidityTokenOwner {
|
||||
internal interface KtFirType : ValidityTokenOwner {
|
||||
val coneType: ConeKotlinType
|
||||
|
||||
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||
}
|
||||
|
||||
internal class KtFirUsualClassType(
|
||||
@@ -45,10 +43,7 @@ internal class KtFirUsualClassType(
|
||||
}
|
||||
|
||||
override val nullability: KtTypeNullability get() = withValidityAssertion { KtTypeNullability.create(coneType.isNullable) }
|
||||
|
||||
override fun asString(): String = withValidityAssertion {
|
||||
coneType.render() //todo
|
||||
}
|
||||
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||
}
|
||||
|
||||
internal class KtFirFunctionalType(
|
||||
@@ -93,18 +88,17 @@ internal class KtFirFunctionalType(
|
||||
override val returnType: KtType
|
||||
get() = withValidityAssertion { (typeArguments.last() as KtTypeArgumentWithVariance).type }
|
||||
|
||||
override fun asString(): String = withValidityAssertion {
|
||||
coneType.render() //todo
|
||||
}
|
||||
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||
}
|
||||
|
||||
internal class KtFirErrorType(
|
||||
internal class KtFirClassErrorType(
|
||||
coneType: ConeClassErrorType,
|
||||
override val token: ValidityToken,
|
||||
) : KtErrorType(), KtFirType {
|
||||
) : KtClassErrorType(), KtFirType {
|
||||
override val coneType by weakRef(coneType)
|
||||
|
||||
override val error: String get() = withValidityAssertion { coneType.diagnostic.reason }
|
||||
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||
}
|
||||
|
||||
internal class KtFirTypeParameterType(
|
||||
@@ -121,10 +115,7 @@ internal class KtFirTypeParameterType(
|
||||
}
|
||||
|
||||
override val nullability: KtTypeNullability get() = withValidityAssertion { KtTypeNullability.create(coneType.isNullable) }
|
||||
|
||||
override fun asString(): String = withValidityAssertion {
|
||||
coneType.render() //todo
|
||||
}
|
||||
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||
}
|
||||
|
||||
internal class KtFirFlexibleType(
|
||||
@@ -136,6 +127,7 @@ internal class KtFirFlexibleType(
|
||||
|
||||
override val lowerBound: KtType by cached { firBuilder.typeBuilder.buildKtType(coneType.lowerBound) }
|
||||
override val upperBound: KtType by cached { firBuilder.typeBuilder.buildKtType(coneType.upperBound) }
|
||||
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||
}
|
||||
|
||||
internal class KtFirIntersectionType(
|
||||
@@ -148,6 +140,8 @@ internal class KtFirIntersectionType(
|
||||
override val conjuncts: List<KtType> by cached {
|
||||
coneType.intersectedTypes.map { conjunct -> firBuilder.typeBuilder.buildKtType(conjunct) }
|
||||
}
|
||||
|
||||
override fun asStringForDebugging(): String = withValidityAssertion { coneType.render() }
|
||||
}
|
||||
|
||||
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