From 031dbf883459512b3fc20943de1a9e6c0c982c9c Mon Sep 17 00:00:00 2001 From: Yang Date: Fri, 26 Jun 2026 09:16:12 +1000 Subject: [PATCH 1/2] RouteBinding - move class generation to IR, re-enable Metro's `generateClassesInIr`. --- .../gradle/internal/metroBuildLogic.kt | 1 - .../routebinding/compiler/ClassIds.kt | 3 - .../fir/RouteBindingClassIdGenerator.kt | 17 -- .../fir/RouteBindingContributionExtension.kt | 67 ------ ...teBindingDeclarationGenerationExtension.kt | 206 ------------------ .../compiler/fir/RouteBindingKeys.kt | 9 - ...ormer.kt => RouteBindingClassGenerator.kt} | 124 ++++++++--- .../ir/RouteBindingIrGenerationExtension.kt | 50 +++-- .../compiler/ir/RouteBindingOrigins.kt | 14 -- .../compiler/ir/symbols/MetroSymbols.kt | 44 ++++ .../ir/symbols/RouteBindingSymbols.kt | 32 +++ ...api.fir.MetroContributionExtension$Factory | 1 - ...oFirDeclarationGenerationExtension$Factory | 1 - .../data/dump/NoReceiverAndParams.fir.txt | 37 ---- .../test/data/dump/NoReceiverAndParams.kt.txt | 63 +++--- .../src/test/data/dump/Standard.fir.txt | 37 ---- .../src/test/data/dump/Standard.kt.txt | 65 +++--- .../data/dump/WithBackStackParamOnly.fir.txt | 37 ---- .../data/dump/WithBackStackParamOnly.kt.txt | 63 +++--- .../data/dump/WithMetadataProvider.fir.txt | 47 ---- .../data/dump/WithMetadataProvider.kt.txt | 65 +++--- .../dump/WithParamWithDefaultValue.fir.txt | 37 ---- .../dump/WithParamWithDefaultValue.kt.txt | 65 +++--- .../test/data/dump/WithRouteParamOnly.fir.txt | 37 ---- .../test/data/dump/WithRouteParamOnly.kt.txt | 63 +++--- ...haredTransitionScopeAsContextParam.fir.txt | 38 ---- ...SharedTransitionScopeAsContextParam.kt.txt | 65 +++--- ...hSharedTransitionScopeAsValueParam.fir.txt | 37 ---- ...thSharedTransitionScopeAsValueParam.kt.txt | 65 +++--- .../routebinding/compiler/AbstractDumpTest.kt | 2 - ...teBindingExtensionRegistrarConfigurator.kt | 9 +- .../gradle/RouteBindingGradlePlugin.kt | 3 +- 32 files changed, 474 insertions(+), 930 deletions(-) delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingClassIdGenerator.kt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingContributionExtension.kt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingDeclarationGenerationExtension.kt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingKeys.kt rename build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/{RouteBindingClassTransformer.kt => RouteBindingClassGenerator.kt} (56%) delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingOrigins.kt create mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/symbols/MetroSymbols.kt create mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/symbols/RouteBindingSymbols.kt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.api.fir.MetroContributionExtension$Factory delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.api.fir.MetroFirDeclarationGenerationExtension$Factory delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/NoReceiverAndParams.fir.txt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/Standard.fir.txt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithBackStackParamOnly.fir.txt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithMetadataProvider.fir.txt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithParamWithDefaultValue.fir.txt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithRouteParamOnly.fir.txt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsContextParam.fir.txt delete mode 100644 build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsValueParam.fir.txt diff --git a/build-logic/kstreamlined-build-plugin/src/main/kotlin/io/github/reactivecircus/kstreamlined/gradle/internal/metroBuildLogic.kt b/build-logic/kstreamlined-build-plugin/src/main/kotlin/io/github/reactivecircus/kstreamlined/gradle/internal/metroBuildLogic.kt index 7164fa83..8a036bcf 100644 --- a/build-logic/kstreamlined-build-plugin/src/main/kotlin/io/github/reactivecircus/kstreamlined/gradle/internal/metroBuildLogic.kt +++ b/build-logic/kstreamlined-build-plugin/src/main/kotlin/io/github/reactivecircus/kstreamlined/gradle/internal/metroBuildLogic.kt @@ -25,7 +25,6 @@ internal fun Project.configureMetro() { extensions.configure(MetroPluginExtension::class.java) { it.generateContributionProviders.set(true) @OptIn(ExperimentalMetroGradleApi::class) - it.generateClassesInIr.set(false) // TODO re-enable once supported by RouteBinding if (providers.gradleProperty("enableMetroCompilerReports").orNull == "true") { it.reportsDestination.set(layout.buildDirectory.dir("metro_reports")) } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ClassIds.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ClassIds.kt index 99b01813..344530ee 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ClassIds.kt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ClassIds.kt @@ -6,9 +6,6 @@ internal object ClassIds { object RouteBinding { val Annotation = ClassId.fromString("io/github/reactivecircus/routebinding/runtime/RouteBinding") val NavEntryInstaller = ClassId.fromString("io/github/reactivecircus/routebinding/runtime/NavEntryInstaller") - val RouteMetadataProvider = ClassId.fromString( - "io/github/reactivecircus/routebinding/runtime/RouteMetadataProvider", - ) } object Compose { diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingClassIdGenerator.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingClassIdGenerator.kt deleted file mode 100644 index bce78f67..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingClassIdGenerator.kt +++ /dev/null @@ -1,17 +0,0 @@ -package io.github.reactivecircus.routebinding.compiler.fir - -import io.github.reactivecircus.routebinding.compiler.ClassIds -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.Name - -/** - * Generates [ClassId] of the NavEntryInstaller class to be generated for the given source function - * annotated with `@Routebinding`. - */ -internal fun generateNavEntryInstallerClassId(sourceFunction: FirNamedFunctionSymbol): ClassId { - val packageFqName = sourceFunction.callableId.packageName - val classNameSuffix = ClassIds.RouteBinding.NavEntryInstaller.shortClassName.asString() - val className = Name.identifier("${sourceFunction.name.asString()}_$classNameSuffix") - return ClassId(packageFqName, className) -} diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingContributionExtension.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingContributionExtension.kt deleted file mode 100644 index 6a81470c..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingContributionExtension.kt +++ /dev/null @@ -1,67 +0,0 @@ -package io.github.reactivecircus.routebinding.compiler.fir - -import dev.zacsweers.metro.compiler.MetroOptions -import dev.zacsweers.metro.compiler.api.fir.MetroContributionExtension -import dev.zacsweers.metro.compiler.api.fir.MetroContributions -import dev.zacsweers.metro.compiler.compat.CompatContext -import dev.zacsweers.metro.compiler.fir.MetroFirTypeResolver -import io.github.reactivecircus.routebinding.compiler.ClassIds -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar -import org.jetbrains.kotlin.fir.extensions.predicate.LookupPredicate -import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider -import org.jetbrains.kotlin.fir.resolve.defaultType -import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol -import org.jetbrains.kotlin.name.ClassId - -internal class RouteBindingContributionExtension( - private val session: FirSession, -) : MetroContributionExtension { - private val hasRouteBindingAnnotation = LookupPredicate.BuilderContext.annotated( - ClassIds.RouteBinding.Annotation.asSingleFqName(), - ) - - private val navEntryInstallerClassIds: List by lazy { - session.predicateBasedProvider - .getSymbolsByPredicate(hasRouteBindingAnnotation) - .filterIsInstance() - .map { generateNavEntryInstallerClassId(it) } - } - - override fun FirDeclarationPredicateRegistrar.registerPredicates() { - register(hasRouteBindingAnnotation) - } - - override fun getContributions( - scopeClassId: ClassId, - typeResolverFactory: MetroFirTypeResolver.Factory, - ): List { - if (scopeClassId != ClassIds.Metro.AppScope) return emptyList() - return navEntryInstallerClassIds.mapNotNull { classId -> - val metroContributionClassId = MetroContributions.metroContributionClassId( - contributingClassId = classId, - scopeClassId = scopeClassId, - ) - - val metroContributionSymbol = session.symbolProvider - .getClassLikeSymbolByClassId(metroContributionClassId) as? FirRegularClassSymbol - ?: return@mapNotNull null - - MetroContributionExtension.Contribution( - supertype = metroContributionSymbol.defaultType(), - replaces = emptyList(), - originClassId = classId, - ) - } - } - - internal class Factory : MetroContributionExtension.Factory { - override fun create( - session: FirSession, - options: MetroOptions, - compatContext: CompatContext, - ): MetroContributionExtension = RouteBindingContributionExtension(session) - } -} diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingDeclarationGenerationExtension.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingDeclarationGenerationExtension.kt deleted file mode 100644 index 78dd59f5..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingDeclarationGenerationExtension.kt +++ /dev/null @@ -1,206 +0,0 @@ -package io.github.reactivecircus.routebinding.compiler.fir - -import dev.zacsweers.metro.compiler.MetroOptions -import dev.zacsweers.metro.compiler.api.fir.MetroContributionHintExtension -import dev.zacsweers.metro.compiler.api.fir.MetroFirDeclarationGenerationExtension -import dev.zacsweers.metro.compiler.compat.CompatContext -import io.github.reactivecircus.routebinding.compiler.ClassIds -import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.declarations.declaredFunctions -import org.jetbrains.kotlin.fir.declarations.getDeprecationsProvider -import org.jetbrains.kotlin.fir.deserialization.toQualifiedPropertyAccessExpression -import org.jetbrains.kotlin.fir.expressions.FirAnnotation -import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotation -import org.jetbrains.kotlin.fir.expressions.builder.buildAnnotationArgumentMapping -import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList -import org.jetbrains.kotlin.fir.expressions.builder.buildEnumEntryDeserializedAccessExpression -import org.jetbrains.kotlin.fir.expressions.builder.buildGetClassCall -import org.jetbrains.kotlin.fir.expressions.builder.buildLiteralExpression -import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier -import org.jetbrains.kotlin.fir.extensions.ExperimentalTopLevelDeclarationsGenerationApi -import org.jetbrains.kotlin.fir.extensions.FirDeclarationPredicateRegistrar -import org.jetbrains.kotlin.fir.extensions.MemberGenerationContext -import org.jetbrains.kotlin.fir.extensions.predicate.LookupPredicate -import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider -import org.jetbrains.kotlin.fir.plugin.createConstructor -import org.jetbrains.kotlin.fir.plugin.createMemberFunction -import org.jetbrains.kotlin.fir.plugin.createTopLevelClass -import org.jetbrains.kotlin.fir.resolve.defaultType -import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider -import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol -import org.jetbrains.kotlin.fir.toFirResolvedTypeRef -import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef -import org.jetbrains.kotlin.fir.types.constructClassLikeType -import org.jetbrains.kotlin.name.CallableId -import org.jetbrains.kotlin.name.ClassId -import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.name.SpecialNames -import org.jetbrains.kotlin.name.StandardClassIds -import org.jetbrains.kotlin.types.ConstantValueKind - -internal class RouteBindingDeclarationGenerationExtension( - session: FirSession, -) : MetroFirDeclarationGenerationExtension(session), MetroContributionHintExtension { - private val hasRouteBindingAnnotation = LookupPredicate.BuilderContext.annotated( - ClassIds.RouteBinding.Annotation.asSingleFqName(), - ) - - private val sourceFunctions: List by lazy { - session.predicateBasedProvider - .getSymbolsByPredicate(hasRouteBindingAnnotation) - .filterIsInstance() - } - - private val navEntryInstallerClassIds: List by lazy { - sourceFunctions.map { generateNavEntryInstallerClassId(it) } - } - - private val installFunctionName = Name.identifier("install") - - override fun FirDeclarationPredicateRegistrar.registerPredicates() { - register(hasRouteBindingAnnotation) - } - - override fun getContributionHints(): List { - return navEntryInstallerClassIds.map { classId -> - MetroContributionHintExtension.ContributionHint( - contributingClassId = classId, - scope = ClassIds.Metro.AppScope, - ) - } - } - - @ExperimentalTopLevelDeclarationsGenerationApi - override fun getTopLevelClassIds(): Set = navEntryInstallerClassIds.toSet() - - @ExperimentalTopLevelDeclarationsGenerationApi - override fun generateTopLevelClassLikeDeclaration(classId: ClassId): FirClassLikeSymbol<*> { - return createTopLevelClass( - classId = classId, - key = RouteBindingKeys.NavEntryInstallerClassDeclaration, - ) { - val navEntryInstallerSymbol = session.symbolProvider - .getClassLikeSymbolByClassId(ClassIds.RouteBinding.NavEntryInstaller) as FirRegularClassSymbol - superType(navEntryInstallerSymbol.defaultType().toFirResolvedTypeRef().coneType) - }.apply { - replaceAnnotations(annotations + buildDeprecatedHiddenAnnotation() + buildContributesIntoSetAnnotation()) - replaceDeprecationsProvider(getDeprecationsProvider(session)) - }.symbol - } - - private fun buildContributesIntoSetAnnotation(): FirAnnotation = buildAnnotation { - val contributesIntoSetSymbol = session.symbolProvider - .getClassLikeSymbolByClassId(ClassIds.Metro.ContributesIntoSet) as FirRegularClassSymbol - annotationTypeRef = buildResolvedTypeRef { - coneType = contributesIntoSetSymbol.defaultType().toFirResolvedTypeRef().coneType - } - argumentMapping = buildAnnotationArgumentMapping { - mapping[Name.identifier("scope")] = buildGetClassCall { - val appScopeSymbol = session.symbolProvider - .getClassLikeSymbolByClassId(ClassIds.Metro.AppScope) as FirRegularClassSymbol - val appScopeConeType = appScopeSymbol.classId.constructClassLikeType() - val kClassSymbol = session.symbolProvider - .getClassLikeSymbolByClassId(StandardClassIds.KClass) as FirRegularClassSymbol - val kClassType = kClassSymbol.classId.constructClassLikeType(arrayOf(appScopeConeType)) - coneTypeOrNull = kClassType - argumentList = buildArgumentList { - arguments += buildResolvedQualifier { - coneTypeOrNull = appScopeConeType - symbol = appScopeSymbol - packageFqName = ClassIds.Metro.AppScope.packageFqName - relativeClassFqName = ClassIds.Metro.AppScope.relativeClassName - resolvedToCompanionObject = false - isFullyQualified = true - } - } - } - } - } - - override fun getCallableNamesForClass(classSymbol: FirClassSymbol<*>, context: MemberGenerationContext): Set { - val classSymbol = context.owner - if (navEntryInstallerClassIds.none { it == classSymbol.classId }) return emptySet() - return setOf(SpecialNames.INIT, installFunctionName) - } - - override fun generateConstructors(context: MemberGenerationContext): List { - val classSymbol = context.owner - if (navEntryInstallerClassIds.none { it == classSymbol.classId }) return emptyList() - return listOf( - createConstructor( - owner = classSymbol, - key = RouteBindingKeys.NavEntryInstallerClassDeclaration, - isPrimary = true, - generateDelegatedNoArgConstructorCall = true, - ).symbol, - ) - } - - override fun generateFunctions( - callableId: CallableId, - context: MemberGenerationContext?, - ): List { - val classSymbol = context?.owner ?: return emptyList() - return when { - navEntryInstallerClassIds.none { it == classSymbol.classId } -> emptyList() - callableId.callableName != installFunctionName -> emptyList() - else -> listOf(generateInstallFunction(classSymbol)) - } - } - - private fun generateInstallFunction(classSymbol: FirClassSymbol<*>): FirNamedFunctionSymbol { - val navEntryInstallerSymbol = session.symbolProvider - .getClassLikeSymbolByClassId(ClassIds.RouteBinding.NavEntryInstaller) as FirRegularClassSymbol - val installFunctionSymbol = navEntryInstallerSymbol.declaredFunctions(session) - .first { it.name == installFunctionName } - - return createMemberFunction( - owner = classSymbol, - key = RouteBindingKeys.InstallFunctionDeclaration, - name = installFunctionName, - returnType = installFunctionSymbol.resolvedReturnType, - ) { - installFunctionSymbol.contextParameterSymbols.forEach { - contextReceiver(it.resolvedReturnType) - } - installFunctionSymbol.valueParameterSymbols.forEach { - valueParameter(it.name, it.resolvedReturnType) - } - status { - isOverride = true - } - }.symbol - } - - private fun buildDeprecatedHiddenAnnotation(): FirAnnotation = buildAnnotation { - val deprecatedAnnotation = session.symbolProvider - .getClassLikeSymbolByClassId(StandardClassIds.Annotations.Deprecated) as FirRegularClassSymbol - - annotationTypeRef = deprecatedAnnotation.defaultType().toFirResolvedTypeRef() - argumentMapping = buildAnnotationArgumentMapping { - mapping[Name.identifier("message")] = buildLiteralExpression( - source = null, - kind = ConstantValueKind.String, - value = "This synthesized declaration should not be used directly", - setType = true, - ) - mapping[Name.identifier("level")] = - buildEnumEntryDeserializedAccessExpression { - enumClassId = StandardClassIds.DeprecationLevel - enumEntryName = Name.identifier("HIDDEN") - }.toQualifiedPropertyAccessExpression(session) - } - } - - internal class Factory : MetroFirDeclarationGenerationExtension.Factory { - override fun create( - session: FirSession, - options: MetroOptions, - compatContext: CompatContext, - ): MetroFirDeclarationGenerationExtension = RouteBindingDeclarationGenerationExtension(session) - } -} diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingKeys.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingKeys.kt deleted file mode 100644 index 61e75fe5..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/fir/RouteBindingKeys.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.reactivecircus.routebinding.compiler.fir - -import org.jetbrains.kotlin.GeneratedDeclarationKey - -internal object RouteBindingKeys { - data object NavEntryInstallerClassDeclaration : GeneratedDeclarationKey() - - data object InstallFunctionDeclaration : GeneratedDeclarationKey() -} diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingClassTransformer.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingClassGenerator.kt similarity index 56% rename from build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingClassTransformer.kt rename to build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingClassGenerator.kt index 12e3ebe3..a937faa2 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingClassTransformer.kt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingClassGenerator.kt @@ -1,87 +1,147 @@ package io.github.reactivecircus.routebinding.compiler.ir import io.github.reactivecircus.routebinding.compiler.ClassIds +import io.github.reactivecircus.routebinding.compiler.ir.symbols.MetroSymbols import io.github.reactivecircus.routebinding.compiler.ir.symbols.Nav3Symbols -import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import io.github.reactivecircus.routebinding.compiler.ir.symbols.RouteBindingSymbols import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder import org.jetbrains.kotlin.descriptors.DescriptorVisibilities -import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.builders.IrBlockBodyBuilder +import org.jetbrains.kotlin.ir.builders.declarations.addFunction import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter +import org.jetbrains.kotlin.ir.builders.declarations.buildClass import org.jetbrains.kotlin.ir.builders.declarations.buildFun import org.jetbrains.kotlin.ir.builders.irBlockBody import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irCallWithSubstitutedType -import org.jetbrains.kotlin.ir.builders.irDelegatingConstructorCall import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.builders.irGetObject import org.jetbrains.kotlin.ir.declarations.IrClass import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.expressions.IrAnnotation import org.jetbrains.kotlin.ir.expressions.IrClassReference import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin +import org.jetbrains.kotlin.ir.expressions.impl.IrAnnotationImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrClassReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl +import org.jetbrains.kotlin.ir.expressions.impl.fromSymbolOwner import org.jetbrains.kotlin.ir.interpreter.getAnnotation import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrTypeSubstitutor import org.jetbrains.kotlin.ir.types.defaultType import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.types.typeWith +import org.jetbrains.kotlin.ir.util.addChild +import org.jetbrains.kotlin.ir.util.addSimpleDelegatingConstructor import org.jetbrains.kotlin.ir.util.classId -import org.jetbrains.kotlin.ir.util.classIdOrFail import org.jetbrains.kotlin.ir.util.constructors +import org.jetbrains.kotlin.ir.util.copyParametersFrom +import org.jetbrains.kotlin.ir.util.createThisReceiverParameter +import org.jetbrains.kotlin.ir.util.defaultType +import org.jetbrains.kotlin.ir.util.file import org.jetbrains.kotlin.ir.util.functions -import org.jetbrains.kotlin.ir.util.getPackageFragment import org.jetbrains.kotlin.ir.util.hasDefaultValue -import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.ir.util.primaryConstructor import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.types.Variance -internal class RouteBindingClassTransformer( +/** + * Generates a class that implements `NavEntryInstaller` for each `@RouteBinding`-annotated source function. + * The class is annotated with `@ContributesIntoSet(scope = AppScope::class)`, + * the overridden `install` function invokes the source `@RouteBinding`-annotated function. + */ +internal class RouteBindingClassGenerator( private val pluginContext: IrPluginContext, + private val metroSymbols: MetroSymbols, private val nav3Symbols: Nav3Symbols, - routeBindingFunctions: Sequence, -) : IrElementTransformerVoidWithContext() { - // generated NavEntryInstaller class -> source function mappings - private val sourceFunctionsMap: Map = routeBindingFunctions - .associateBy { function -> - val classNameSuffix = ClassIds.RouteBinding.NavEntryInstaller.shortClassName.asString() - ClassId( - function.getPackageFragment().packageFqName, - Name.identifier("${function.name.asString()}_$classNameSuffix"), - ) - } + routeBindingSymbols: RouteBindingSymbols, +) { + private val navEntryInstallerSymbol = routeBindingSymbols.navEntryInstallInterface + + private val installFunction: IrSimpleFunction = navEntryInstallerSymbol.owner.functions + .single { it.name.asString() == "install" } - override fun visitClassNew(declaration: IrClass): IrStatement { - if (declaration.origin == RouteBindingOrigins.NavEntryInstallerClassDeclaration) { - val sourceFunction = sourceFunctionsMap.getValue(declaration.classIdOrFail) - transformNavEntryInstallerClass(irClass = declaration, sourceFunction = sourceFunction) + fun generate(sourceFunction: IrSimpleFunction) { + val irClass = pluginContext.irFactory.buildClass { + startOffset = UNDEFINED_OFFSET + endOffset = UNDEFINED_OFFSET + name = Name.identifier("${sourceFunction.name.asString()}_NavEntryInstaller") + visibility = DescriptorVisibilities.PUBLIC + }.apply { + createThisReceiverParameter() + superTypes = listOf(navEntryInstallerSymbol.owner.defaultType) + annotations = listOf(buildContributesIntoSetAnnotation()) } - return super.visitClassNew(declaration) + + sourceFunction.file.addChild(irClass) + pluginContext.metadataDeclarationRegistrar.registerClassAsMetadataVisible(irClass) + + addPrimaryConstructor(irClass) + addInstallFunction(irClass, sourceFunction) } - private fun transformNavEntryInstallerClass(irClass: IrClass, sourceFunction: IrSimpleFunction) { - irClass.constructors.forEach { constructor -> - constructor.body = DeclarationIrBuilder(pluginContext, constructor.symbol).irBlockBody { - +irDelegatingConstructorCall(pluginContext.irBuiltIns.anyClass.owner.constructors.single()) - } + /** + * Builds the `@ContributesIntoSet(scope = AppScope::class)` annotation. + */ + private fun buildContributesIntoSetAnnotation(): IrAnnotation { + val contributesIntoSetCtor = metroSymbols.contributesIntoSetClass.constructors.single() + val appScopeSymbol = metroSymbols.appScopeClass + val annotationType = contributesIntoSetCtor.owner.parentAsClass.defaultType + val appScopeKClassType = pluginContext.irBuiltIns.kClassClass.typeWith(appScopeSymbol.owner.defaultType) + return IrAnnotationImpl.fromSymbolOwner( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + type = annotationType, + constructorSymbol = contributesIntoSetCtor, + ).apply { + // ContributesIntoSet(scope = AppScope::class, ...); remaining params have defaults. + arguments[0] = IrClassReferenceImpl( + startOffset = UNDEFINED_OFFSET, + endOffset = UNDEFINED_OFFSET, + type = appScopeKClassType, + symbol = appScopeSymbol, + classType = appScopeSymbol.owner.defaultType, + ) } + } - val installFunction = irClass.functions.first { - it.origin == RouteBindingOrigins.InstallFunction + private fun addPrimaryConstructor(irClass: IrClass) { + val anyConstructor = pluginContext.irBuiltIns.anyClass.owner.primaryConstructor!! + val constructor = irClass.addSimpleDelegatingConstructor( + superConstructor = anyConstructor, + irBuiltIns = pluginContext.irBuiltIns, + isPrimary = true, + ).apply { + visibility = DescriptorVisibilities.PRIVATE } + pluginContext.metadataDeclarationRegistrar.registerConstructorAsMetadataVisible(constructor) + } - installFunction.body = DeclarationIrBuilder(pluginContext, installFunction.symbol).irBlockBody { + private fun addInstallFunction(irClass: IrClass, sourceFunction: IrSimpleFunction) { + val function = irClass.addFunction { + startOffset = UNDEFINED_OFFSET + endOffset = UNDEFINED_OFFSET + name = installFunction.name + returnType = installFunction.returnType + visibility = DescriptorVisibilities.PUBLIC + } + function.copyParametersFrom(installFunction) + function.overriddenSymbols = listOf(installFunction.symbol) + function.body = DeclarationIrBuilder(pluginContext, function.symbol).irBlockBody { createInstallFunctionBody( sourceFunction = sourceFunction, - installFunction = installFunction, + installFunction = function, ) } + pluginContext.metadataDeclarationRegistrar.registerFunctionAsMetadataVisible(function) } private fun IrBlockBodyBuilder.createInstallFunctionBody( diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingIrGenerationExtension.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingIrGenerationExtension.kt index 86307721..bcecc496 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingIrGenerationExtension.kt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingIrGenerationExtension.kt @@ -1,7 +1,9 @@ package io.github.reactivecircus.routebinding.compiler.ir import io.github.reactivecircus.routebinding.compiler.ClassIds +import io.github.reactivecircus.routebinding.compiler.ir.symbols.MetroSymbols import io.github.reactivecircus.routebinding.compiler.ir.symbols.Nav3Symbols +import io.github.reactivecircus.routebinding.compiler.ir.symbols.RouteBindingSymbols import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext import org.jetbrains.kotlin.cli.common.messages.MessageCollector @@ -13,26 +15,40 @@ internal class RouteBindingIrGenerationExtension( private val messageCollector: MessageCollector, ) : IrGenerationExtension { override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) { - val routeBindingFunctions = moduleFragment.files.asSequence() + moduleFragment.files .flatMap { it.declarations } .filterIsInstance() .filter { it.hasAnnotation(ClassIds.RouteBinding.Annotation) } - if (routeBindingFunctions.none()) return + .let { routeBindingFunctions -> + if (routeBindingFunctions.isEmpty()) return + val metroSymbols = MetroSymbols.create( + pluginContext, + messageCollector, + contributesIntoSetClassId = ClassIds.Metro.ContributesIntoSet, + appScopeClassId = ClassIds.Metro.AppScope, + ) + val nav3Symbols = Nav3Symbols.create( + pluginContext, + messageCollector, + entryProviderScopeClassId = ClassIds.Nav3.EntryProviderScope, + ) + val routeBindingSymbols = RouteBindingSymbols.create( + pluginContext, + messageCollector, + navEntryInstallerClassId = ClassIds.RouteBinding.NavEntryInstaller, + ) + if (metroSymbols == null || nav3Symbols == null || routeBindingSymbols == null) return - val nav3Symbols = Nav3Symbols.create( - pluginContext, - messageCollector, - entryProviderScopeClassId = ClassIds.Nav3.EntryProviderScope, - ) - if (nav3Symbols == null) return - - moduleFragment.transform( - RouteBindingClassTransformer( - pluginContext, - nav3Symbols, - routeBindingFunctions, - ), - null, - ) + // Generate the NavEntryInstaller class for each `@RouteBinding`-annotated source function. + val generator = RouteBindingClassGenerator( + pluginContext, + metroSymbols, + nav3Symbols, + routeBindingSymbols, + ) + for (sourceFunction in routeBindingFunctions) { + generator.generate(sourceFunction) + } + } } } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingOrigins.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingOrigins.kt deleted file mode 100644 index 96172e1c..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingOrigins.kt +++ /dev/null @@ -1,14 +0,0 @@ -package io.github.reactivecircus.routebinding.compiler.ir - -import io.github.reactivecircus.routebinding.compiler.fir.RouteBindingKeys -import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin - -internal object RouteBindingOrigins { - val NavEntryInstallerClassDeclaration: IrDeclarationOrigin = IrDeclarationOrigin.GeneratedByPlugin( - RouteBindingKeys.NavEntryInstallerClassDeclaration, - ) - - val InstallFunction: IrDeclarationOrigin = IrDeclarationOrigin.GeneratedByPlugin( - RouteBindingKeys.InstallFunctionDeclaration, - ) -} diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/symbols/MetroSymbols.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/symbols/MetroSymbols.kt new file mode 100644 index 00000000..433b2dea --- /dev/null +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/symbols/MetroSymbols.kt @@ -0,0 +1,44 @@ +package io.github.reactivecircus.routebinding.compiler.ir.symbols + +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.name.ClassId + +internal class MetroSymbols private constructor( + val contributesIntoSetClass: IrClassSymbol, + val appScopeClass: IrClassSymbol, +) { + companion object { + fun create( + pluginContext: IrPluginContext, + messageCollector: MessageCollector, + contributesIntoSetClassId: ClassId, + appScopeClassId: ClassId, + ): MetroSymbols? { + val contributesIntoSetClass = pluginContext.finderForBuiltins().findClass(contributesIntoSetClassId) + if (contributesIntoSetClass == null) { + messageCollector.report( + CompilerMessageSeverity.ERROR, + "Could not find class <$contributesIntoSetClassId>.", + ) + return null + } + + val appScopeClass = pluginContext.finderForBuiltins().findClass(appScopeClassId) + if (appScopeClass == null) { + messageCollector.report( + CompilerMessageSeverity.ERROR, + "Could not find class <$appScopeClassId>.", + ) + return null + } + + return MetroSymbols( + contributesIntoSetClass = contributesIntoSetClass, + appScopeClass = appScopeClass, + ) + } + } +} diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/symbols/RouteBindingSymbols.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/symbols/RouteBindingSymbols.kt new file mode 100644 index 00000000..10063afe --- /dev/null +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/symbols/RouteBindingSymbols.kt @@ -0,0 +1,32 @@ +package io.github.reactivecircus.routebinding.compiler.ir.symbols + +import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +import org.jetbrains.kotlin.cli.common.messages.MessageCollector +import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.name.ClassId + +internal class RouteBindingSymbols private constructor( + val navEntryInstallInterface: IrClassSymbol, +) { + companion object { + fun create( + pluginContext: IrPluginContext, + messageCollector: MessageCollector, + navEntryInstallerClassId: ClassId, + ): RouteBindingSymbols? { + val navEntryInstallInterface = pluginContext.finderForBuiltins().findClass(navEntryInstallerClassId) + if (navEntryInstallInterface == null) { + messageCollector.report( + CompilerMessageSeverity.ERROR, + "Could not find interface <$navEntryInstallerClassId>.", + ) + return null + } + + return RouteBindingSymbols( + navEntryInstallInterface = navEntryInstallInterface, + ) + } + } +} diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.api.fir.MetroContributionExtension$Factory b/build-logic/routebinding/routebinding-compiler-plugin/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.api.fir.MetroContributionExtension$Factory deleted file mode 100644 index 3e18a834..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.api.fir.MetroContributionExtension$Factory +++ /dev/null @@ -1 +0,0 @@ -io.github.reactivecircus.routebinding.compiler.fir.RouteBindingContributionExtension$Factory diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.api.fir.MetroFirDeclarationGenerationExtension$Factory b/build-logic/routebinding/routebinding-compiler-plugin/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.api.fir.MetroFirDeclarationGenerationExtension$Factory deleted file mode 100644 index 01d40491..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.api.fir.MetroFirDeclarationGenerationExtension$Factory +++ /dev/null @@ -1 +0,0 @@ -io.github.reactivecircus.routebinding.compiler.fir.RouteBindingDeclarationGenerationExtension$Factory diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/NoReceiverAndParams.fir.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/NoReceiverAndParams.fir.txt deleted file mode 100644 index c9d86180..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/NoReceiverAndParams.fir.txt +++ /dev/null @@ -1,37 +0,0 @@ -FILE: NoReceiverAndParams.kt - @R|io/github/reactivecircus/routebinding/runtime/RouteBinding|(route = (Q|DummyRoute|) [evaluated = (Q|DummyRoute|)]) @R|androidx/compose/runtime/Composable|() internal final fun FooScreen(): R|kotlin/Unit| { - } - public final fun box(): R|kotlin/String| { - ^box String(OK) - } -FILE: /FooScreen_NavEntryInstaller.kt - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/ContributesIntoSet|(scope = (Q|dev/zacsweers/metro/AppScope|)) public final class FooScreen_NavEntryInstaller : R|io/github/reactivecircus/routebinding/runtime/NavEntryInstaller| { - context(: R|androidx/navigation3/runtime/EntryProviderScope|, : R|androidx/compose/animation/SharedTransitionScope|) - public final override fun install(backStack: R|androidx/navigation3/runtime/NavBackStack|): R|kotlin/Unit| - - public constructor(): R|FooScreen_NavEntryInstaller| { - super() - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final object MetroFactory : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroFactory| { - super() - } - - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroContribution|(scope = (Q|dev/zacsweers/metro/AppScope|)) @R|dev/zacsweers/metro/BindingContainer|() @R|dev/zacsweers/metro/Origin|(value = (Q|FooScreen_NavEntryInstaller|)) @R|dev/zacsweers/metro/internal/ComptimeOnly|() public abstract interface MetroContributionToDevzacsweersmetroappScopeocf15 : R|kotlin/Any| { - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public abstract class BindsMirror : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroContributionToDevzacsweersmetroappScopeocf15.BindsMirror| { - super() - } - - } - - } - - } -FILE: metro/hints/fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt - package metro.hints - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final fun dev_zacsweers_metro_AppScope(contributed: R|FooScreen_NavEntryInstaller|): R|kotlin/Unit| diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/NoReceiverAndParams.kt.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/NoReceiverAndParams.kt.txt index 83a20e72..e6b3ff84 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/NoReceiverAndParams.kt.txt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/NoReceiverAndParams.kt.txt @@ -1,33 +1,43 @@ -// FILE: FooScreen_NavEntryInstaller.kt +// FILE: NoReceiverAndParams.kt -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ContributesIntoSet(scope = AppScope::class) class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) - object MetroFactory : Factory { - private constructor() /* primary */ { - super/*Any*/() - /* () */ + class MetroFactory : Factory { + @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) + companion object Companion { + private constructor() /* primary */ { + super/*Any*/() + /* () */ - } + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun create(): MetroFactory { + return MetroFactory() + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun newInstance(): FooScreen_NavEntryInstaller { + return FooScreen_NavEntryInstaller() + } - @HiddenFromObjC - @JvmStatic - @JsStatic - fun create(): MetroFactory { - return MetroFactory } @HiddenFromObjC - @JvmStatic - @JsStatic - fun newInstance(): FooScreen_NavEntryInstaller { - return FooScreen_NavEntryInstaller() + private constructor() /* primary */ { + super/*Any*/() + /* () */ + } @HiddenFromObjC override operator fun invoke(): FooScreen_NavEntryInstaller { - return MetroFactory.newInstance() + return Companion.newInstance() } @ComptimeOnly @@ -41,18 +51,12 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @MetroContribution(scope = AppScope::class) @BindingContainer - @Origin(value = FooScreen_NavEntryInstaller::class) + @Origin(value = FooScreen_NavEntryInstaller::class, context = "contribution_provider") @ComptimeOnly interface MetroContributionToDevzacsweersmetroappScopeocf15 { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ComptimeOnly abstract class BindsMirror { - private constructor() /* primary */ { - super/*Any*/() - /* () */ - - } - @Binds @IntoSet @CallableMetadata(callableName = "bindIntoSetAsNavEntryInstaller", propertyName = "", startOffset = -1, endOffset = -1) @@ -71,13 +75,15 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } - constructor() /* primary */ { + private constructor() /* primary */ { super/*Any*/() + /* () */ + } - context(: EntryProviderScope, : SharedTransitionScope) + context(entryProviderScope: EntryProviderScope, sharedTransitionScope: SharedTransitionScope) override fun install(backStack: NavBackStack) { - .entry(content = local fun (it: DummyRoute) { + entryProviderScope.entry(content = local fun (it: DummyRoute) { FooScreen() } ) @@ -85,8 +91,6 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } -// FILE: NoReceiverAndParams.kt - @RouteBinding(route = DummyRoute::class) @Composable internal fun FooScreen() { @@ -99,7 +103,6 @@ fun box(): String { // FILE: fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt package metro.hints -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) fun dev_zacsweers_metro_AppScope(contributed: FooScreen_NavEntryInstaller) { return error(message = "Never called") } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/Standard.fir.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/Standard.fir.txt deleted file mode 100644 index a0249227..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/Standard.fir.txt +++ /dev/null @@ -1,37 +0,0 @@ -FILE: Standard.kt - @R|io/github/reactivecircus/routebinding/runtime/RouteBinding|(route = (Q|DummyRoute|) [evaluated = (Q|DummyRoute|)]) @R|androidx/compose/runtime/Composable|() internal final fun R|androidx/compose/animation/SharedTransitionScope|.FooScreen(backStack: R|androidx/navigation3/runtime/NavBackStack|, route: R|DummyRoute|): R|kotlin/Unit| { - } - public final fun box(): R|kotlin/String| { - ^box String(OK) - } -FILE: /FooScreen_NavEntryInstaller.kt - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/ContributesIntoSet|(scope = (Q|dev/zacsweers/metro/AppScope|)) public final class FooScreen_NavEntryInstaller : R|io/github/reactivecircus/routebinding/runtime/NavEntryInstaller| { - context(: R|androidx/navigation3/runtime/EntryProviderScope|, : R|androidx/compose/animation/SharedTransitionScope|) - public final override fun install(backStack: R|androidx/navigation3/runtime/NavBackStack|): R|kotlin/Unit| - - public constructor(): R|FooScreen_NavEntryInstaller| { - super() - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final object MetroFactory : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroFactory| { - super() - } - - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroContribution|(scope = (Q|dev/zacsweers/metro/AppScope|)) @R|dev/zacsweers/metro/BindingContainer|() @R|dev/zacsweers/metro/Origin|(value = (Q|FooScreen_NavEntryInstaller|)) @R|dev/zacsweers/metro/internal/ComptimeOnly|() public abstract interface MetroContributionToDevzacsweersmetroappScopeocf15 : R|kotlin/Any| { - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public abstract class BindsMirror : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroContributionToDevzacsweersmetroappScopeocf15.BindsMirror| { - super() - } - - } - - } - - } -FILE: metro/hints/fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt - package metro.hints - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final fun dev_zacsweers_metro_AppScope(contributed: R|FooScreen_NavEntryInstaller|): R|kotlin/Unit| diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/Standard.kt.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/Standard.kt.txt index 67c34142..903f58f2 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/Standard.kt.txt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/Standard.kt.txt @@ -1,33 +1,43 @@ -// FILE: FooScreen_NavEntryInstaller.kt +// FILE: Standard.kt -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ContributesIntoSet(scope = AppScope::class) class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) - object MetroFactory : Factory { - private constructor() /* primary */ { - super/*Any*/() - /* () */ + class MetroFactory : Factory { + @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) + companion object Companion { + private constructor() /* primary */ { + super/*Any*/() + /* () */ - } + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun create(): MetroFactory { + return MetroFactory() + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun newInstance(): FooScreen_NavEntryInstaller { + return FooScreen_NavEntryInstaller() + } - @HiddenFromObjC - @JvmStatic - @JsStatic - fun create(): MetroFactory { - return MetroFactory } @HiddenFromObjC - @JvmStatic - @JsStatic - fun newInstance(): FooScreen_NavEntryInstaller { - return FooScreen_NavEntryInstaller() + private constructor() /* primary */ { + super/*Any*/() + /* () */ + } @HiddenFromObjC override operator fun invoke(): FooScreen_NavEntryInstaller { - return MetroFactory.newInstance() + return Companion.newInstance() } @ComptimeOnly @@ -41,18 +51,12 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @MetroContribution(scope = AppScope::class) @BindingContainer - @Origin(value = FooScreen_NavEntryInstaller::class) + @Origin(value = FooScreen_NavEntryInstaller::class, context = "contribution_provider") @ComptimeOnly interface MetroContributionToDevzacsweersmetroappScopeocf15 { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ComptimeOnly abstract class BindsMirror { - private constructor() /* primary */ { - super/*Any*/() - /* () */ - - } - @Binds @IntoSet @CallableMetadata(callableName = "bindIntoSetAsNavEntryInstaller", propertyName = "", startOffset = -1, endOffset = -1) @@ -71,22 +75,22 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } - constructor() /* primary */ { + private constructor() /* primary */ { super/*Any*/() + /* () */ + } - context(: EntryProviderScope, : SharedTransitionScope) + context(entryProviderScope: EntryProviderScope, sharedTransitionScope: SharedTransitionScope) override fun install(backStack: NavBackStack) { - .entry(content = local fun (it: DummyRoute) { - FooScreen(/* = , */ backStack = backStack, route = it) + entryProviderScope.entry(content = local fun (it: DummyRoute) { + FooScreen(/* = sharedTransitionScope, */ backStack = backStack, route = it) } ) } } -// FILE: Standard.kt - @RouteBinding(route = DummyRoute::class) @Composable internal fun SharedTransitionScope.FooScreen(backStack: NavBackStack, route: DummyRoute) { @@ -99,7 +103,6 @@ fun box(): String { // FILE: fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt package metro.hints -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) fun dev_zacsweers_metro_AppScope(contributed: FooScreen_NavEntryInstaller) { return error(message = "Never called") } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithBackStackParamOnly.fir.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithBackStackParamOnly.fir.txt deleted file mode 100644 index 03590dda..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithBackStackParamOnly.fir.txt +++ /dev/null @@ -1,37 +0,0 @@ -FILE: WithBackStackParamOnly.kt - @R|io/github/reactivecircus/routebinding/runtime/RouteBinding|(route = (Q|DummyRoute|) [evaluated = (Q|DummyRoute|)]) @R|androidx/compose/runtime/Composable|() internal final fun FooScreen(backStack: R|androidx/navigation3/runtime/NavBackStack|): R|kotlin/Unit| { - } - public final fun box(): R|kotlin/String| { - ^box String(OK) - } -FILE: /FooScreen_NavEntryInstaller.kt - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/ContributesIntoSet|(scope = (Q|dev/zacsweers/metro/AppScope|)) public final class FooScreen_NavEntryInstaller : R|io/github/reactivecircus/routebinding/runtime/NavEntryInstaller| { - context(: R|androidx/navigation3/runtime/EntryProviderScope|, : R|androidx/compose/animation/SharedTransitionScope|) - public final override fun install(backStack: R|androidx/navigation3/runtime/NavBackStack|): R|kotlin/Unit| - - public constructor(): R|FooScreen_NavEntryInstaller| { - super() - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final object MetroFactory : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroFactory| { - super() - } - - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroContribution|(scope = (Q|dev/zacsweers/metro/AppScope|)) @R|dev/zacsweers/metro/BindingContainer|() @R|dev/zacsweers/metro/Origin|(value = (Q|FooScreen_NavEntryInstaller|)) @R|dev/zacsweers/metro/internal/ComptimeOnly|() public abstract interface MetroContributionToDevzacsweersmetroappScopeocf15 : R|kotlin/Any| { - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public abstract class BindsMirror : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroContributionToDevzacsweersmetroappScopeocf15.BindsMirror| { - super() - } - - } - - } - - } -FILE: metro/hints/fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt - package metro.hints - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final fun dev_zacsweers_metro_AppScope(contributed: R|FooScreen_NavEntryInstaller|): R|kotlin/Unit| diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithBackStackParamOnly.kt.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithBackStackParamOnly.kt.txt index e9324f78..10a5d2ee 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithBackStackParamOnly.kt.txt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithBackStackParamOnly.kt.txt @@ -1,33 +1,43 @@ -// FILE: FooScreen_NavEntryInstaller.kt +// FILE: WithBackStackParamOnly.kt -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ContributesIntoSet(scope = AppScope::class) class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) - object MetroFactory : Factory { - private constructor() /* primary */ { - super/*Any*/() - /* () */ + class MetroFactory : Factory { + @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) + companion object Companion { + private constructor() /* primary */ { + super/*Any*/() + /* () */ - } + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun create(): MetroFactory { + return MetroFactory() + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun newInstance(): FooScreen_NavEntryInstaller { + return FooScreen_NavEntryInstaller() + } - @HiddenFromObjC - @JvmStatic - @JsStatic - fun create(): MetroFactory { - return MetroFactory } @HiddenFromObjC - @JvmStatic - @JsStatic - fun newInstance(): FooScreen_NavEntryInstaller { - return FooScreen_NavEntryInstaller() + private constructor() /* primary */ { + super/*Any*/() + /* () */ + } @HiddenFromObjC override operator fun invoke(): FooScreen_NavEntryInstaller { - return MetroFactory.newInstance() + return Companion.newInstance() } @ComptimeOnly @@ -41,18 +51,12 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @MetroContribution(scope = AppScope::class) @BindingContainer - @Origin(value = FooScreen_NavEntryInstaller::class) + @Origin(value = FooScreen_NavEntryInstaller::class, context = "contribution_provider") @ComptimeOnly interface MetroContributionToDevzacsweersmetroappScopeocf15 { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ComptimeOnly abstract class BindsMirror { - private constructor() /* primary */ { - super/*Any*/() - /* () */ - - } - @Binds @IntoSet @CallableMetadata(callableName = "bindIntoSetAsNavEntryInstaller", propertyName = "", startOffset = -1, endOffset = -1) @@ -71,13 +75,15 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } - constructor() /* primary */ { + private constructor() /* primary */ { super/*Any*/() + /* () */ + } - context(: EntryProviderScope, : SharedTransitionScope) + context(entryProviderScope: EntryProviderScope, sharedTransitionScope: SharedTransitionScope) override fun install(backStack: NavBackStack) { - .entry(content = local fun (it: DummyRoute) { + entryProviderScope.entry(content = local fun (it: DummyRoute) { FooScreen(backStack = backStack) } ) @@ -85,8 +91,6 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } -// FILE: WithBackStackParamOnly.kt - @RouteBinding(route = DummyRoute::class) @Composable internal fun FooScreen(backStack: NavBackStack) { @@ -99,7 +103,6 @@ fun box(): String { // FILE: fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt package metro.hints -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) fun dev_zacsweers_metro_AppScope(contributed: FooScreen_NavEntryInstaller) { return error(message = "Never called") } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithMetadataProvider.fir.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithMetadataProvider.fir.txt deleted file mode 100644 index 459717c1..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithMetadataProvider.fir.txt +++ /dev/null @@ -1,47 +0,0 @@ -FILE: WithMetadataProvider.kt - public final object DummyMetadataProvider : R|io/github/reactivecircus/routebinding/runtime/RouteMetadataProvider| { - private constructor(): R|DummyMetadataProvider| { - super() - } - - public open override fun provide(): R|kotlin/collections/Map| { - ^provide R|kotlin/collections/mapOf|(String(key).R|kotlin/to|(String(value))) - } - - } - @R|io/github/reactivecircus/routebinding/runtime/RouteBinding|(route = (Q|DummyRoute|) [evaluated = (Q|DummyRoute|)], metadataProvider = (Q|DummyMetadataProvider|) [evaluated = (Q|DummyMetadataProvider|)]) @R|androidx/compose/runtime/Composable|() internal final fun R|androidx/compose/animation/SharedTransitionScope|.FooScreen(backStack: R|androidx/navigation3/runtime/NavBackStack|, route: R|DummyRoute|): R|kotlin/Unit| { - } - public final fun box(): R|kotlin/String| { - ^box String(OK) - } -FILE: /FooScreen_NavEntryInstaller.kt - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/ContributesIntoSet|(scope = (Q|dev/zacsweers/metro/AppScope|)) public final class FooScreen_NavEntryInstaller : R|io/github/reactivecircus/routebinding/runtime/NavEntryInstaller| { - context(: R|androidx/navigation3/runtime/EntryProviderScope|, : R|androidx/compose/animation/SharedTransitionScope|) - public final override fun install(backStack: R|androidx/navigation3/runtime/NavBackStack|): R|kotlin/Unit| - - public constructor(): R|FooScreen_NavEntryInstaller| { - super() - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final object MetroFactory : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroFactory| { - super() - } - - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroContribution|(scope = (Q|dev/zacsweers/metro/AppScope|)) @R|dev/zacsweers/metro/BindingContainer|() @R|dev/zacsweers/metro/Origin|(value = (Q|FooScreen_NavEntryInstaller|)) @R|dev/zacsweers/metro/internal/ComptimeOnly|() public abstract interface MetroContributionToDevzacsweersmetroappScopeocf15 : R|kotlin/Any| { - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public abstract class BindsMirror : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroContributionToDevzacsweersmetroappScopeocf15.BindsMirror| { - super() - } - - } - - } - - } -FILE: metro/hints/fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt - package metro.hints - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final fun dev_zacsweers_metro_AppScope(contributed: R|FooScreen_NavEntryInstaller|): R|kotlin/Unit| diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithMetadataProvider.kt.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithMetadataProvider.kt.txt index f1c2ff02..f4582a52 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithMetadataProvider.kt.txt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithMetadataProvider.kt.txt @@ -1,33 +1,43 @@ -// FILE: FooScreen_NavEntryInstaller.kt +// FILE: WithMetadataProvider.kt -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ContributesIntoSet(scope = AppScope::class) class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) - object MetroFactory : Factory { - private constructor() /* primary */ { - super/*Any*/() - /* () */ + class MetroFactory : Factory { + @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) + companion object Companion { + private constructor() /* primary */ { + super/*Any*/() + /* () */ - } + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun create(): MetroFactory { + return MetroFactory() + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun newInstance(): FooScreen_NavEntryInstaller { + return FooScreen_NavEntryInstaller() + } - @HiddenFromObjC - @JvmStatic - @JsStatic - fun create(): MetroFactory { - return MetroFactory } @HiddenFromObjC - @JvmStatic - @JsStatic - fun newInstance(): FooScreen_NavEntryInstaller { - return FooScreen_NavEntryInstaller() + private constructor() /* primary */ { + super/*Any*/() + /* () */ + } @HiddenFromObjC override operator fun invoke(): FooScreen_NavEntryInstaller { - return MetroFactory.newInstance() + return Companion.newInstance() } @ComptimeOnly @@ -41,18 +51,12 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @MetroContribution(scope = AppScope::class) @BindingContainer - @Origin(value = FooScreen_NavEntryInstaller::class) + @Origin(value = FooScreen_NavEntryInstaller::class, context = "contribution_provider") @ComptimeOnly interface MetroContributionToDevzacsweersmetroappScopeocf15 { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ComptimeOnly abstract class BindsMirror { - private constructor() /* primary */ { - super/*Any*/() - /* () */ - - } - @Binds @IntoSet @CallableMetadata(callableName = "bindIntoSetAsNavEntryInstaller", propertyName = "", startOffset = -1, endOffset = -1) @@ -71,22 +75,22 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } - constructor() /* primary */ { + private constructor() /* primary */ { super/*Any*/() + /* () */ + } - context(: EntryProviderScope, : SharedTransitionScope) + context(entryProviderScope: EntryProviderScope, sharedTransitionScope: SharedTransitionScope) override fun install(backStack: NavBackStack) { - .entry(metadata = DummyMetadataProvider.provide(), content = local fun (it: DummyRoute) { - FooScreen(/* = , */ backStack = backStack, route = it) + entryProviderScope.entry(metadata = DummyMetadataProvider.provide(), content = local fun (it: DummyRoute) { + FooScreen(/* = sharedTransitionScope, */ backStack = backStack, route = it) } ) } } -// FILE: WithMetadataProvider.kt - object DummyMetadataProvider : RouteMetadataProvider { private constructor() /* primary */ { super/*Any*/() @@ -112,7 +116,6 @@ fun box(): String { // FILE: fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt package metro.hints -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) fun dev_zacsweers_metro_AppScope(contributed: FooScreen_NavEntryInstaller) { return error(message = "Never called") } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithParamWithDefaultValue.fir.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithParamWithDefaultValue.fir.txt deleted file mode 100644 index 9da502fc..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithParamWithDefaultValue.fir.txt +++ /dev/null @@ -1,37 +0,0 @@ -FILE: WithParamWithDefaultValue.kt - @R|io/github/reactivecircus/routebinding/runtime/RouteBinding|(route = (Q|DummyRoute|) [evaluated = (Q|DummyRoute|)]) @R|androidx/compose/runtime/Composable|() internal final fun R|androidx/compose/animation/SharedTransitionScope|.FooScreen(backStack: R|androidx/navigation3/runtime/NavBackStack|, route: R|DummyRoute|, title: R|kotlin/String| = String(Title)): R|kotlin/Unit| { - } - public final fun box(): R|kotlin/String| { - ^box String(OK) - } -FILE: /FooScreen_NavEntryInstaller.kt - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/ContributesIntoSet|(scope = (Q|dev/zacsweers/metro/AppScope|)) public final class FooScreen_NavEntryInstaller : R|io/github/reactivecircus/routebinding/runtime/NavEntryInstaller| { - context(: R|androidx/navigation3/runtime/EntryProviderScope|, : R|androidx/compose/animation/SharedTransitionScope|) - public final override fun install(backStack: R|androidx/navigation3/runtime/NavBackStack|): R|kotlin/Unit| - - public constructor(): R|FooScreen_NavEntryInstaller| { - super() - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final object MetroFactory : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroFactory| { - super() - } - - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroContribution|(scope = (Q|dev/zacsweers/metro/AppScope|)) @R|dev/zacsweers/metro/BindingContainer|() @R|dev/zacsweers/metro/Origin|(value = (Q|FooScreen_NavEntryInstaller|)) @R|dev/zacsweers/metro/internal/ComptimeOnly|() public abstract interface MetroContributionToDevzacsweersmetroappScopeocf15 : R|kotlin/Any| { - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public abstract class BindsMirror : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroContributionToDevzacsweersmetroappScopeocf15.BindsMirror| { - super() - } - - } - - } - - } -FILE: metro/hints/fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt - package metro.hints - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final fun dev_zacsweers_metro_AppScope(contributed: R|FooScreen_NavEntryInstaller|): R|kotlin/Unit| diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithParamWithDefaultValue.kt.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithParamWithDefaultValue.kt.txt index 387150ad..8d9ec20d 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithParamWithDefaultValue.kt.txt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithParamWithDefaultValue.kt.txt @@ -1,33 +1,43 @@ -// FILE: FooScreen_NavEntryInstaller.kt +// FILE: WithParamWithDefaultValue.kt -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ContributesIntoSet(scope = AppScope::class) class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) - object MetroFactory : Factory { - private constructor() /* primary */ { - super/*Any*/() - /* () */ + class MetroFactory : Factory { + @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) + companion object Companion { + private constructor() /* primary */ { + super/*Any*/() + /* () */ - } + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun create(): MetroFactory { + return MetroFactory() + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun newInstance(): FooScreen_NavEntryInstaller { + return FooScreen_NavEntryInstaller() + } - @HiddenFromObjC - @JvmStatic - @JsStatic - fun create(): MetroFactory { - return MetroFactory } @HiddenFromObjC - @JvmStatic - @JsStatic - fun newInstance(): FooScreen_NavEntryInstaller { - return FooScreen_NavEntryInstaller() + private constructor() /* primary */ { + super/*Any*/() + /* () */ + } @HiddenFromObjC override operator fun invoke(): FooScreen_NavEntryInstaller { - return MetroFactory.newInstance() + return Companion.newInstance() } @ComptimeOnly @@ -41,18 +51,12 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @MetroContribution(scope = AppScope::class) @BindingContainer - @Origin(value = FooScreen_NavEntryInstaller::class) + @Origin(value = FooScreen_NavEntryInstaller::class, context = "contribution_provider") @ComptimeOnly interface MetroContributionToDevzacsweersmetroappScopeocf15 { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ComptimeOnly abstract class BindsMirror { - private constructor() /* primary */ { - super/*Any*/() - /* () */ - - } - @Binds @IntoSet @CallableMetadata(callableName = "bindIntoSetAsNavEntryInstaller", propertyName = "", startOffset = -1, endOffset = -1) @@ -71,22 +75,22 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } - constructor() /* primary */ { + private constructor() /* primary */ { super/*Any*/() + /* () */ + } - context(: EntryProviderScope, : SharedTransitionScope) + context(entryProviderScope: EntryProviderScope, sharedTransitionScope: SharedTransitionScope) override fun install(backStack: NavBackStack) { - .entry(content = local fun (it: DummyRoute) { - FooScreen(/* = , */ backStack = backStack, route = it) + entryProviderScope.entry(content = local fun (it: DummyRoute) { + FooScreen(/* = sharedTransitionScope, */ backStack = backStack, route = it) } ) } } -// FILE: WithParamWithDefaultValue.kt - @RouteBinding(route = DummyRoute::class) @Composable internal fun SharedTransitionScope.FooScreen(backStack: NavBackStack, route: DummyRoute, title: String = "Title") { @@ -99,7 +103,6 @@ fun box(): String { // FILE: fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt package metro.hints -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) fun dev_zacsweers_metro_AppScope(contributed: FooScreen_NavEntryInstaller) { return error(message = "Never called") } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithRouteParamOnly.fir.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithRouteParamOnly.fir.txt deleted file mode 100644 index 18646914..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithRouteParamOnly.fir.txt +++ /dev/null @@ -1,37 +0,0 @@ -FILE: WithRouteParamOnly.kt - @R|io/github/reactivecircus/routebinding/runtime/RouteBinding|(route = (Q|DummyRoute|) [evaluated = (Q|DummyRoute|)]) @R|androidx/compose/runtime/Composable|() internal final fun FooScreen(route: R|DummyRoute|): R|kotlin/Unit| { - } - public final fun box(): R|kotlin/String| { - ^box String(OK) - } -FILE: /FooScreen_NavEntryInstaller.kt - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/ContributesIntoSet|(scope = (Q|dev/zacsweers/metro/AppScope|)) public final class FooScreen_NavEntryInstaller : R|io/github/reactivecircus/routebinding/runtime/NavEntryInstaller| { - context(: R|androidx/navigation3/runtime/EntryProviderScope|, : R|androidx/compose/animation/SharedTransitionScope|) - public final override fun install(backStack: R|androidx/navigation3/runtime/NavBackStack|): R|kotlin/Unit| - - public constructor(): R|FooScreen_NavEntryInstaller| { - super() - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final object MetroFactory : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroFactory| { - super() - } - - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroContribution|(scope = (Q|dev/zacsweers/metro/AppScope|)) @R|dev/zacsweers/metro/BindingContainer|() @R|dev/zacsweers/metro/Origin|(value = (Q|FooScreen_NavEntryInstaller|)) @R|dev/zacsweers/metro/internal/ComptimeOnly|() public abstract interface MetroContributionToDevzacsweersmetroappScopeocf15 : R|kotlin/Any| { - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public abstract class BindsMirror : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroContributionToDevzacsweersmetroappScopeocf15.BindsMirror| { - super() - } - - } - - } - - } -FILE: metro/hints/fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt - package metro.hints - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final fun dev_zacsweers_metro_AppScope(contributed: R|FooScreen_NavEntryInstaller|): R|kotlin/Unit| diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithRouteParamOnly.kt.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithRouteParamOnly.kt.txt index 7e68a2b7..81ef3f2c 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithRouteParamOnly.kt.txt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithRouteParamOnly.kt.txt @@ -1,33 +1,43 @@ -// FILE: FooScreen_NavEntryInstaller.kt +// FILE: WithRouteParamOnly.kt -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ContributesIntoSet(scope = AppScope::class) class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) - object MetroFactory : Factory { - private constructor() /* primary */ { - super/*Any*/() - /* () */ + class MetroFactory : Factory { + @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) + companion object Companion { + private constructor() /* primary */ { + super/*Any*/() + /* () */ - } + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun create(): MetroFactory { + return MetroFactory() + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun newInstance(): FooScreen_NavEntryInstaller { + return FooScreen_NavEntryInstaller() + } - @HiddenFromObjC - @JvmStatic - @JsStatic - fun create(): MetroFactory { - return MetroFactory } @HiddenFromObjC - @JvmStatic - @JsStatic - fun newInstance(): FooScreen_NavEntryInstaller { - return FooScreen_NavEntryInstaller() + private constructor() /* primary */ { + super/*Any*/() + /* () */ + } @HiddenFromObjC override operator fun invoke(): FooScreen_NavEntryInstaller { - return MetroFactory.newInstance() + return Companion.newInstance() } @ComptimeOnly @@ -41,18 +51,12 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @MetroContribution(scope = AppScope::class) @BindingContainer - @Origin(value = FooScreen_NavEntryInstaller::class) + @Origin(value = FooScreen_NavEntryInstaller::class, context = "contribution_provider") @ComptimeOnly interface MetroContributionToDevzacsweersmetroappScopeocf15 { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ComptimeOnly abstract class BindsMirror { - private constructor() /* primary */ { - super/*Any*/() - /* () */ - - } - @Binds @IntoSet @CallableMetadata(callableName = "bindIntoSetAsNavEntryInstaller", propertyName = "", startOffset = -1, endOffset = -1) @@ -71,13 +75,15 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } - constructor() /* primary */ { + private constructor() /* primary */ { super/*Any*/() + /* () */ + } - context(: EntryProviderScope, : SharedTransitionScope) + context(entryProviderScope: EntryProviderScope, sharedTransitionScope: SharedTransitionScope) override fun install(backStack: NavBackStack) { - .entry(content = local fun (it: DummyRoute) { + entryProviderScope.entry(content = local fun (it: DummyRoute) { FooScreen(route = it) } ) @@ -85,8 +91,6 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } -// FILE: WithRouteParamOnly.kt - @RouteBinding(route = DummyRoute::class) @Composable internal fun FooScreen(route: DummyRoute) { @@ -99,7 +103,6 @@ fun box(): String { // FILE: fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt package metro.hints -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) fun dev_zacsweers_metro_AppScope(contributed: FooScreen_NavEntryInstaller) { return error(message = "Never called") } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsContextParam.fir.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsContextParam.fir.txt deleted file mode 100644 index ca55cdce..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsContextParam.fir.txt +++ /dev/null @@ -1,38 +0,0 @@ -FILE: WithSharedTransitionScopeAsContextParam.kt - context(sharedTransitionScope: R|androidx/compose/animation/SharedTransitionScope|) - @R|io/github/reactivecircus/routebinding/runtime/RouteBinding|(route = (Q|DummyRoute|) [evaluated = (Q|DummyRoute|)]) @R|androidx/compose/runtime/Composable|() internal final fun FooScreen(backStack: R|androidx/navigation3/runtime/NavBackStack|, route: R|DummyRoute|): R|kotlin/Unit| { - } - public final fun box(): R|kotlin/String| { - ^box String(OK) - } -FILE: /FooScreen_NavEntryInstaller.kt - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/ContributesIntoSet|(scope = (Q|dev/zacsweers/metro/AppScope|)) public final class FooScreen_NavEntryInstaller : R|io/github/reactivecircus/routebinding/runtime/NavEntryInstaller| { - context(: R|androidx/navigation3/runtime/EntryProviderScope|, : R|androidx/compose/animation/SharedTransitionScope|) - public final override fun install(backStack: R|androidx/navigation3/runtime/NavBackStack|): R|kotlin/Unit| - - public constructor(): R|FooScreen_NavEntryInstaller| { - super() - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final object MetroFactory : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroFactory| { - super() - } - - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroContribution|(scope = (Q|dev/zacsweers/metro/AppScope|)) @R|dev/zacsweers/metro/BindingContainer|() @R|dev/zacsweers/metro/Origin|(value = (Q|FooScreen_NavEntryInstaller|)) @R|dev/zacsweers/metro/internal/ComptimeOnly|() public abstract interface MetroContributionToDevzacsweersmetroappScopeocf15 : R|kotlin/Any| { - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public abstract class BindsMirror : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroContributionToDevzacsweersmetroappScopeocf15.BindsMirror| { - super() - } - - } - - } - - } -FILE: metro/hints/fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt - package metro.hints - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final fun dev_zacsweers_metro_AppScope(contributed: R|FooScreen_NavEntryInstaller|): R|kotlin/Unit| diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsContextParam.kt.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsContextParam.kt.txt index 249161c1..36a33284 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsContextParam.kt.txt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsContextParam.kt.txt @@ -1,33 +1,43 @@ -// FILE: FooScreen_NavEntryInstaller.kt +// FILE: WithSharedTransitionScopeAsContextParam.kt -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ContributesIntoSet(scope = AppScope::class) class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) - object MetroFactory : Factory { - private constructor() /* primary */ { - super/*Any*/() - /* () */ + class MetroFactory : Factory { + @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) + companion object Companion { + private constructor() /* primary */ { + super/*Any*/() + /* () */ - } + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun create(): MetroFactory { + return MetroFactory() + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun newInstance(): FooScreen_NavEntryInstaller { + return FooScreen_NavEntryInstaller() + } - @HiddenFromObjC - @JvmStatic - @JsStatic - fun create(): MetroFactory { - return MetroFactory } @HiddenFromObjC - @JvmStatic - @JsStatic - fun newInstance(): FooScreen_NavEntryInstaller { - return FooScreen_NavEntryInstaller() + private constructor() /* primary */ { + super/*Any*/() + /* () */ + } @HiddenFromObjC override operator fun invoke(): FooScreen_NavEntryInstaller { - return MetroFactory.newInstance() + return Companion.newInstance() } @ComptimeOnly @@ -41,18 +51,12 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @MetroContribution(scope = AppScope::class) @BindingContainer - @Origin(value = FooScreen_NavEntryInstaller::class) + @Origin(value = FooScreen_NavEntryInstaller::class, context = "contribution_provider") @ComptimeOnly interface MetroContributionToDevzacsweersmetroappScopeocf15 { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ComptimeOnly abstract class BindsMirror { - private constructor() /* primary */ { - super/*Any*/() - /* () */ - - } - @Binds @IntoSet @CallableMetadata(callableName = "bindIntoSetAsNavEntryInstaller", propertyName = "", startOffset = -1, endOffset = -1) @@ -71,22 +75,22 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } - constructor() /* primary */ { + private constructor() /* primary */ { super/*Any*/() + /* () */ + } - context(: EntryProviderScope, : SharedTransitionScope) + context(entryProviderScope: EntryProviderScope, sharedTransitionScope: SharedTransitionScope) override fun install(backStack: NavBackStack) { - .entry(content = local fun (it: DummyRoute) { - FooScreen(/* sharedTransitionScope = , */ backStack = backStack, route = it) + entryProviderScope.entry(content = local fun (it: DummyRoute) { + FooScreen(/* sharedTransitionScope = sharedTransitionScope, */ backStack = backStack, route = it) } ) } } -// FILE: WithSharedTransitionScopeAsContextParam.kt - @RouteBinding(route = DummyRoute::class) @Composable context(sharedTransitionScope: SharedTransitionScope) @@ -100,7 +104,6 @@ fun box(): String { // FILE: fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt package metro.hints -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) fun dev_zacsweers_metro_AppScope(contributed: FooScreen_NavEntryInstaller) { return error(message = "Never called") } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsValueParam.fir.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsValueParam.fir.txt deleted file mode 100644 index 7acb41bc..00000000 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsValueParam.fir.txt +++ /dev/null @@ -1,37 +0,0 @@ -FILE: WithSharedTransitionScopeAsValueParam.kt - @R|io/github/reactivecircus/routebinding/runtime/RouteBinding|(route = (Q|DummyRoute|) [evaluated = (Q|DummyRoute|)]) @R|androidx/compose/runtime/Composable|() internal final fun FooScreen(sharedTransitionScope: R|androidx/compose/animation/SharedTransitionScope|, backStack: R|androidx/navigation3/runtime/NavBackStack|): R|kotlin/Unit| { - } - public final fun box(): R|kotlin/String| { - ^box String(OK) - } -FILE: /FooScreen_NavEntryInstaller.kt - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/ContributesIntoSet|(scope = (Q|dev/zacsweers/metro/AppScope|)) public final class FooScreen_NavEntryInstaller : R|io/github/reactivecircus/routebinding/runtime/NavEntryInstaller| { - context(: R|androidx/navigation3/runtime/EntryProviderScope|, : R|androidx/compose/animation/SharedTransitionScope|) - public final override fun install(backStack: R|androidx/navigation3/runtime/NavBackStack|): R|kotlin/Unit| - - public constructor(): R|FooScreen_NavEntryInstaller| { - super() - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final object MetroFactory : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroFactory| { - super() - } - - } - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroContribution|(scope = (Q|dev/zacsweers/metro/AppScope|)) @R|dev/zacsweers/metro/BindingContainer|() @R|dev/zacsweers/metro/Origin|(value = (Q|FooScreen_NavEntryInstaller|)) @R|dev/zacsweers/metro/internal/ComptimeOnly|() public abstract interface MetroContributionToDevzacsweersmetroappScopeocf15 : R|kotlin/Any| { - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public abstract class BindsMirror : R|kotlin/Any| { - private constructor(): R|FooScreen_NavEntryInstaller.MetroContributionToDevzacsweersmetroappScopeocf15.BindsMirror| { - super() - } - - } - - } - - } -FILE: metro/hints/fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt - package metro.hints - - @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) public final fun dev_zacsweers_metro_AppScope(contributed: R|FooScreen_NavEntryInstaller|): R|kotlin/Unit| diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsValueParam.kt.txt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsValueParam.kt.txt index a92a0766..5f46a1e3 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsValueParam.kt.txt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/test/data/dump/WithSharedTransitionScopeAsValueParam.kt.txt @@ -1,33 +1,43 @@ -// FILE: FooScreen_NavEntryInstaller.kt +// FILE: WithSharedTransitionScopeAsValueParam.kt -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ContributesIntoSet(scope = AppScope::class) class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) - object MetroFactory : Factory { - private constructor() /* primary */ { - super/*Any*/() - /* () */ + class MetroFactory : Factory { + @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) + companion object Companion { + private constructor() /* primary */ { + super/*Any*/() + /* () */ - } + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun create(): MetroFactory { + return MetroFactory() + } + + @HiddenFromObjC + @JvmStatic + @JsStatic + fun newInstance(): FooScreen_NavEntryInstaller { + return FooScreen_NavEntryInstaller() + } - @HiddenFromObjC - @JvmStatic - @JsStatic - fun create(): MetroFactory { - return MetroFactory } @HiddenFromObjC - @JvmStatic - @JsStatic - fun newInstance(): FooScreen_NavEntryInstaller { - return FooScreen_NavEntryInstaller() + private constructor() /* primary */ { + super/*Any*/() + /* () */ + } @HiddenFromObjC override operator fun invoke(): FooScreen_NavEntryInstaller { - return MetroFactory.newInstance() + return Companion.newInstance() } @ComptimeOnly @@ -41,18 +51,12 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @MetroContribution(scope = AppScope::class) @BindingContainer - @Origin(value = FooScreen_NavEntryInstaller::class) + @Origin(value = FooScreen_NavEntryInstaller::class, context = "contribution_provider") @ComptimeOnly interface MetroContributionToDevzacsweersmetroappScopeocf15 { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ComptimeOnly abstract class BindsMirror { - private constructor() /* primary */ { - super/*Any*/() - /* () */ - - } - @Binds @IntoSet @CallableMetadata(callableName = "bindIntoSetAsNavEntryInstaller", propertyName = "", startOffset = -1, endOffset = -1) @@ -71,22 +75,22 @@ class FooScreen_NavEntryInstaller : NavEntryInstaller { } - constructor() /* primary */ { + private constructor() /* primary */ { super/*Any*/() + /* () */ + } - context(: EntryProviderScope, : SharedTransitionScope) + context(entryProviderScope: EntryProviderScope, sharedTransitionScope: SharedTransitionScope) override fun install(backStack: NavBackStack) { - .entry(content = local fun (it: DummyRoute) { - FooScreen(sharedTransitionScope = , backStack = backStack) + entryProviderScope.entry(content = local fun (it: DummyRoute) { + FooScreen(sharedTransitionScope = sharedTransitionScope, backStack = backStack) } ) } } -// FILE: WithSharedTransitionScopeAsValueParam.kt - @RouteBinding(route = DummyRoute::class) @Composable internal fun FooScreen(sharedTransitionScope: SharedTransitionScope, backStack: NavBackStack) { @@ -99,7 +103,6 @@ fun box(): String { // FILE: fooScreen_NavEntryInstallerDev_zacsweers_metro_AppScope.kt package metro.hints -@Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) fun dev_zacsweers_metro_AppScope(contributed: FooScreen_NavEntryInstaller) { return error(message = "Never called") } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/kotlin/io/github/reactivecircus/routebinding/compiler/AbstractDumpTest.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/kotlin/io/github/reactivecircus/routebinding/compiler/AbstractDumpTest.kt index c3ff30c5..e2c005db 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/kotlin/io/github/reactivecircus/routebinding/compiler/AbstractDumpTest.kt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/test/kotlin/io/github/reactivecircus/routebinding/compiler/AbstractDumpTest.kt @@ -7,7 +7,6 @@ import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.DUMP_KT_IR import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_DEXING import org.jetbrains.kotlin.test.directives.ConfigurationDirectives.WITH_STDLIB import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives.DISABLE_GENERATED_FIR_TAGS -import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives.FIR_DUMP import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.FULL_JDK import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JVM_TARGET import org.jetbrains.kotlin.test.runners.ir.AbstractFirLightTreeJvmIrTextTest @@ -34,7 +33,6 @@ open class AbstractDumpTest : AbstractFirLightTreeJvmIrTextTest() { -DUMP_IR +DUMP_KT_IR - +FIR_DUMP } } } diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/test/kotlin/io/github/reactivecircus/routebinding/compiler/RouteBindingExtensionRegistrarConfigurator.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/test/kotlin/io/github/reactivecircus/routebinding/compiler/RouteBindingExtensionRegistrarConfigurator.kt index a3336f7a..a47a1ab4 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/test/kotlin/io/github/reactivecircus/routebinding/compiler/RouteBindingExtensionRegistrarConfigurator.kt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/test/kotlin/io/github/reactivecircus/routebinding/compiler/RouteBindingExtensionRegistrarConfigurator.kt @@ -42,17 +42,12 @@ private class RouteBindingExtensionRegistrarConfigurator( // configure and register Metro compiler plugin metroCliProcessor.processOption( - option = metroCliOptionByName("generate-contribution-hints-in-fir"), - value = "true", - configuration = configuration, - ) - metroCliProcessor.processOption( - option = metroCliOptionByName("contributes-as-inject"), + option = metroCliOptionByName("generate-contribution-providers"), value = "true", configuration = configuration, ) metroCliProcessor.processOption( - option = metroCliOptionByName("generate-contribution-providers"), + option = metroCliOptionByName("generate-classes-in-ir"), value = "true", configuration = configuration, ) diff --git a/build-logic/routebinding/routebinding-gradle-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/gradle/RouteBindingGradlePlugin.kt b/build-logic/routebinding/routebinding-gradle-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/gradle/RouteBindingGradlePlugin.kt index d90202b2..96618344 100644 --- a/build-logic/routebinding/routebinding-gradle-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/gradle/RouteBindingGradlePlugin.kt +++ b/build-logic/routebinding/routebinding-gradle-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/gradle/RouteBindingGradlePlugin.kt @@ -17,7 +17,8 @@ public class RouteBindingGradlePlugin : KotlinCompilerPluginSupportPlugin { override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider> { kotlinCompilation.compileTaskProvider.configure { - it.compilerOptions.freeCompilerArgs.add( + it.compilerOptions.freeCompilerArgs.addAll( + "-Xcompiler-plugin-order=$RouteBindingCompilerPluginId>$MetroCompilerPluginId", "-Xcompiler-plugin-order=$RouteBindingCompilerPluginId>$ComposeCompilerPluginId", ) } From 1f6160dc9cc719ca9891f733b73a8801ef3057e8 Mon Sep 17 00:00:00 2001 From: Yang Date: Fri, 26 Jun 2026 10:25:18 +1000 Subject: [PATCH 2/2] Reuse generator. --- .../compiler/ir/RouteBindingClassGenerator.kt | 1 - .../ir/RouteBindingIrGenerationExtension.kt | 58 +++++++++---------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingClassGenerator.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingClassGenerator.kt index a937faa2..3fc87644 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingClassGenerator.kt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingClassGenerator.kt @@ -102,7 +102,6 @@ internal class RouteBindingClassGenerator( type = annotationType, constructorSymbol = contributesIntoSetCtor, ).apply { - // ContributesIntoSet(scope = AppScope::class, ...); remaining params have defaults. arguments[0] = IrClassReferenceImpl( startOffset = UNDEFINED_OFFSET, endOffset = UNDEFINED_OFFSET, diff --git a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingIrGenerationExtension.kt b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingIrGenerationExtension.kt index bcecc496..7d2677c0 100644 --- a/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingIrGenerationExtension.kt +++ b/build-logic/routebinding/routebinding-compiler-plugin/src/main/kotlin/io/github/reactivecircus/routebinding/compiler/ir/RouteBindingIrGenerationExtension.kt @@ -15,40 +15,38 @@ internal class RouteBindingIrGenerationExtension( private val messageCollector: MessageCollector, ) : IrGenerationExtension { override fun generate(moduleFragment: IrModuleFragment, pluginContext: IrPluginContext) { + val generator by lazy { + val metroSymbols = MetroSymbols.create( + pluginContext, + messageCollector, + contributesIntoSetClassId = ClassIds.Metro.ContributesIntoSet, + appScopeClassId = ClassIds.Metro.AppScope, + ) + val nav3Symbols = Nav3Symbols.create( + pluginContext, + messageCollector, + entryProviderScopeClassId = ClassIds.Nav3.EntryProviderScope, + ) + val routeBindingSymbols = RouteBindingSymbols.create( + pluginContext, + messageCollector, + navEntryInstallerClassId = ClassIds.RouteBinding.NavEntryInstaller, + ) + if (metroSymbols == null || nav3Symbols == null || routeBindingSymbols == null) return@lazy null + RouteBindingClassGenerator( + pluginContext, + metroSymbols, + nav3Symbols, + routeBindingSymbols, + ) + } + moduleFragment.files .flatMap { it.declarations } .filterIsInstance() .filter { it.hasAnnotation(ClassIds.RouteBinding.Annotation) } - .let { routeBindingFunctions -> - if (routeBindingFunctions.isEmpty()) return - val metroSymbols = MetroSymbols.create( - pluginContext, - messageCollector, - contributesIntoSetClassId = ClassIds.Metro.ContributesIntoSet, - appScopeClassId = ClassIds.Metro.AppScope, - ) - val nav3Symbols = Nav3Symbols.create( - pluginContext, - messageCollector, - entryProviderScopeClassId = ClassIds.Nav3.EntryProviderScope, - ) - val routeBindingSymbols = RouteBindingSymbols.create( - pluginContext, - messageCollector, - navEntryInstallerClassId = ClassIds.RouteBinding.NavEntryInstaller, - ) - if (metroSymbols == null || nav3Symbols == null || routeBindingSymbols == null) return - - // Generate the NavEntryInstaller class for each `@RouteBinding`-annotated source function. - val generator = RouteBindingClassGenerator( - pluginContext, - metroSymbols, - nav3Symbols, - routeBindingSymbols, - ) - for (sourceFunction in routeBindingFunctions) { - generator.generate(sourceFunction) - } + .forEach { sourceFunction -> + generator?.generate(sourceFunction) } } }