Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added basic CheckedTypeAnnotation impl with compiler plugin check #240

Merged
merged 6 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ plugins {
alias(libs.plugins.conventions.kover)
alias(libs.plugins.conventions.gradle.doctor)
alias(libs.plugins.atomicfu)
id("build-util")
}

configureProjectReport()
Expand Down
1 change: 1 addition & 0 deletions compiler-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import util.whenForIde

plugins {
alias(libs.plugins.conventions.gradle.doctor)
id("build-util")
}

val rpcVersion: String = libs.versions.kotlinx.rpc.get()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.name.Name
object RpcClassId {
val remoteServiceInterface = ClassId(FqName("kotlinx.rpc"), Name.identifier("RemoteService"))
val rpcAnnotation = ClassId(FqName("kotlinx.rpc.annotations"), Name.identifier("Rpc"))
val checkedTypeAnnotation = ClassId(FqName("kotlinx.rpc.annotations"), Name.identifier("CheckedTypeAnnotation"))

val serializableAnnotation = ClassId(FqName("kotlinx.serialization"), Name.identifier("Serializable"))
val contextualAnnotation = ClassId(FqName("kotlinx.serialization"), Name.identifier("Contextual"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,32 @@

package kotlinx.rpc.codegen

import kotlinx.rpc.codegen.checkers.FirCheckedAnnotationHelper
import kotlinx.rpc.codegen.checkers.FirRpcDeclarationCheckers
import kotlinx.rpc.codegen.checkers.FirRpcExpressionCheckers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.extensions.FirAdditionalCheckersExtension
import org.jetbrains.kotlin.fir.caches.createCache
import org.jetbrains.kotlin.fir.caches.firCachesFactory
import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol

class FirRpcCheckers(session: FirSession) : FirAdditionalCheckersExtension(session) {
class FirRpcCheckers(session: FirSession, serializationIsPresent: Boolean) : FirAdditionalCheckersExtension(session) {
override fun FirDeclarationPredicateRegistrar.registerPredicates() {
register(FirRpcPredicates.rpc)
register(FirRpcPredicates.checkedAnnotationMeta)
}

override val declarationCheckers: DeclarationCheckers = FirRpcDeclarationCheckers
private val ctx = FirCheckersContext(session, serializationIsPresent)

override val declarationCheckers: DeclarationCheckers = FirRpcDeclarationCheckers(ctx)
override val expressionCheckers: ExpressionCheckers = FirRpcExpressionCheckers(ctx)
}

class FirCheckersContext(private val session: FirSession, val serializationIsPresent: Boolean) {
val typeParametersCache = session.firCachesFactory.createCache { typeParameter: FirTypeParameterSymbol ->
FirCheckedAnnotationHelper.checkedAnnotations(session, typeParameter)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package kotlinx.rpc.codegen

import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
Expand All @@ -16,8 +17,20 @@ class FirRpcExtensionRegistrar(private val configuration: CompilerConfiguration)
override fun ExtensionRegistrarContext.configurePlugin() {
val logger = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)

+CFactory { FirRpcCheckers(it) }
+GFactory { FirRpcServiceGenerator(it, logger) }
val serializationIsPresent = try {
Class.forName("org.jetbrains.kotlinx.serialization.compiler.fir.SerializationFirResolveExtension")
+GFactory { FirRpcServiceGenerator(it, logger) }
true
} catch (_ : ClassNotFoundException) {
logger.report(
severity = CompilerMessageSeverity.INFO,
message = "Serialization plugin is not found, so generated services are not available",
)
false
}

+CFactory { FirRpcCheckers(it, serializationIsPresent) }

+SFactory { FirRpcSupertypeGenerator(it, logger) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ object FirRpcPredicates {
internal val rpc = DeclarationPredicate.create {
annotated(RpcClassId.rpcAnnotation.asSingleFqName()) // @Rpc
}

internal val checkedAnnotationMeta = DeclarationPredicate.create {
metaAnnotated(RpcClassId.checkedTypeAnnotation.asSingleFqName(), includeItself = false)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,10 @@ class FirRpcServiceGenerator(
@Suppress("unused")
private val logger: MessageCollector,
) : FirDeclarationGenerationExtension(session) {
private val serializationExtension = SerializationFirResolveExtension(session)
private val serializationExtension by lazy {
SerializationFirResolveExtension(session)
}

private val isJvmOrMetadata = !session.moduleData.platform.run { isJs() || isWasm() || isNative() }

override fun FirDeclarationPredicateRegistrar.registerPredicates() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
package kotlinx.rpc.codegen

import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeRef
Expand All @@ -16,10 +18,20 @@ interface FirVersionSpecificApi {
delegatedTypeRef: FirTypeRef? = null,
): FirResolvedTypeRef

fun ConeKotlinType.toClassSymbolVS(
session: FirSession,
): FirClassSymbol<*>?

var FirResolvedTypeRefBuilder.coneTypeVS: ConeKotlinType
}

fun <T> vsApi(body: FirVersionSpecificApi.() -> T) : T {
val klass = Class.forName("kotlinx.rpc.codegen.FirVersionSpecificApiImpl")
return (klass.kotlin.objectInstance as FirVersionSpecificApi).body()
val vsApiClass by lazy {
runCatching {
Class.forName("kotlinx.rpc.codegen.FirVersionSpecificApiImpl")
}.getOrNull()
}

inline fun <T> vsApi(body: FirVersionSpecificApi.() -> T): T {
val kClass = vsApiClass?.kotlin ?: error("FirVersionSpecificApi is not present")
return (kClass.objectInstance as FirVersionSpecificApi).body()
}
Loading