[FIR] Add ability to generate members and nested classifiers for existing classes
This commit is contained in:
committed by
TeamCityServer
parent
9bfa6c54b8
commit
26fa772846
+2
-4
@@ -13,13 +13,11 @@ class FirAllOpenComponentRegistrar : FirExtensionRegistrar() {
|
||||
+::AllOpenStatusTransformer
|
||||
+::AllOpenVisibilityTransformer
|
||||
+::AllOpenSupertypeGenerator
|
||||
+::AllOpenAdditionalCheckers
|
||||
|
||||
// Declaration generators
|
||||
// +::AllOpenMemberGenerator
|
||||
// +::AllOpenNestedClassGenerator
|
||||
+::AllOpenAdditionalCheckers
|
||||
+::AllOpenTopLevelDeclarationsGenerator
|
||||
+::AllOpenClassGenerator
|
||||
// +::AllOpenRecursiveNestedClassGenerator
|
||||
+::AllOpenMembersGenerator
|
||||
}
|
||||
}
|
||||
|
||||
+4
-39
@@ -88,24 +88,7 @@ class AllOpenClassGenerator(session: FirSession) : FirDeclarationGenerationExten
|
||||
else -> return emptyList()
|
||||
}
|
||||
|
||||
val constructor = buildPrimaryConstructor {
|
||||
moduleData = session.moduleData
|
||||
origin = key.origin
|
||||
returnTypeRef = buildResolvedTypeRef {
|
||||
type = ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(classId),
|
||||
emptyArray(),
|
||||
isNullable = false
|
||||
)
|
||||
}
|
||||
status = FirResolvedDeclarationStatusImpl(
|
||||
Visibilities.Public,
|
||||
Modality.FINAL,
|
||||
EffectiveVisibility.Public
|
||||
)
|
||||
symbol = FirConstructorSymbol(callableId)
|
||||
}
|
||||
return listOf(constructor.symbol)
|
||||
return listOf(buildConstructor(classId, callableId, isInner = false).symbol)
|
||||
}
|
||||
|
||||
private val CallableId.isGeneratedConstructor: Boolean
|
||||
@@ -136,25 +119,7 @@ class AllOpenClassGenerator(session: FirSession) : FirDeclarationGenerationExten
|
||||
require(owner is FirRegularClassSymbol)
|
||||
val matchedClassId = owner.fir.matchedClass ?: return emptyList()
|
||||
val matchedClassSymbol = session.symbolProvider.getClassLikeSymbolByClassId(matchedClassId) ?: return emptyList()
|
||||
val function = buildSimpleFunction {
|
||||
moduleData = session.moduleData
|
||||
origin = key.origin
|
||||
status = FirResolvedDeclarationStatusImpl(
|
||||
Visibilities.Public,
|
||||
Modality.FINAL,
|
||||
EffectiveVisibility.Public
|
||||
)
|
||||
returnTypeRef = buildResolvedTypeRef {
|
||||
type = ConeClassLikeTypeImpl(
|
||||
matchedClassSymbol.toLookupTag(),
|
||||
emptyArray(),
|
||||
isNullable = false
|
||||
)
|
||||
}
|
||||
name = MATERIALIZE_NAME
|
||||
symbol = FirNamedFunctionSymbol(callableId)
|
||||
}
|
||||
return listOf(function.symbol)
|
||||
return listOf(buildMaterializeFunction(matchedClassSymbol, callableId).symbol)
|
||||
}
|
||||
|
||||
private fun buildClass(classId: ClassId): FirRegularClass {
|
||||
@@ -170,7 +135,7 @@ class AllOpenClassGenerator(session: FirSession) : FirDeclarationGenerationExten
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCallableNamesForGeneratedClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
return if (classSymbol.classId in classIdsForMatchedClasses) {
|
||||
setOf(MATERIALIZE_NAME)
|
||||
} else {
|
||||
@@ -178,7 +143,7 @@ class AllOpenClassGenerator(session: FirSession) : FirDeclarationGenerationExten
|
||||
}
|
||||
}
|
||||
|
||||
override fun getNestedClassifiersNamesForGeneratedClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
override fun getNestedClassifiersNames(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
return if (classSymbol.classId == GENERATED_CLASS_ID) {
|
||||
return classIdsForMatchedClasses.keys.mapTo(mutableSetOf()) { it.shortClassName }
|
||||
} else {
|
||||
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.fir.plugin.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirPluginKey
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
|
||||
import org.jetbrains.kotlin.fir.extensions.predicate.DeclarationPredicate
|
||||
import org.jetbrains.kotlin.fir.extensions.predicate.has
|
||||
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.plugin.fqn
|
||||
import org.jetbrains.kotlin.fir.scopes.kotlinScopeProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/*
|
||||
* For each class annotated with @C generates
|
||||
* - member fun materialize(): ClassName
|
||||
* - nested class Nested with default constructor
|
||||
*/
|
||||
class AllOpenMembersGenerator(session: FirSession) : FirDeclarationGenerationExtension(session) {
|
||||
companion object {
|
||||
private val MATERIALIZE_NAME = Name.identifier("materialize")
|
||||
private val NESTED_NAME = Name.identifier("Nested")
|
||||
}
|
||||
|
||||
private val predicateBasedProvider = session.predicateBasedProvider
|
||||
private val matchedClasses by lazy {
|
||||
predicateBasedProvider.getSymbolsByPredicate(predicate).map { it.symbol }.filterIsInstance<FirRegularClassSymbol>()
|
||||
}
|
||||
|
||||
override fun generateFunctions(callableId: CallableId, owner: FirClassSymbol<*>?): List<FirNamedFunctionSymbol> {
|
||||
if (callableId.callableName != MATERIALIZE_NAME) return emptyList()
|
||||
val classId = callableId.classId ?: return emptyList()
|
||||
val matchedClassSymbol = matchedClasses.firstOrNull { it.classId == classId } ?: return emptyList()
|
||||
return listOf(buildMaterializeFunction(matchedClassSymbol, callableId).symbol)
|
||||
}
|
||||
|
||||
override fun generateClassLikeDeclaration(classId: ClassId): FirClassLikeSymbol<*>? {
|
||||
if (classId.shortClassName != NESTED_NAME) return null
|
||||
val parentClassId = classId.parentClassId ?: return null
|
||||
if (matchedClasses.none { it.classId == parentClassId }) return null
|
||||
return buildRegularClass {
|
||||
moduleData = session.moduleData
|
||||
origin = key.origin
|
||||
classKind = ClassKind.CLASS
|
||||
scopeProvider = session.kotlinScopeProvider
|
||||
status = FirResolvedDeclarationStatusImpl(Visibilities.Public, Modality.FINAL, EffectiveVisibility.Public)
|
||||
name = classId.shortClassName
|
||||
symbol = FirRegularClassSymbol(classId)
|
||||
superTypeRefs += session.builtinTypes.anyType
|
||||
}.symbol
|
||||
}
|
||||
|
||||
override fun generateConstructors(callableId: CallableId): List<FirConstructorSymbol> {
|
||||
val classId = callableId.classId ?: return emptyList()
|
||||
if (callableId.callableName != NESTED_NAME) return emptyList()
|
||||
if (matchedClasses.none { it.classId == classId }) return emptyList()
|
||||
return listOf(buildConstructor(classId.createNestedClassId(NESTED_NAME), callableId, isInner = false).symbol)
|
||||
}
|
||||
|
||||
override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
return if (classSymbol in matchedClasses) setOf(MATERIALIZE_NAME) else emptySet()
|
||||
}
|
||||
|
||||
override fun getNestedClassifiersNames(classSymbol: FirClassSymbol<*>): Set<Name> {
|
||||
return if (classSymbol in matchedClasses) setOf(NESTED_NAME) else emptySet()
|
||||
}
|
||||
|
||||
object Key : FirPluginKey() {
|
||||
override fun toString(): String {
|
||||
return "AllOpenMembersGeneratorKey"
|
||||
}
|
||||
}
|
||||
|
||||
override val key: FirPluginKey
|
||||
get() = Key
|
||||
override val predicate: DeclarationPredicate
|
||||
get() = has("C".fqn())
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.fir.plugin.generators
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.containingClassForStaticMemberAttr
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildPrimaryConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.builder.buildSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
|
||||
import org.jetbrains.kotlin.fir.extensions.FirDeclarationGenerationExtension
|
||||
import org.jetbrains.kotlin.fir.moduleData
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.symbolProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
fun FirDeclarationGenerationExtension.buildMaterializeFunction(
|
||||
matchedClassSymbol: FirClassLikeSymbol<*>,
|
||||
callableId: CallableId
|
||||
): FirSimpleFunction {
|
||||
return buildSimpleFunction {
|
||||
moduleData = session.moduleData
|
||||
origin = key.origin
|
||||
status = FirResolvedDeclarationStatusImpl(
|
||||
Visibilities.Public,
|
||||
Modality.FINAL,
|
||||
EffectiveVisibility.Public
|
||||
)
|
||||
returnTypeRef = buildResolvedTypeRef {
|
||||
type = ConeClassLikeTypeImpl(
|
||||
matchedClassSymbol.toLookupTag(),
|
||||
emptyArray(),
|
||||
isNullable = false
|
||||
)
|
||||
}
|
||||
name = callableId.callableName
|
||||
symbol = FirNamedFunctionSymbol(callableId)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
fun FirDeclarationGenerationExtension.buildConstructor(classId: ClassId, callableId: CallableId, isInner: Boolean): FirConstructor {
|
||||
val lookupTag = ConeClassLikeLookupTagImpl(classId)
|
||||
return buildPrimaryConstructor {
|
||||
moduleData = session.moduleData
|
||||
origin = key.origin
|
||||
returnTypeRef = buildResolvedTypeRef {
|
||||
type = ConeClassLikeTypeImpl(
|
||||
lookupTag,
|
||||
emptyArray(),
|
||||
isNullable = false
|
||||
)
|
||||
}
|
||||
status = FirResolvedDeclarationStatusImpl(
|
||||
Visibilities.Public,
|
||||
Modality.FINAL,
|
||||
EffectiveVisibility.Public
|
||||
)
|
||||
symbol = FirConstructorSymbol(callableId)
|
||||
if (isInner) {
|
||||
dispatchReceiverType = callableId.classId?.let {
|
||||
val firClass = session.symbolProvider.getClassLikeSymbolByClassId(it)?.fir as? FirClass
|
||||
firClass?.defaultType()
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
it.containingClassForStaticMemberAttr = lookupTag
|
||||
}
|
||||
}
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
FILE: classWithGeneratedMembersAndNestedClass.kt
|
||||
@R|org/jetbrains/kotlin/fir/plugin/C|() public final class Foo : R|kotlin/Any| {
|
||||
public constructor(): R|Foo| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final class MyNested : R|kotlin/Any| {
|
||||
public constructor(): R|Foo.MyNested| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
public final class Bar : R|kotlin/Any| {
|
||||
public constructor(): R|Bar| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test_1(foo: R|Foo|): R|kotlin/Unit| {
|
||||
lval foo2: R|Foo| = R|<local>/foo|.R|/Foo.materialize|()
|
||||
lval nested: R|Foo.Nested| = Q|Foo|.R|/Foo.Nested|()
|
||||
}
|
||||
public final fun test_2(bar: R|Bar|): R|kotlin/Unit| {
|
||||
lval foo2: R|Bar| = R|<local>/bar|.<Unresolved name: materialize>#()
|
||||
lval nested: <ERROR TYPE REF: Unresolved name: Nested> = Q|Bar|.<Unresolved name: Nested>#()
|
||||
}
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
import org.jetbrains.kotlin.fir.plugin.C
|
||||
|
||||
@C
|
||||
class Foo {
|
||||
class MyNested
|
||||
}
|
||||
|
||||
class Bar
|
||||
|
||||
fun test_1(foo: Foo) {
|
||||
val foo2: Foo = foo.materialize()
|
||||
val nested = Foo.Nested()
|
||||
}
|
||||
|
||||
// should be errors
|
||||
fun test_2(bar: Bar) {
|
||||
val foo2: Bar = bar.<!UNRESOLVED_REFERENCE!>materialize<!>()
|
||||
val nested = Bar.<!UNRESOLVED_REFERENCE!>Nested<!>()
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
FILE: topLevelClass.kt
|
||||
@R|org/jetbrains/kotlin/fir/plugin/A|() public final class SomeClass : R|kotlin/Any| {
|
||||
public constructor(): R|SomeClass| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
Q|TopLevelSomeClass|.<Unresolved name: hello>#()
|
||||
}
|
||||
public final object TopLevelSomeClass {
|
||||
public final fun hello(): R|kotlin/Int|
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import org.jetbrains.kotlin.fir.plugin.A
|
||||
|
||||
@A
|
||||
class SomeClass
|
||||
|
||||
fun test() {
|
||||
TopLevelSomeClass.hello()
|
||||
}
|
||||
+6
-6
@@ -49,6 +49,12 @@ public class FirAllOpenDiagnosticTestGenerated extends AbstractFirAllOpenDiagnos
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("plugins/fir/fir-plugin-prototype/testData/memberGen"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("classWithGeneratedMembersAndNestedClass.kt")
|
||||
public void testClassWithGeneratedMembersAndNestedClass() throws Exception {
|
||||
runTest("plugins/fir/fir-plugin-prototype/testData/memberGen/classWithGeneratedMembersAndNestedClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("generatedClassWithMembersAndNestedClasses.kt")
|
||||
public void testGeneratedClassWithMembersAndNestedClasses() throws Exception {
|
||||
@@ -60,12 +66,6 @@ public class FirAllOpenDiagnosticTestGenerated extends AbstractFirAllOpenDiagnos
|
||||
public void testTopLevelCallables() throws Exception {
|
||||
runTest("plugins/fir/fir-plugin-prototype/testData/memberGen/topLevelCallables.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("topLevelClass.kt")
|
||||
public void testTopLevelClass() throws Exception {
|
||||
runTest("plugins/fir/fir-plugin-prototype/testData/memberGen/topLevelClass.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
Reference in New Issue
Block a user