├── .github ├── workflows │ └── .java-version ├── pull_request_template.md └── ISSUE_TEMPLATE │ └── config.yml ├── compiler-compat ├── k2220 │ ├── version.txt │ └── src │ │ └── main │ │ └── resources │ │ └── META-INF │ │ └── services │ │ └── dev.zacsweers.metro.compiler.compat.CompatContext$Factory ├── k230_beta1 │ ├── version.txt │ └── src │ │ └── main │ │ └── resources │ │ └── META-INF │ │ └── services │ │ └── dev.zacsweers.metro.compiler.compat.CompatContext$Factory ├── k2320_dev_5437 │ ├── version.txt │ └── src │ │ └── main │ │ └── resources │ │ └── META-INF │ │ └── services │ │ └── dev.zacsweers.metro.compiler.compat.CompatContext$Factory ├── version-aliases.txt └── build.gradle.kts ├── compiler-tests └── src │ ├── test │ ├── data │ │ ├── dump │ │ │ ├── fir │ │ │ │ ├── scratch.kt │ │ │ │ ├── scratch.fir.txt │ │ │ │ ├── aggregation │ │ │ │ │ ├── ContributingTypes.kt │ │ │ │ │ ├── ContributingTypesDependency.kt │ │ │ │ │ ├── ContributingGraphExtensions.kt │ │ │ │ │ ├── FirHintGenerationWorks_k22x.kt │ │ │ │ │ └── FirHintGenerationWorks_k23x.kt │ │ │ │ └── private-provides-status-transformation │ │ │ │ │ └── ProvidersAreMadePrivate.kt │ │ │ └── ir │ │ │ │ ├── scratch.kt │ │ │ │ ├── scratch.fir.kt.txt │ │ │ │ ├── injectconstructor │ │ │ │ ├── DefaultValuesPropagateToNewInstanceParams.kt │ │ │ │ └── ConstructorFunctionSignatures.kt │ │ │ │ ├── provides │ │ │ │ ├── DefaultValuesPropagateToNewInstanceParams.kt │ │ │ │ └── JvmFieldProvidersUseFieldAccess.kt │ │ │ │ ├── dependencygraph │ │ │ │ ├── EmptyMapMultibindingsUseEmptyMap.kt │ │ │ │ ├── MapsUseMapBuilderIfNoProvider.kt │ │ │ │ ├── UnusedScopedBindingsInUnextendedGraphGetNoProviderFields.kt │ │ │ │ ├── ProviderAccessorsAreTrackedInRefCounting.kt │ │ │ │ ├── GraphImplClassAsReturnType.kt │ │ │ │ ├── ExtensionsAreInnerClasses.kt │ │ │ │ ├── UnusedInstanceBindingsInUnextendedGraphGetNoProviderFields.kt │ │ │ │ ├── MultipleRefsGetProviderFields.kt │ │ │ │ ├── LazyPropertiesHaveDeterministicOrder.kt │ │ │ │ ├── OptionalBindingsHaveValidFieldNames.kt │ │ │ │ ├── GraphAccessors.kt │ │ │ │ └── MapBuildersUseInlineInstantiation.kt │ │ │ │ ├── MultibindingsWithComplexDependenciesGetProperties.kt │ │ │ │ ├── cycles │ │ │ │ ├── SelfCycle.kt │ │ │ │ ├── BindsCycleGraph.kt │ │ │ │ └── CycleMapGraph.kt │ │ │ │ ├── visibility │ │ │ │ ├── InternalVisibility.kt │ │ │ │ └── InternalVisibilityDifferentModule.kt │ │ │ │ ├── multibindings │ │ │ │ ├── MapProvidersParticipateInProviderRefcounting.kt │ │ │ │ └── MultibindingSourcesGetGettersThroughAliases.kt │ │ │ │ └── aggregation │ │ │ │ └── ContributorsWithSameSimpleNames.kt │ │ ├── diagnostic │ │ │ ├── functioninject │ │ │ │ ├── CannotHaveTypeArgs.fir.diag.txt │ │ │ │ ├── CannotBeScoped.fir.diag.txt │ │ │ │ ├── CannotHaveExtensionReceivers.fir.diag.txt │ │ │ │ ├── ContextParamsCannotBeOptional.fir.diag.txt │ │ │ │ ├── CannotHaveExtensionReceivers.kt │ │ │ │ ├── CannotHaveTypeArgs.kt │ │ │ │ ├── CannotBeScoped.kt │ │ │ │ └── ContextParamsCannotBeOptional.kt │ │ │ ├── provides │ │ │ │ ├── Binds_Interface_OkCase.kt │ │ │ │ ├── PrivateProviderOption_Error.fir.diag.txt │ │ │ │ ├── ProvidesPropertiesCannotBeMutable.fir.diag.txt │ │ │ │ ├── Binds_interface_ShouldNotHaveBodies.fir.diag.txt │ │ │ │ ├── ProvidesShouldBePrivate_InInterface.fir.diag.txt │ │ │ │ ├── ProvidesShouldBePrivate_InAbstractClass.fir.diag.txt │ │ │ │ ├── BindsWithBodiesShouldBePrivate_InInterface.fir.diag.txt │ │ │ │ ├── BindsWithBodiesShouldBePrivate_InAbstractClass.fir.diag.txt │ │ │ │ ├── ProvidesCannotLiveInObjects.kt │ │ │ │ ├── LazyAssistedFactoryProvides.fir.diag.txt │ │ │ │ ├── ProvidesFunctionsCannotBeTopLevel.kt │ │ │ │ ├── ProvidesMustHaveABody_Interface.kt │ │ │ │ ├── ProvidesPropertiesCannotBeMutable.kt │ │ │ │ ├── AssistedParametersAreNotSupportedOnProvides.kt │ │ │ │ ├── AssistedParametersAreNotSupportedOnProvides.fir.diag.txt │ │ │ │ ├── ProvidesMustHaveABody_Interface.fir.diag.txt │ │ │ │ ├── ProvidesMustHaveABody_AbstractClass.kt │ │ │ │ ├── ProvidesMustHaveABody_AbstractClass.fir.diag.txt │ │ │ │ ├── PrivateProviderOption_None.kt │ │ │ │ ├── ProvidesFunctionsCannotBeTopLevel.fir.diag.txt │ │ │ │ ├── BindsNonThisReturningBodiesShouldError_Interface.kt │ │ │ │ ├── BindsNonThisReturningBodiesShouldError_AbstractClass.kt │ │ │ │ ├── ProvidesCannotHaveReceivers_AbstractClass.kt │ │ │ │ ├── ProvidesCannotHaveReceivers_Interface.kt │ │ │ │ ├── ProvidesWithExtensionsAndNonThisReturningBodiesShouldError.kt │ │ │ │ ├── Provides_Interface_MayNotHaveTypeParameters.fir.diag.txt │ │ │ │ ├── ProvidesNamesMustBeUniqueInContainer.kt │ │ │ │ ├── ProvidedInjectedClassesWithMatchingTypeKeysAreReportedAsWarnings.fir.diag.txt │ │ │ │ ├── Provides_AbstractClass_MayNotHaveTypeParameters.fir.diag.txt │ │ │ │ ├── Binds_interface_BoundTypesMustBeSubtypes.kt │ │ │ │ ├── ProvidesCannotLiveInObjects.fir.diag.txt │ │ │ │ ├── Binds_interface_ShouldNotHaveBodies.kt │ │ │ │ ├── ProvidedInjectedClassesWithMatchingTypeKeysButDifferentScopesAreOk.kt │ │ │ │ ├── PrivateProviderOption_Error.kt │ │ │ │ ├── ProvidedInjectedClassesWithMatchingTypeKeysAreReportedAsWarnings.kt │ │ │ │ ├── ProvidesNamesMustBeUniqueInGraph.fir.diag.txt │ │ │ │ ├── Binds_interface_BoundTypesMustBeSubtypes.fir.diag.txt │ │ │ │ ├── ProvidedInjectedClassesWithMatchingTypeKeysAreREportedAsWarnings_Qualified.fir.diag.txt │ │ │ │ ├── Provides_Interface_MayNotHaveTypeParameters.kt │ │ │ │ ├── ProvidesNamesMustBeUniqueInGraph.kt │ │ │ │ ├── ProvidesShouldBePrivate_InInterface.kt │ │ │ │ ├── Provides_AbstractClass_MayNotHaveTypeParameters.kt │ │ │ │ ├── BindsWithBodiesShouldBePrivate_InInterface.kt │ │ │ │ ├── DaggerReusable_IsUnsupported.kt │ │ │ │ ├── ProvidesNamesMustBeUniqueInContainer.fir.diag.txt │ │ │ │ ├── BindsWithBodiesShouldBePrivate_InAbstractClass.kt │ │ │ │ ├── ProvidesMustHaveExplicitReturnTypes.fir.diag.txt │ │ │ │ ├── BindsMayNotHaveScopes.fir.diag.txt │ │ │ │ ├── ProvidedInjectedClassesWithMatchingTypeKeysAreREportedAsWarnings_Qualified.kt │ │ │ │ ├── ProvidesShouldBePrivate_InAbstractClass.kt │ │ │ │ ├── DaggerReusable_IsUnsupported.fir.diag.txt │ │ │ │ ├── BindsNonThisReturningBodiesShouldError_Interface.fir.diag.txt │ │ │ │ ├── BindsNonThisReturningBodiesShouldError_AbstractClass.fir.diag.txt │ │ │ │ ├── ProvidesCannotHaveReceivers_Interface.fir.diag.txt │ │ │ │ ├── ProvidesCannotHaveReceivers_AbstractClass.fir.diag.txt │ │ │ │ ├── BindsMayNotHaveScopes.kt │ │ │ │ └── ProvidesWithExtensionsAndNonThisReturningBodiesShouldError.fir.diag.txt │ │ │ ├── inject │ │ │ │ ├── assisted │ │ │ │ │ ├── AssistedFactoriesCannotBeLocal.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBePrivate.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBeProtected.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBeEnums.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBeFinal.fir.diag.txt │ │ │ │ │ ├── AssistedFactoryWithMissingSAM.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBeSealedClasses.fir.diag.txt │ │ │ │ │ ├── LazyAssistedFactoryInjection.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBeAnnotationClasses.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBeAnnotationObjects.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBeSealedInterfaces.fir.diag.txt │ │ │ │ │ ├── AssistedFactoryWithMissingSAM.kt │ │ │ │ │ ├── AssistedFactoriesCannotBeAnnotationClasses.kt │ │ │ │ │ ├── AssistedFactoryMustTargetAssistedInjectTypesButMissingConstructor.kt │ │ │ │ │ ├── LazyAssistedFactoryInjection.kt │ │ │ │ │ ├── AssistedFactoriesCannotBeLocal.kt │ │ │ │ │ ├── AssistedFactoriesCannotBeSealedClasses.kt │ │ │ │ │ ├── AssistedFactoriesCannotBeSealedInterfaces.kt │ │ │ │ │ ├── AssistedFactoriesCannotBePrivate.kt │ │ │ │ │ ├── AssistedFactoryMustTargetAssistedInjectTypesWithMatchingParameters.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBeProtected.kt │ │ │ │ │ ├── AssistedFactoryMustTargetAssistedInjectTypesButMissingReturnType.kt │ │ │ │ │ ├── AssistedFactoryWithMultipleSAMs.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBeFinal.kt │ │ │ │ │ ├── AssistedFactoryMustTargetAssistedInjectTypesButMissingReturnType.fir.diag.txt │ │ │ │ │ ├── AssistedFactoriesCannotBeAnnotationObjects.kt │ │ │ │ │ ├── AssistedFactoryMustTargetAssistedInjectTypesButMissingConstructor.fir.diag.txt │ │ │ │ │ ├── AssistedFactoryMustTargetAssistedInjectTypesWithMatchingParameters.kt │ │ │ │ │ ├── AssistedFactoryWithMultipleSAMs.kt │ │ │ │ │ └── AssistedFactoriesCannotBeEnums.kt │ │ │ │ ├── InjectingAPlainObjectIsSus.kt │ │ │ │ ├── member │ │ │ │ │ ├── FunctionMemberInjectsCannotHaveTypeParams.kt │ │ │ │ │ ├── MissingMemberInjectionShouldFailBinding1.fir.ir.diag.txt │ │ │ │ │ ├── MissingMemberInjectionShouldFailBinding2.fir.ir.diag.txt │ │ │ │ │ └── MembersInjectorParameterWithNoDefaultShouldError.kt │ │ │ │ ├── InjectingAPlainObjectIsSus.fir.diag.txt │ │ │ │ ├── ConflictingProvidesAndClassScopes.fir.diag.txt │ │ │ │ ├── function │ │ │ │ │ ├── LazyAssistedFactoryFunctionInjection.fir.diag.txt │ │ │ │ │ └── LazyAssistedFactoryFunctionInjection.kt │ │ │ │ ├── ProvidingAConstructorInjectedTypeHasASpecificWarning.fir.diag.txt │ │ │ │ ├── ConflictingProvidesAndClassScopes.kt │ │ │ │ ├── SuggestInjectClassOnSingleContructor.fir.diag.txt │ │ │ │ ├── SuggestInjectClassOnSingleContructor.kt │ │ │ │ └── ProvidingAConstructorInjectedTypeHasASpecificWarning.kt │ │ │ ├── bindingcontainer │ │ │ │ ├── CannotAnnotateBothGraphAndContainer.fir.diag.txt │ │ │ │ ├── CannotAnnotateBothGraphAndContainer.kt │ │ │ │ ├── IncludedMustBeAContainer.fir.diag.txt │ │ │ │ ├── AbstractContainersCannotHaveProvides.fir.diag.txt │ │ │ │ ├── ContributedContainersMustHaveNoArgConstructors.fir.diag.txt │ │ │ │ ├── AbstractContainersCannotHaveProvides.kt │ │ │ │ ├── ContributedContainersMustHaveNoArgConstructors.kt │ │ │ │ ├── IncludedMustBeAContainer.kt │ │ │ │ ├── ContainersCannotExtendOtherContainers.kt │ │ │ │ ├── CannotIncludeGenericContainer.kt │ │ │ │ ├── ContainersCannotExtendOtherContainers.fir.diag.txt │ │ │ │ ├── CannotIncludeGenericContainer.fir.diag.txt │ │ │ │ └── NoProvidesOnParams.kt │ │ │ ├── dependencygraph │ │ │ │ ├── AsContributionCannotWorkOnContributedExtensions.fir.diag.txt │ │ │ │ ├── GraphsCannotDirectlyExtendOtherGraphs.fir.diag.txt │ │ │ │ ├── AsContributionCannotWorkOnContributedExtensionsMultiModule.fir.diag.txt │ │ │ │ ├── optional │ │ │ │ │ ├── OptionalBindingIsNotAllowedOnInjectors.kt │ │ │ │ │ ├── OptionalBindingIsNotAllowedOnInjectors.fir.diag.txt │ │ │ │ │ ├── RequiredAnnotationResultsInMissingBindingMultiModule.fir.ir.diag.txt │ │ │ │ │ ├── OptionalBindingParamWarningIfDefault.kt │ │ │ │ │ ├── DisabledResultsInMissingBindings.kt │ │ │ │ │ ├── OptionalBindingErrorIfDisabled.kt │ │ │ │ │ ├── DisabledResultsInMissingBindingsEvenWithAnnotation.kt │ │ │ │ │ ├── RequiredAnnotationResultsInMissingBindings.kt │ │ │ │ │ ├── OptionalBindingParamRequiresDefaultValue.kt │ │ │ │ │ ├── DisabledResultsInMissingBindingMultiModule.kt │ │ │ │ │ └── RequiredAnnotationResultsInMissingBindingMultiModule.kt │ │ │ │ ├── MissingBindingHintsShouldReportInternalOnlyIfInternal.fir.ir.diag.txt │ │ │ │ ├── ConfigurableMaxIrErrors.fir.ir.diag.txt │ │ │ │ ├── AssistedTypesCannotBeDirectlyQualified.fir.diag.txt │ │ │ │ ├── leniency │ │ │ │ │ ├── SomeUnusedAndSomeUsed.kt │ │ │ │ │ └── SomeUnusedAndSomeUsed.fir.ir.diag.txt │ │ │ │ ├── GraphsCannotDirectlyExtendOtherGraphs.kt │ │ │ │ ├── extensions │ │ │ │ │ └── ExtensionsWithFactoriesMustUseThem.fir.diag.txt │ │ │ │ ├── AssistedTypesCannotBeProvidedWithoutQualifiers.fir.diag.txt │ │ │ │ ├── AllDuplicateBindingsAreReported.kt │ │ │ │ ├── AssistedTypesCannotBeProvidedWithoutQualifiers.kt │ │ │ │ ├── InternalBindings.fir.ir.diag.txt │ │ │ │ ├── MultipleMissingDeps.kt │ │ │ │ ├── dynamic │ │ │ │ │ └── CreateDynamicGraphCannotBeInLocalClasses.fir.diag.txt │ │ │ │ ├── MismatchedSingleInScopesDisambiguateSameNameScopes.fir.ir.diag.txt │ │ │ │ ├── UsefulHintsForMissingImplDeps.kt │ │ │ │ ├── MismatchedSingleInScopesDisambiguateSameNameScopes.kt │ │ │ │ ├── MixedCycleParams.fir.ir.diag.txt │ │ │ │ ├── AssistedTypesCannotBeDirectlyQualified.kt │ │ │ │ ├── MissingBindingHintsShouldReportInternalOnlyIfInternal.kt │ │ │ │ └── MixedCycleParams.kt │ │ │ ├── createGraph │ │ │ │ ├── CreateGraph_MustBeGraph.kt │ │ │ │ ├── GraphFactoriesMayNotHaveVarargs.fir.diag.txt │ │ │ │ ├── CreateGraph_MustBeGraph.fir.diag.txt │ │ │ │ ├── CreateGraph_MustBeGraphFactory.fir.diag.txt │ │ │ │ ├── CreateGraph_GraphHasFactory.fir.diag.txt │ │ │ │ ├── CreateGraph_GraphHasFactory.kt │ │ │ │ ├── CreateGraph_MustBeGraphFactory.kt │ │ │ │ ├── GraphFactoriesMayNotHaveVarargs.kt │ │ │ │ └── CreateGraph_OkCase.kt │ │ │ ├── interop │ │ │ │ └── dagger │ │ │ │ │ ├── DoNotSuggestMovingInjectAnnotationToClassWhenUsingJavaxOrJakartaInject.fir.diag.txt │ │ │ │ │ ├── ModulesWithConstructorInjectedFields.fir.diag.txt │ │ │ │ │ ├── DoNotSuggestMovingInjectAnnotationToClassWhenUsingJavaxOrJakartaInject.kt │ │ │ │ │ ├── MemberInjectionQualifiersAreLookedUp.fir.ir.diag.txt │ │ │ │ │ ├── PositionalAnnotationArgsError.fir.diag.txt │ │ │ │ │ ├── PositionalAnnotationArgsError.kt │ │ │ │ │ ├── PositionalAnnotationArgsWarning.kt │ │ │ │ │ ├── PositionalAnnotationArgsWarning.fir.diag.txt │ │ │ │ │ └── BindsOptionalOfDiagnostics.kt │ │ │ ├── aggregation │ │ │ │ ├── InternalHintsAreNotVisibleWithoutFriends.fir.ir.diag.txt │ │ │ │ ├── InternalContributionMissingHint.fir.ir.diag.txt │ │ │ │ ├── InternalContributionMissingHint.kt │ │ │ │ └── InternalHintsAreNotVisibleWithoutFriends.kt │ │ │ └── graph │ │ │ │ ├── LazyAssistedFactoryGraphAccessor.fir.diag.txt │ │ │ │ └── LazyAssistedFactoryGraphAccessor.kt │ │ └── box │ │ │ ├── multibindings │ │ │ ├── UnusedMultibindingsDoNotGetValidated.kt │ │ │ └── LazyMemberInjectedBindings.kt │ │ │ ├── dependencygraph │ │ │ ├── GraphsCanHaveExistingImplClases.kt │ │ │ ├── OpenAccessorsInClasses.kt │ │ │ ├── leniency │ │ │ │ ├── UnusedProvidersAreNotValidated.kt │ │ │ │ └── UnusedProvidersInContainersAreNotValidated.kt │ │ │ ├── GraphFactoriesSupportGenericProviders.kt │ │ │ ├── ProvidingEmptyProviderMapDirectly.kt │ │ │ ├── extensions │ │ │ │ ├── ExtensionsCanBeDeclaredWithoutFactories.kt │ │ │ │ ├── ExtensionsUsingDeferredTypesAreValid.kt │ │ │ │ ├── SimpleExtension.kt │ │ │ │ ├── FieldInjectorInGraphExtensionContainer.kt │ │ │ │ ├── MultipleExtensionFactoriesAreValid.kt │ │ │ │ └── ManagedBindingContainerInstancesPlumbDown.kt │ │ │ ├── dynamic │ │ │ │ └── GraphsAreCachedByType.kt │ │ │ ├── bindingcontainers │ │ │ │ ├── BindingContainerViaAnnotationCycleIsOk.kt │ │ │ │ └── BindingContainerViaCreator.kt │ │ │ ├── ExposingIncludedGraphsDirectly.kt │ │ │ ├── ProvidingEmptyMultibindingsDirectly.kt │ │ │ └── OverrideCompatibleAccessorsFromContributedInterface.kt │ │ │ ├── inject │ │ │ ├── DefaultValuesPropagateToNewInstanceParams.kt │ │ │ ├── InjectedTypeInheritsAnAnnotatedAbstractClass.kt │ │ │ ├── member │ │ │ │ ├── MultiInheritanceMemberInject.kt │ │ │ │ ├── MemberInjectorRequest.kt │ │ │ │ ├── GenericMemberInjectorRequest.kt │ │ │ │ └── MemberInjectorRequestAsProvidesParam.kt │ │ │ └── assisted │ │ │ │ ├── ImplsAreVisibleAcrossModules.kt │ │ │ │ ├── NoAssistedArgsInAssistedInject.kt │ │ │ │ ├── AssistedTypesCanBeProvidedWithQualifiers.kt │ │ │ │ ├── DefaultAssistedFactoryIsGeneratedInFIR.kt │ │ │ │ └── DefaultAssistedFactoryWithDefaultValues.kt │ │ │ ├── provides │ │ │ ├── DefaultValuesPropagateToNewInstanceParams.kt │ │ │ ├── SimpleFunctionProvider.kt │ │ │ ├── JvmFieldProvidersAreRespected.kt │ │ │ ├── CapitalizedProvides.kt │ │ │ └── QualifiersOnDifferentAnnotationSites.kt │ │ │ ├── cycles │ │ │ ├── SimpleBindingIntoMulti.kt │ │ │ ├── SelfCycle.kt │ │ │ └── BindsCycleGraph.kt │ │ │ ├── aggregation │ │ │ ├── AnyIsAValidSupertype.kt │ │ │ ├── ExcludesWithOrigin.kt │ │ │ ├── InternalHintsInGraph.kt │ │ │ ├── ReplacementsWithOrigin.kt │ │ │ ├── ContributingMultibileNullableBindings.kt │ │ │ └── ContributedBindingContainerReplacements.kt │ │ │ ├── bindingcontainers │ │ │ ├── PrivateBindsProperty.kt │ │ │ ├── MultibindsOnlyInContainer.kt │ │ │ └── SimpleContainersWithHintsWork.kt │ │ │ ├── member │ │ │ ├── SimpleAncestorInjectionWithEmptyChild.kt │ │ │ ├── SimpleAncestorInjectionWithEmptyChildNoFactory.kt │ │ │ ├── SimpleAncestorInjectionWithEmptyChildWithParentInAnotherModule.kt │ │ │ └── AncestorInjectionWithEmptyDescendants.kt │ │ │ └── interop │ │ │ ├── dagger │ │ │ ├── DaggerFactoryClassCanBeLoaded.kt │ │ │ ├── DaggerFactoryClassCanBeLoadedJakarta.kt │ │ │ ├── DaggerComponentModulesAnnotationInterop.kt │ │ │ ├── DaggerMultibindsAllowEmptyByDefault.kt │ │ │ ├── AnotherBindsOptionalPresentTest.kt │ │ │ ├── InjectedJavaxProviderInteropWorks.kt │ │ │ ├── JavaxProviderShouldWorkInSet.kt │ │ │ ├── QualifiedDaggerFactoryClassCanBeLoaded.kt │ │ │ ├── GenericDaggerFactoryClassCanBeLoaded.kt │ │ │ ├── JavaxProviderShouldWorkInMap.kt │ │ │ └── ZeroArgConstructorInjectionGeneratedByAnvil.kt │ │ │ └── guice │ │ │ ├── InjectedGuiceProviderInteropWorks.kt │ │ │ └── InjectedKotlinLazyFromGuiceProviderWorks.kt │ └── kotlin │ │ └── dev │ │ └── zacsweers │ │ └── metro │ │ └── compiler │ │ ├── KotlinTestImportPreprocessor.kt │ │ ├── MetroDefaultImportPreprocessor.kt │ │ └── interop │ │ └── Jsr330Utils.kt │ ├── generator220 │ └── kotlin │ │ └── dev │ │ └── zacsweers │ │ └── metro │ │ └── compiler │ │ └── MetroKotlinStandardLibrariesPathProvider.kt │ ├── generator230 │ └── kotlin │ │ └── dev │ │ └── zacsweers │ │ └── metro │ │ └── compiler │ │ └── MetroKotlinStandardLibrariesPathProvider.kt │ └── generator2320 │ └── kotlin │ └── dev │ └── zacsweers │ └── metro │ └── compiler │ └── MetroKotlinStandardLibrariesPathProvider.kt ├── benchmark ├── startup-android │ ├── app │ │ ├── proguard-rules.pro │ │ └── src │ │ │ └── main │ │ │ ├── res │ │ │ └── values │ │ │ │ └── strings.xml │ │ │ └── kotlin │ │ │ └── dev │ │ │ └── zacsweers │ │ │ └── metro │ │ │ └── benchmark │ │ │ └── startup │ │ │ └── android │ │ │ ├── MainActivity.kt │ │ │ └── BenchmarkApplication.kt │ ├── microbenchmark │ │ └── src │ │ │ └── main │ │ │ └── AndroidManifest.xml │ └── benchmark │ │ └── src │ │ └── main │ │ └── AndroidManifest.xml ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── startup-jvm │ ├── build.gradle.kts │ └── minified-jar │ │ └── proguard-rules.pro └── gradle.properties ├── spotless ├── spotless.java └── spotless.kt ├── runtime ├── gradle.properties └── src │ ├── commonMain │ └── kotlin │ │ └── dev │ │ └── zacsweers │ │ └── metro │ │ ├── internal │ │ ├── Factory.kt │ │ ├── GraphFactoryInvokeFunctionMarker.kt │ │ ├── MetroImplMarker.kt │ │ ├── MetroContribution.kt │ │ ├── InjectedFunctionClass.kt │ │ ├── AssistedMarker.kt │ │ └── MultibindingElement.kt │ │ ├── Includes.kt │ │ └── Named.kt │ └── commonTest │ └── kotlin │ └── dev │ └── zacsweers │ └── metro │ └── internal │ └── SimpleCounter.kt ├── docs ├── site-assets │ └── img │ │ ├── favicon.ico │ │ └── favicon-readme.txt └── benchmark_assets │ ├── runtime_jvm.png │ ├── benchmark_abi.png │ ├── benchmark_noabi.png │ ├── runtime_android.png │ ├── runtime_jvm_r8.png │ └── benchmark_graph_processing.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── metrox-android ├── gradle.properties └── src │ └── main │ ├── AndroidManifest.xml │ └── kotlin │ └── dev │ └── zacsweers │ └── metrox │ └── android │ ├── ServiceKey.kt │ ├── ActivityKey.kt │ ├── BroadcastReceiverKey.kt │ └── ContentProviderKey.kt ├── interop-dagger ├── gradle.properties ├── build.gradle.kts └── api │ └── interop-dagger.api ├── interop-guice ├── gradle.properties └── build.gradle.kts ├── interop-javax ├── gradle.properties ├── api │ └── interop-javax.api └── build.gradle.kts ├── metrox-viewmodel ├── gradle.properties └── src │ └── commonMain │ └── kotlin │ └── dev │ └── zacsweers │ └── metrox │ └── viewmodel │ └── ViewModelScope.kt ├── interop-jakarta ├── gradle.properties ├── api │ └── interop-jakarta.api └── build.gradle.kts ├── samples ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── integration-tests │ ├── README.md │ └── src │ │ ├── androidMain │ │ └── res │ │ │ └── layout │ │ │ └── activity_main.xml │ │ ├── commonTest │ │ └── kotlin │ │ │ └── dev │ │ │ └── zacsweers │ │ │ └── metro │ │ │ └── test │ │ │ └── integration │ │ │ ├── Callable.kt │ │ │ ├── Platform.kt │ │ │ └── Singleton.kt │ │ ├── jsTest │ │ └── kotlin │ │ │ └── dev │ │ │ └── zacsweers │ │ │ └── metro │ │ │ └── test │ │ │ └── integration │ │ │ └── Platform.js.kt │ │ ├── commonJvmTest │ │ └── kotlin │ │ │ └── dev │ │ │ └── zacsweers │ │ │ └── metro │ │ │ └── test │ │ │ └── integration │ │ │ └── Platform.jvm.kt │ │ ├── nativeTest │ │ └── kotlin │ │ │ └── dev │ │ │ └── zacsweers │ │ │ └── metro │ │ │ └── test │ │ │ └── integration │ │ │ └── Platform.native.kt │ │ ├── commonWasmTest │ │ └── kotlin │ │ │ └── dev │ │ │ └── zacsweers │ │ │ └── metro │ │ │ └── test │ │ │ └── integration │ │ │ └── Platform.wasm.kt │ │ └── androidUnitTest │ │ └── kotlin │ │ └── dev │ │ └── zacsweers │ │ └── metro │ │ └── test │ │ └── integration │ │ └── replaces │ │ └── AndroidPlatformContribution.kt ├── android-app │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── values │ │ │ │ └── ic_launcher_background.xml │ │ │ └── mipmap-anydpi-v26 │ │ │ │ └── ic_launcher.xml │ │ │ └── kotlin │ │ │ └── dev │ │ │ └── zacsweers │ │ │ └── metro │ │ │ └── sample │ │ │ └── android │ │ │ ├── FragmentKey.kt │ │ │ └── WorkerKey.kt │ └── README.md ├── compose-viewmodels │ ├── app │ │ └── src │ │ │ ├── androidMain │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ └── ic_launcher_background.xml │ │ │ │ └── mipmap-anydpi-v26 │ │ │ │ │ └── ic_launcher.xml │ │ │ └── kotlin │ │ │ │ └── dev │ │ │ │ └── zacsweers │ │ │ │ └── metro │ │ │ │ └── sample │ │ │ │ └── composeviewmodels │ │ │ │ └── app │ │ │ │ ├── Graphs.kt │ │ │ │ └── MetroApp.kt │ │ │ ├── jvmMain │ │ │ └── kotlin │ │ │ │ └── dev │ │ │ │ └── zacsweers │ │ │ │ └── metro │ │ │ │ └── sample │ │ │ │ └── composeviewmodels │ │ │ │ └── app │ │ │ │ ├── Graphs.kt │ │ │ │ └── Main.kt │ │ │ └── commonMain │ │ │ └── kotlin │ │ │ └── dev │ │ │ └── zacsweers │ │ │ └── metro │ │ │ └── sample │ │ │ └── composeviewmodels │ │ │ └── app │ │ │ └── Routes.kt │ ├── screen-home │ │ └── build.gradle.kts │ ├── screen-details │ │ └── build.gradle.kts │ └── screen-settings │ │ └── build.gradle.kts ├── circuit-app │ └── src │ │ └── wasmJsMain │ │ ├── resources │ │ └── index.html │ │ └── kotlin │ │ └── dev │ │ └── zacsweers │ │ └── metro │ │ └── sample │ │ └── circuit │ │ └── main.kt ├── interop │ ├── customAnnotations-kotlinInject │ │ ├── src │ │ │ └── commonTest │ │ │ │ └── kotlin │ │ │ │ └── dev │ │ │ │ └── zacsweers │ │ │ │ └── metro │ │ │ │ └── sample │ │ │ │ ├── Singleton.kt │ │ │ │ └── Named.kt │ │ └── build.gradle.kts │ ├── dependencies-kotlinInject │ │ ├── src │ │ │ └── test │ │ │ │ └── kotlin │ │ │ │ └── dev │ │ │ │ └── zacsweers │ │ │ │ └── metro │ │ │ │ └── sample │ │ │ │ ├── StringComponent.kt │ │ │ │ └── StringGraph.kt │ │ └── build.gradle.kts │ ├── customAnnotations-guice │ │ └── build.gradle.kts │ ├── dependencies-dagger │ │ ├── build.gradle.kts │ │ └── src │ │ │ └── test │ │ │ └── kotlin │ │ │ └── dev │ │ │ └── zacsweers │ │ │ └── metro │ │ │ └── sample │ │ │ ├── StringComponent.kt │ │ │ └── StringGraph.kt │ └── customAnnotations-dagger │ │ └── build.gradle.kts ├── weather-app │ ├── src │ │ └── jvmMain │ │ │ └── kotlin │ │ │ └── dev │ │ │ └── zacsweers │ │ │ └── metro │ │ │ └── sample │ │ │ └── weather │ │ │ └── JvmAppGraph.kt │ └── README.md └── graph-analysis │ └── build.gradle.kts ├── compiler ├── src │ └── main │ │ ├── resources │ │ └── META-INF │ │ │ └── services │ │ │ ├── org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor │ │ │ └── org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar │ │ └── kotlin │ │ └── dev │ │ └── zacsweers │ │ └── metro │ │ └── compiler │ │ ├── ir │ │ └── IrBindingContainerCallable.kt │ │ ├── graph │ │ ├── MissingBindingHints.kt │ │ └── BaseTypeKey.kt │ │ ├── exceptions.kt │ │ └── OptionalBindingBehavior.kt └── gradle.properties ├── gradle-plugin ├── gradle.properties └── src │ ├── main │ └── kotlin │ │ └── dev │ │ └── zacsweers │ │ └── metro │ │ └── gradle │ │ ├── MetroExtensionMarker.kt │ │ ├── KotlinVersions.kt │ │ ├── metroGradleUtil.kt │ │ └── DiagnosticSeverity.kt │ └── functionalTest │ └── kotlin │ └── dev │ └── zacsweers │ └── metro │ └── gradle │ └── MetroOptionOverrides.kt ├── metrox-viewmodel-compose ├── gradle.properties └── api │ └── metrox-viewmodel-compose.api ├── .idea ├── externalDependencies.xml └── kotlinTestDataPluginTestDataPaths.xml ├── .gitattributes ├── RELEASING.md ├── scripts └── generate_docs_dokka.sh └── .gitignore /.github/workflows/.java-version: -------------------------------------------------------------------------------- 1 | 24 -------------------------------------------------------------------------------- /compiler-compat/k2220/version.txt: -------------------------------------------------------------------------------- 1 | 2.2.20 -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/fir/scratch.kt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/scratch.kt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /compiler-compat/k230_beta1/version.txt: -------------------------------------------------------------------------------- 1 | 2.3.0-Beta1 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/scratch.fir.kt.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /compiler-compat/k2320_dev_5437/version.txt: -------------------------------------------------------------------------------- 1 | 2.3.20-dev-5437 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/fir/scratch.fir.txt: -------------------------------------------------------------------------------- 1 | FILE: scratch.kt 2 | -------------------------------------------------------------------------------- /benchmark/startup-android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Not necessary for our use 2 | -dontobfuscate -------------------------------------------------------------------------------- /spotless/spotless.java: -------------------------------------------------------------------------------- 1 | // Copyright (C) $YEAR Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 -------------------------------------------------------------------------------- /spotless/spotless.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) $YEAR Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 -------------------------------------------------------------------------------- /runtime/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Metro Runtime 2 | POM_ARTIFACT_ID=runtime 3 | POM_PACKAGING=jar 4 | -------------------------------------------------------------------------------- /docs/site-assets/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZacSweers/metro/HEAD/docs/site-assets/img/favicon.ico -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZacSweers/metro/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /metrox-android/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Metrox Android 2 | POM_ARTIFACT_ID=metrox-android 3 | POM_PACKAGING=aar 4 | -------------------------------------------------------------------------------- /interop-dagger/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Metro Dagger Inteorp 2 | POM_ARTIFACT_ID=interop-dagger 3 | POM_PACKAGING=jar 4 | -------------------------------------------------------------------------------- /interop-guice/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Metro Guice Interop 2 | POM_ARTIFACT_ID=interop-guice 3 | POM_PACKAGING=jar 4 | -------------------------------------------------------------------------------- /interop-javax/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Metro Javax Interop 2 | POM_ARTIFACT_ID=interop-javax 3 | POM_PACKAGING=jar 4 | -------------------------------------------------------------------------------- /metrox-viewmodel/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Metrox ViewModel 2 | POM_ARTIFACT_ID=metrox-viewmodel 3 | POM_PACKAGING=jar 4 | -------------------------------------------------------------------------------- /docs/benchmark_assets/runtime_jvm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZacSweers/metro/HEAD/docs/benchmark_assets/runtime_jvm.png -------------------------------------------------------------------------------- /interop-jakarta/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Metro Jakarta Interop 2 | POM_ARTIFACT_ID=interop-jakarta 3 | POM_PACKAGING=jar 4 | -------------------------------------------------------------------------------- /docs/benchmark_assets/benchmark_abi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZacSweers/metro/HEAD/docs/benchmark_assets/benchmark_abi.png -------------------------------------------------------------------------------- /docs/benchmark_assets/benchmark_noabi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZacSweers/metro/HEAD/docs/benchmark_assets/benchmark_noabi.png -------------------------------------------------------------------------------- /docs/benchmark_assets/runtime_android.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZacSweers/metro/HEAD/docs/benchmark_assets/runtime_android.png -------------------------------------------------------------------------------- /docs/benchmark_assets/runtime_jvm_r8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZacSweers/metro/HEAD/docs/benchmark_assets/runtime_jvm_r8.png -------------------------------------------------------------------------------- /samples/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZacSweers/metro/HEAD/samples/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /benchmark/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZacSweers/metro/HEAD/benchmark/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/injectconstructor/DefaultValuesPropagateToNewInstanceParams.kt: -------------------------------------------------------------------------------- 1 | @Inject class ValueHolder(stringValue: String? = null) 2 | -------------------------------------------------------------------------------- /docs/benchmark_assets/benchmark_graph_processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZacSweers/metro/HEAD/docs/benchmark_assets/benchmark_graph_processing.png -------------------------------------------------------------------------------- /compiler/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor: -------------------------------------------------------------------------------- 1 | dev.zacsweers.metro.compiler.MetroCommandLineProcessor 2 | -------------------------------------------------------------------------------- /compiler/src/main/resources/META-INF/services/org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar: -------------------------------------------------------------------------------- 1 | dev.zacsweers.metro.compiler.MetroCompilerPluginRegistrar 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/functioninject/CannotHaveTypeArgs.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /CannotHaveTypeArgs.kt:(112,115): error: Injected functions cannot be generic. 2 | -------------------------------------------------------------------------------- /compiler/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Metro Compiler 2 | POM_ARTIFACT_ID=compiler 3 | POM_PACKAGING=jar 4 | 5 | # kotlinc imposes its own 6 | kotlin.stdlib.default.dependency=false -------------------------------------------------------------------------------- /compiler-compat/k2220/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.compat.CompatContext$Factory: -------------------------------------------------------------------------------- 1 | dev.zacsweers.metro.compiler.compat.k2220.CompatContextImpl$Factory -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/functioninject/CannotBeScoped.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /CannotBeScoped.kt:(100,126): error: Injected functions are stateless and should not be scoped. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/Binds_Interface_OkCase.kt: -------------------------------------------------------------------------------- 1 | interface ExampleGraph { 2 | @Binds val Int.bind: Number 3 | @Binds fun String.bind(): CharSequence 4 | } 5 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/PrivateProviderOption_Error.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /PrivateProviderOption_Error.kt:(240,253): error: `@Provides` declarations should be private. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesPropertiesCannotBeMutable.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesPropertiesCannotBeMutable.kt:(150,160): error: @Provides properties cannot be var 2 | -------------------------------------------------------------------------------- /samples/integration-tests/README.md: -------------------------------------------------------------------------------- 1 | Metro Integration Tests 2 | ======================= 3 | 4 | TODO - document remote debugging setup. Ideally an easy way to test individual components 5 | -------------------------------------------------------------------------------- /compiler-compat/k230_beta1/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.compat.CompatContext$Factory: -------------------------------------------------------------------------------- 1 | dev.zacsweers.metro.compiler.compat.k230_beta1.CompatContextImpl$Factory 2 | -------------------------------------------------------------------------------- /gradle-plugin/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Metro Gradle Plugin 2 | POM_ARTIFACT_ID=gradle-plugin 3 | POM_PACKAGING=jar 4 | 5 | # Gradle imposes its own 6 | kotlin.stdlib.default.dependency=false 7 | -------------------------------------------------------------------------------- /samples/android-app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/functioninject/CannotHaveExtensionReceivers.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /CannotHaveExtensionReceivers.kt:(112,118): error: Injected functions cannot have receiver parameters. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/Binds_interface_ShouldNotHaveBodies.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /Binds_interface_ShouldNotHaveBodies.kt:(226,230): warning: `@Binds` declarations should be private. 2 | -------------------------------------------------------------------------------- /compiler-compat/k2320_dev_5437/src/main/resources/META-INF/services/dev.zacsweers.metro.compiler.compat.CompatContext$Factory: -------------------------------------------------------------------------------- 1 | dev.zacsweers.metro.compiler.compat.k2320_dev_5437.CompatContextImpl$Factory 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesShouldBePrivate_InInterface.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesShouldBePrivate_InInterface.kt:(239,252): warning: `@Provides` declarations should be private. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/functioninject/ContextParamsCannotBeOptional.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ContextParamsCannotBeOptional.kt:(166,172): error: Context parameters cannot be annotated @OptionalBinding. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeLocal.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoriesCannotBeLocal.kt:(133,152): error: @AssistedFactory declarations cannot be local classes. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesShouldBePrivate_InAbstractClass.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesShouldBePrivate_InAbstractClass.kt:(280,293): warning: `@Provides` declarations should be private. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/provides/DefaultValuesPropagateToNewInstanceParams.kt: -------------------------------------------------------------------------------- 1 | interface IntProvider { 2 | @Provides fun provideInt(stringValue: String? = null): Int = stringValue?.toInt() ?: 0 3 | } -------------------------------------------------------------------------------- /metrox-viewmodel-compose/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Metrox ViewModel Compose 2 | POM_ARTIFACT_ID=metrox-viewmodel-compose 3 | POM_PACKAGING=jar 4 | 5 | org.jetbrains.compose.experimental.macos.enabled=true 6 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBePrivate.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoriesCannotBePrivate.kt:(150,157): error: @AssistedFactory declarations must be public or internal. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/BindsWithBodiesShouldBePrivate_InInterface.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /BindsWithBodiesShouldBePrivate_InInterface.kt:(247,260): warning: `@Binds` declarations should be private. 2 | -------------------------------------------------------------------------------- /benchmark/startup-android/microbenchmark/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeProtected.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoriesCannotBeProtected.kt:(150,159): error: @AssistedFactory declarations must be public or internal. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/fir/aggregation/ContributingTypes.kt: -------------------------------------------------------------------------------- 1 | @ContributesTo(AppScope::class) 2 | interface ContributedInterface 3 | 4 | @DependencyGraph(scope = AppScope::class) 5 | interface ExampleGraph 6 | -------------------------------------------------------------------------------- /samples/android-app/README.md: -------------------------------------------------------------------------------- 1 | # Android Sample 2 | 3 | This is an extremely simple Android sample app that demonstrates using Metro to constructor-inject `Activity`, `Fragment`, and `ViewModel` with multibindings. 4 | -------------------------------------------------------------------------------- /samples/compose-viewmodels/app/src/androidMain/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | 5 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/BindsWithBodiesShouldBePrivate_InAbstractClass.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /BindsWithBodiesShouldBePrivate_InAbstractClass.kt:(252,265): warning: `@Binds` declarations should be private. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/InjectingAPlainObjectIsSus.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | object ObjectClass 3 | 4 | @Inject 5 | class Example(obj: ObjectClass) 6 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/member/FunctionMemberInjectsCannotHaveTypeParams.kt: -------------------------------------------------------------------------------- 1 | class Example { 2 | @Inject fun injectedFunction(value: T) { 3 | 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesCannotLiveInObjects.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | object InvalidContainer { 4 | @Provides fun provideString(): String = "Hello" 5 | } 6 | -------------------------------------------------------------------------------- /.idea/externalDependencies.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/functioninject/CannotHaveExtensionReceivers.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // ENABLE_TOP_LEVEL_FUNCTION_INJECTION 3 | @Inject 4 | fun String.Example() { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeEnums.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoriesCannotBeEnums.kt:(161,168): error: @AssistedFactory declarations should be non-sealed abstract classes or interfaces. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeFinal.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoriesCannotBeFinal.kt:(156,163): error: @AssistedFactory declarations should be non-sealed abstract classes or interfaces. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoryWithMissingSAM.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoryWithMissingSAM.kt:(160,167): error: @AssistedFactory declarations must have exactly one abstract function but found none. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/EmptyMapMultibindingsUseEmptyMap.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | // Uses emptyMap() in code gen 4 | @Multibinds(allowEmpty = true) 5 | val ints: Map 6 | } -------------------------------------------------------------------------------- /docs/site-assets/img/favicon-readme.txt: -------------------------------------------------------------------------------- 1 | - Emoji Icon Author: Google Noto Emoji fonts 2 | - Emoji Icon Source: https://github.com/googlefonts/noto-emoji/blob/main/svg/emoji_u1f687.svg 3 | - Emoji Icon License: Apache license, version 2.0 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/CannotAnnotateBothGraphAndContainer.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /CannotAnnotateBothGraphAndContainer.kt:(62,78): error: Classes cannot be annotated with both '@BindingContainer' and '@DependencyGraph'. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/functioninject/CannotHaveTypeArgs.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // ENABLE_TOP_LEVEL_FUNCTION_INJECTION 3 | @Inject 4 | fun Example() { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/functioninject/CannotBeScoped.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // ENABLE_TOP_LEVEL_FUNCTION_INJECTION 3 | @SingleIn(AppScope::class) 4 | @Inject 5 | fun Example() { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/InjectingAPlainObjectIsSus.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /InjectingAPlainObjectIsSus.kt:(108,119): warning: Suspicious injection of an unqualified object type 'ObjectClass'. This is probably unnecessary or unintentional. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeSealedClasses.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoriesCannotBeSealedClasses.kt:(163,170): error: @AssistedFactory declarations should be non-sealed abstract classes or interfaces. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/LazyAssistedFactoryInjection.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /LazyAssistedFactoryInjection.kt:(105,118): error: Metro does not support injecting Lazy because Foo.Factory is an @AssistedFactory-annotated type. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/ConflictingProvidesAndClassScopes.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ConflictingProvidesAndClassScopes.kt:(181,191): warning: Provided type 'Bar' is already constructor-injected but declares a different scope. This is likely a bug. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeAnnotationClasses.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoriesCannotBeAnnotationClasses.kt:(167,174): error: @AssistedFactory declarations should be non-sealed abstract classes or interfaces. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeAnnotationObjects.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoriesCannotBeAnnotationObjects.kt:(157,164): error: @AssistedFactory declarations should be non-sealed abstract classes or interfaces. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeSealedInterfaces.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoriesCannotBeSealedInterfaces.kt:(167,174): error: @AssistedFactory declarations should be non-sealed abstract classes or interfaces. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/LazyAssistedFactoryProvides.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /LazyAssistedFactoryProvides.kt:(443,466): error: Metro does not support injecting Lazy because MyAssistedFactory is an @AssistedFactory-annotated type. 2 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/kotlin/dev/zacsweers/metro/gradle/MetroExtensionMarker.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.gradle 4 | 5 | @DslMarker public annotation class MetroExtensionMarker 6 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/AsContributionCannotWorkOnContributedExtensions.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AsContributionCannotWorkOnContributedExtensions.kt:(608,618): error: `asContribution` receiver must be annotated with a `@DependencyGraph` annotation. 2 | -------------------------------------------------------------------------------- /samples/integration-tests/src/androidMain/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default behavior, in case people don't have core.autocrlf set. 2 | * text=auto 3 | 4 | compiler-tests/**/*.java linguist-generated=true 5 | **/yarn.lock linguist-generated=true 6 | **/package-lock.lock linguist-generated=true 7 | *.bat text eol=crlf 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/CannotAnnotateBothGraphAndContainer.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | @BindingContainer 5 | interface ConfusedContainer { 6 | @Binds val Int.bind: Number 7 | } 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesFunctionsCannotBeTopLevel.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | abstract class ExampleGraph { 5 | abstract val int: Int 6 | } 7 | 8 | @Provides fun provideInt(): Int = 0 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesMustHaveABody_Interface.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | interface ExampleGraph { 4 | @Provides val provideInt: Int 5 | @Provides fun provideString(): String 6 | } 7 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesPropertiesCannotBeMutable.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | abstract class ExampleGraph { 5 | abstract val int: Int 6 | 7 | @Provides var provideInt: Int = 0 8 | } 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/GraphsCannotDirectlyExtendOtherGraphs.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /module_main_GraphsCannotDirectlyExtendOtherGraphs.kt:(101,112): error: Graph class 'ChildGraph' may not directly extend graph class 'ParentGraph'. Use @GraphExtension instead. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/AssistedParametersAreNotSupportedOnProvides.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | interface Example { 4 | @Provides 5 | fun provideString(@Assisted int: Int): String = "Hello, assisted parameters" 6 | } 7 | -------------------------------------------------------------------------------- /samples/integration-tests/src/commonTest/kotlin/dev/zacsweers/metro/test/integration/Callable.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.test.integration 4 | 5 | fun interface Callable { 6 | fun call(): T 7 | } 8 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | Releasing 2 | ========= 3 | 4 | 1. Update the `CHANGELOG.md` for the impending release. 5 | - If the Kotlin version changed, update `compatibility.md` docs too. 6 | 2. Run `./release.sh (--patch|--minor|--major)`. 7 | 3. Publish the release on the repo's releases tab. 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/function/LazyAssistedFactoryFunctionInjection.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /LazyAssistedFactoryFunctionInjection.kt:(364,387): error: Metro does not support injecting Lazy because MyAssistedFactory is an @AssistedFactory-annotated type. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/fir/aggregation/ContributingTypesDependency.kt: -------------------------------------------------------------------------------- 1 | // MODULE: lib 2 | 3 | @ContributesTo(AppScope::class) 4 | interface ContributedInterface 5 | 6 | // MODULE: main(lib) 7 | 8 | @DependencyGraph(scope = AppScope::class) 9 | interface ExampleGraph 10 | -------------------------------------------------------------------------------- /runtime/src/commonMain/kotlin/dev/zacsweers/metro/internal/Factory.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.internal 4 | 5 | import dev.zacsweers.metro.Provider 6 | 7 | public fun interface Factory : Provider 8 | -------------------------------------------------------------------------------- /benchmark/startup-android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Metro Startup Benchmark 6 | 7 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/AssistedParametersAreNotSupportedOnProvides.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedParametersAreNotSupportedOnProvides.kt:(114,123): error: Assisted parameters are not supported for `@Provides` methods. Create a concrete assisted-injected factory class instead. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/MultibindingsWithComplexDependenciesGetProperties.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | val ints: Set 4 | 5 | @Provides fun provideString(): String = "3" 6 | @Provides @IntoSet fun provideInt(string: String): Int = string.toInt() 7 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesMustHaveABody_Interface.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesMustHaveABody_Interface.kt:(103,113): error: `@Provides` declarations must have bodies. 2 | 3 | /ProvidesMustHaveABody_Interface.kt:(135,148): error: `@Provides` declarations must have bodies. 4 | -------------------------------------------------------------------------------- /samples/integration-tests/src/commonTest/kotlin/dev/zacsweers/metro/test/integration/Platform.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.test.integration 4 | 5 | expect fun isJvm(): Boolean 6 | 7 | expect fun isWasm(): Boolean 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/multibindings/UnusedMultibindingsDoNotGetValidated.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | @Provides @IntoSet fun provideInt(string: String): Int = string.toInt() 4 | } 5 | 6 | fun box(): String { 7 | val graph = createGraph() 8 | return "OK" 9 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/AsContributionCannotWorkOnContributedExtensionsMultiModule.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /module_main_AsContributionCannotWorkOnContributedExtensionsMultiModule.kt:(361,371): error: `asContribution` receiver must be annotated with a `@DependencyGraph` annotation. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoryWithMissingSAM.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | ) { 6 | @AssistedFactory 7 | interface Factory 8 | } 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesMustHaveABody_AbstractClass.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | abstract class ExampleGraph { 4 | @Provides abstract val provideInt: Int 5 | @Provides abstract fun provideString(): String 6 | } 7 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/MapsUseMapBuilderIfNoProvider.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | @Multibinds 4 | val ints: Map 5 | 6 | val intsWithProviders: Map> 7 | 8 | @Provides @IntoMap @IntKey(3) fun provideInt(): Int = 3 9 | } -------------------------------------------------------------------------------- /gradle-plugin/src/functionalTest/kotlin/dev/zacsweers/metro/gradle/MetroOptionOverrides.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.gradle 4 | 5 | data class MetroOptionOverrides(val enableFullBindingGraphValidation: Boolean? = null) 6 | -------------------------------------------------------------------------------- /samples/circuit-app/src/wasmJsMain/resources/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Counter 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeAnnotationClasses.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | ) { 6 | @AssistedFactory 7 | annotation class Factory 8 | } 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesMustHaveABody_AbstractClass.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesMustHaveABody_AbstractClass.kt:(117,127): error: `@Provides` declarations must have bodies. 2 | 3 | /ProvidesMustHaveABody_AbstractClass.kt:(158,171): error: `@Provides` declarations must have bodies. 4 | -------------------------------------------------------------------------------- /compiler/src/main/kotlin/dev/zacsweers/metro/compiler/ir/IrBindingContainerCallable.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler.ir 4 | 5 | internal sealed interface IrBindingContainerCallable { 6 | val typeKey: IrTypeKey 7 | } 8 | -------------------------------------------------------------------------------- /samples/integration-tests/src/commonTest/kotlin/dev/zacsweers/metro/test/integration/Singleton.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.test.integration 4 | 5 | import dev.zacsweers.metro.Scope 6 | 7 | @Scope annotation class Singleton 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/createGraph/CreateGraph_MustBeGraph.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | interface SomeType 4 | 5 | fun example() { 6 | val someType = createGraph<SomeType>() 7 | val someType2: SomeType = createGraph() 8 | } 9 | -------------------------------------------------------------------------------- /samples/integration-tests/src/jsTest/kotlin/dev/zacsweers/metro/test/integration/Platform.js.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.test.integration 4 | 5 | actual fun isJvm(): Boolean = false 6 | 7 | actual fun isWasm(): Boolean = false 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/PrivateProviderOption_None.kt: -------------------------------------------------------------------------------- 1 | // PUBLIC_PROVIDER_SEVERITY: NONE 2 | // DISABLE_TRANSFORM_PROVIDERS_TO_PRIVATE 3 | 4 | interface ExampleGraph { 5 | @Provides val provideCharSequence: String get() = "Hello" 6 | @Provides fun provideString(): String = "Hello" 7 | } 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/cycles/SelfCycle.kt: -------------------------------------------------------------------------------- 1 | // DONT_SORT_DECLARATIONS 2 | @DependencyGraph 3 | interface SelfCycleGraph { 4 | fun s(): S 5 | } 6 | 7 | @Suppress("MEMBERS_INJECT_WARNING") 8 | @Inject 9 | class S(val sProvider: Provider) { 10 | @Inject lateinit var sLazy: Lazy 11 | } 12 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /interop-javax/api/interop-javax.api: -------------------------------------------------------------------------------- 1 | public final class dev/zacsweers/metro/interop/javax/JavaxInteropKt { 2 | public static final fun asJavaxProvider (Ldev/zacsweers/metro/Provider;)Ljavax/inject/Provider; 3 | public static final fun asMetroProvider (Ljavax/inject/Provider;)Ldev/zacsweers/metro/Provider; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /samples/integration-tests/src/commonJvmTest/kotlin/dev/zacsweers/metro/test/integration/Platform.jvm.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.test.integration 4 | 5 | actual fun isJvm(): Boolean = true 6 | 7 | actual fun isWasm(): Boolean = false 8 | -------------------------------------------------------------------------------- /samples/integration-tests/src/nativeTest/kotlin/dev/zacsweers/metro/test/integration/Platform.native.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.test.integration 4 | 5 | actual fun isJvm(): Boolean = false 6 | 7 | actual fun isWasm(): Boolean = false 8 | -------------------------------------------------------------------------------- /samples/interop/customAnnotations-kotlinInject/src/commonTest/kotlin/dev/zacsweers/metro/sample/Singleton.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample 4 | 5 | import me.tatarka.inject.annotations.Scope 6 | 7 | @Scope annotation class Singleton 8 | -------------------------------------------------------------------------------- /samples/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /samples/integration-tests/src/commonWasmTest/kotlin/dev/zacsweers/metro/test/integration/Platform.wasm.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.test.integration 4 | 5 | actual fun isJvm(): Boolean = false 6 | 7 | actual fun isWasm(): Boolean = true 8 | -------------------------------------------------------------------------------- /benchmark/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoryMustTargetAssistedInjectTypesButMissingConstructor.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | class ExampleClass 3 | 4 | @AssistedFactory 5 | fun interface ExampleClassFactory { 6 | fun create(count: Int): ExampleClass 7 | } 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/functioninject/ContextParamsCannotBeOptional.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // LANGUAGE: +ContextParameters 3 | // ENABLE_TOP_LEVEL_FUNCTION_INJECTION 4 | 5 | @Inject 6 | context(@OptionalBinding string: String) 7 | fun App() { 8 | // ... 9 | } 10 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/ProvidingAConstructorInjectedTypeHasASpecificWarning.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidingAConstructorInjectedTypeHasASpecificWarning.kt:(412,415): warning: Provided type 'Bar' is already constructor-injected and does not need to be provided explicitly. Consider removing this `@Provides` declaration. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/LazyAssistedFactoryInjection.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @AssistedInject 4 | class Foo(factoryProvider: Lazy) { 5 | @AssistedFactory 6 | interface Factory { 7 | fun create(): Foo 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /interop-jakarta/api/interop-jakarta.api: -------------------------------------------------------------------------------- 1 | public final class dev/zacsweers/metro/interop/jakarta/JakartaInteropKt { 2 | public static final fun asJakartaProvider (Ldev/zacsweers/metro/Provider;)Ljakarta/inject/Provider; 3 | public static final fun asMetroProvider (Ljakarta/inject/Provider;)Ldev/zacsweers/metro/Provider; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/IncludedMustBeAContainer.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /IncludedMustBeAContainer.kt:(150,169): error: Included classes must be binding containers but 'SomeBindings' is not. 2 | 3 | /IncludedMustBeAContainer.kt:(240,259): error: Included classes must be binding containers but 'SomeBindings' is not. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/interop/dagger/DoNotSuggestMovingInjectAnnotationToClassWhenUsingJavaxOrJakartaInject.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /DoNotSuggestMovingInjectAnnotationToClassWhenUsingJavaxOrJakartaInject.kt:(285,292): warning: There is only one @Inject-annotated constructor. Consider moving the annotation to the class instead. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesFunctionsCannotBeTopLevel.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesFunctionsCannotBeTopLevel.kt:(150,160): error: @Provides/@Binds declarations must be within an interface, class, or companion object. If you're seeing this, `provideInt` is likely defined as a top-level method which isn't supported. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/UnusedScopedBindingsInUnextendedGraphGetNoProviderFields.kt: -------------------------------------------------------------------------------- 1 | @SingleIn(AppScope::class) 2 | @DependencyGraph 3 | interface AppGraph { 4 | @Provides @SingleIn(AppScope::class) fun provideString(): String = "Hi" 5 | @Provides private fun provideInt(): Int = 3 6 | 7 | val int: Int 8 | } -------------------------------------------------------------------------------- /interop-javax/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.jvm) 5 | alias(libs.plugins.mavenPublish) 6 | alias(libs.plugins.testkit) 7 | } 8 | 9 | dependencies { 10 | api(project(":runtime")) 11 | api(libs.javaxInject) 12 | } 13 | -------------------------------------------------------------------------------- /metrox-viewmodel/src/commonMain/kotlin/dev/zacsweers/metrox/viewmodel/ViewModelScope.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metrox.viewmodel 4 | 5 | /** Scope marker for ViewModel-scoped dependency graphs. */ 6 | public abstract class ViewModelScope private constructor() 7 | -------------------------------------------------------------------------------- /samples/interop/customAnnotations-kotlinInject/src/commonTest/kotlin/dev/zacsweers/metro/sample/Named.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample 4 | 5 | import me.tatarka.inject.annotations.Qualifier 6 | 7 | @Qualifier annotation class Named(val value: String) 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeLocal.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | class ExampleClass 3 | 4 | fun example() { 5 | @AssistedFactory 6 | abstract class ExampleClassFactory { 7 | abstract fun create(count: Int): ExampleClass 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/BindsNonThisReturningBodiesShouldError_Interface.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | interface ExampleGraph { 4 | @Binds val String.provideCharSequence: CharSequence get() = "something else" 5 | @Binds fun Int.provideNumber(): Number = 3 6 | } 7 | -------------------------------------------------------------------------------- /interop-jakarta/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.jvm) 5 | alias(libs.plugins.mavenPublish) 6 | alias(libs.plugins.testkit) 7 | } 8 | 9 | dependencies { 10 | api(project(":runtime")) 11 | api(libs.jakartaInject) 12 | } 13 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/BindsNonThisReturningBodiesShouldError_AbstractClass.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | abstract class ExampleGraph { 4 | @Binds val String.provideCharSequence: CharSequence get() = "something else" 5 | @Binds fun Int.provideNumber(): Number = 3 6 | } 7 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesCannotHaveReceivers_AbstractClass.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | abstract class ExampleGraph { 4 | @Provides val Long.provideInt: Int get() = this.toInt() 5 | @Provides private fun CharSequence.provideString(): String = "Hello" 6 | } 7 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesCannotHaveReceivers_Interface.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | interface ExampleGraph { 4 | @Provides val Long.provideInt: Int get() = this.toInt() 5 | @Provides private fun CharSequence.provideString(): String = this.toString() 6 | } 7 | -------------------------------------------------------------------------------- /samples/android-app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/GraphsCanHaveExistingImplClases.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | // Some other class called Impl 4 | class Impl 5 | } 6 | 7 | fun box(): String { 8 | val graph = createGraph() 9 | assertEquals("AppGraph.Impl2", graph::class.qualifiedName) 10 | return "OK" 11 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/DefaultValuesPropagateToNewInstanceParams.kt: -------------------------------------------------------------------------------- 1 | @Inject class ValueHolder(val stringValue: String? = null) 2 | 3 | @DependencyGraph 4 | interface AppGraph { 5 | val holder: ValueHolder 6 | } 7 | 8 | fun box(): String { 9 | assertNull(createGraph().holder.stringValue) 10 | return "OK" 11 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/ConflictingProvidesAndClassScopes.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @SingleIn(AppScope::class) 3 | @Inject 4 | class Bar() 5 | 6 | @DependencyGraph 7 | interface AppGraph { 8 | val bar: Bar 9 | 10 | @Provides 11 | fun provideBar(): Bar = Bar() 12 | } 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/OpenAccessorsInClasses.kt: -------------------------------------------------------------------------------- 1 | abstract class Base { 2 | abstract val int: Int 3 | } 4 | 5 | @DependencyGraph 6 | abstract class AppGraph : Base() { 7 | @Provides fun provideInt(): Int = 3 8 | } 9 | 10 | fun box(): String { 11 | assertEquals(3, createGraph().int) 12 | return "OK" 13 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/provides/DefaultValuesPropagateToNewInstanceParams.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | val int: Int 4 | @Provides fun provideInt(stringValue: String? = null): Int = stringValue?.toInt() ?: 3 5 | } 6 | 7 | fun box(): String { 8 | assertEquals(3, createGraph().int) 9 | return "OK" 10 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/AbstractContainersCannotHaveProvides.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AbstractContainersCannotHaveProvides.kt:(149,159): error: Abstract binding containers cannot contain @Provides callables ('ConfusedContainer' is an interface). Either convert it to an object class or move these declarations to its companion object. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/createGraph/GraphFactoriesMayNotHaveVarargs.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /GraphFactoriesMayNotHaveVarargs.kt:(174,180): error: DependencyGraph.Factory abstract function parameters may not be vararg. 2 | 3 | /GraphFactoriesMayNotHaveVarargs.kt:(323,329): error: GraphExtension.Factory abstract function parameters may not be vararg. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesWithExtensionsAndNonThisReturningBodiesShouldError.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | abstract class ExampleGraph { 4 | @Provides val String.provideCharSequence: CharSequence get() = "hello" 5 | @Provides fun Int.provideNumber(): Number = 3 6 | } 7 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/Provides_Interface_MayNotHaveTypeParameters.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /Provides_Interface_MayNotHaveTypeParameters.kt:(105,108): error: `@Provides` declarations may not have type parameters. 2 | 3 | /Provides_Interface_MayNotHaveTypeParameters.kt:(187,190): error: `@Provides` declarations may not have type parameters. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesNamesMustBeUniqueInContainer.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @BindingContainer 4 | class ExampleBindings { 5 | @Provides fun provideNumber(): Number = 3 6 | @Provides fun provideNumber(string: String): Int = string.length 7 | } 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/interop/dagger/ModulesWithConstructorInjectedFields.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ModulesWithConstructorInjectedFields.kt:(782,804): error: Included binding container 'ProvidersModule's does not have a no-arg constructor and thus cannot be included via annotation. Add a no-arg constructor or declare it as a graph factory parameter instead. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidedInjectedClassesWithMatchingTypeKeysAreReportedAsWarnings.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidedInjectedClassesWithMatchingTypeKeysAreReportedAsWarnings.kt:(154,173): warning: Provided type 'ExampleClass' is already constructor-injected and does not need to be provided explicitly. Consider removing this `@Provides` declaration. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/Provides_AbstractClass_MayNotHaveTypeParameters.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /Provides_AbstractClass_MayNotHaveTypeParameters.kt:(110,113): error: `@Provides` declarations may not have type parameters. 2 | 3 | /Provides_AbstractClass_MayNotHaveTypeParameters.kt:(192,195): error: `@Provides` declarations may not have type parameters. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/ProviderAccessorsAreTrackedInRefCounting.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | @Provides fun provideInt(): Int = 3 4 | 5 | val int1: Provider 6 | val int2: Provider 7 | 8 | @Provides fun provideLong(): Long = 3L 9 | 10 | val long1: Lazy 11 | val long2: Lazy 12 | } -------------------------------------------------------------------------------- /samples/compose-viewmodels/app/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeSealedClasses.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | ) { 6 | @AssistedFactory 7 | sealed class Factory { 8 | abstract fun create(count: Int): ExampleClass 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeSealedInterfaces.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | ) { 6 | @AssistedFactory 7 | sealed interface Factory { 8 | fun create(count: Int): ExampleClass 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/cycles/SimpleBindingIntoMulti.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | val ints: Set 4 | 5 | @Provides fun provideInt(): Int = 3 6 | 7 | @Binds @IntoSet val Int.bind: Int 8 | } 9 | 10 | fun box(): String { 11 | val graph = createGraph() 12 | assertEquals(setOf(3), graph.ints) 13 | return "OK" 14 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/createGraph/CreateGraph_MustBeGraph.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /CreateGraph_MustBeGraph.kt:(127,135): error: `createGraph` type argument 'SomeType' must be annotated with a `@DependencyGraph` annotation. 2 | 3 | /CreateGraph_MustBeGraph.kt:(167,178): error: `createGraph` type argument 'SomeType' must be annotated with a `@DependencyGraph` annotation. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/OptionalBindingIsNotAllowedOnInjectors.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | interface AppGraph { 5 | @OptionalBinding 6 | fun inject(@OptionalBinding example: Example) 7 | } 8 | 9 | class Example { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBePrivate.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | ) { 6 | @AssistedFactory 7 | private fun interface Factory { 8 | fun create(count: Int): ExampleClass 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoryMustTargetAssistedInjectTypesWithMatchingParameters.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoryMustTargetAssistedInjectTypesWithMatchingParameters.kt:(83,95): error: Parameter mismatch. Assisted factory and assisted inject constructor parameters must match but found differences: 2 | Missing from factory: kotlin.String 3 | -------------------------------------------------------------------------------- /samples/weather-app/src/jvmMain/kotlin/dev/zacsweers/metro/sample/weather/JvmAppGraph.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample.weather 4 | 5 | import dev.zacsweers.metro.AppScope 6 | import dev.zacsweers.metro.DependencyGraph 7 | 8 | @DependencyGraph(AppScope::class) interface JvmAppGraph : AppGraph 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/OptionalBindingIsNotAllowedOnInjectors.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /OptionalBindingIsNotAllowedOnInjectors.kt:(125,131): error: Injector functions cannot be annotated with @OptionalBinding. 2 | 3 | /OptionalBindingIsNotAllowedOnInjectors.kt:(132,148): error: Injector function parameters cannot be annotated with @OptionalBinding. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeProtected.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | ) { 6 | @AssistedFactory 7 | protected fun interface Factory { 8 | fun create(count: Int): ExampleClass 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoryMustTargetAssistedInjectTypesButMissingReturnType.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // Regression test for https://github.com/ZacSweers/metro/issues/364#issuecomment-2841469320 3 | 4 | @AssistedFactory 5 | fun interface ExampleClassFactory { 6 | fun create(count: Int) 7 | } 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoryWithMultipleSAMs.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoryWithMultipleSAMs.kt:(178,184): error: @AssistedFactory declarations must have exactly one abstract function but found 2. 2 | 3 | /AssistedFactoryWithMultipleSAMs.kt:(219,226): error: @AssistedFactory declarations must have exactly one abstract function but found 2. 4 | -------------------------------------------------------------------------------- /benchmark/startup-jvm/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.jvm) 5 | alias(libs.plugins.jmh) 6 | } 7 | 8 | dependencies { jmh(project(":app:component")) } 9 | 10 | jmh { 11 | warmupIterations = 4 12 | iterations = 10 13 | fork = 2 14 | resultFormat = "JSON" 15 | } 16 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/Binds_interface_BoundTypesMustBeSubtypes.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | interface ExampleGraph { 4 | // Valid cases 5 | @Binds fun String.bind(): CharSequence 6 | 7 | // Bad cases 8 | @Binds val Number.bind: Int 9 | @Binds fun CharSequence.bind(): String 10 | } 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesCannotLiveInObjects.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesCannotLiveInObjects.kt:(104,117): error: @Provides declarations must be within an either a @BindingContainer-annotated class XOR interface, class, or companion object. `provideString` appears to be defined directly within a (non-companion) object that is not annotated @BindingContainer. 2 | -------------------------------------------------------------------------------- /metrox-viewmodel-compose/api/metrox-viewmodel-compose.api: -------------------------------------------------------------------------------- 1 | public final class dev/zacsweers/metrox/viewmodel/MetroViewModelKt { 2 | public static final fun getLocalMetroViewModelFactory ()Landroidx/compose/runtime/ProvidableCompositionLocal; 3 | public static final fun requireViewModelStoreOwner (Landroidx/compose/runtime/Composer;I)Landroidx/lifecycle/ViewModelStoreOwner; 4 | } 5 | 6 | -------------------------------------------------------------------------------- /runtime/src/commonTest/kotlin/dev/zacsweers/metro/internal/SimpleCounter.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.internal 4 | 5 | // Replicates a simple AtomicInt 6 | class SimpleCounter(var count: Int = 0) { 7 | fun incrementAndGet(): Int = ++count 8 | 9 | fun getAndIncrement(): Int = count++ 10 | } 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/leniency/UnusedProvidersAreNotValidated.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | @Provides 4 | fun unusedString(int: Int): String { 5 | return int.toString() 6 | } 7 | 8 | @Binds val Int.unusedBinding: Number 9 | } 10 | 11 | fun box(): String { 12 | val graph = createGraph() 13 | return "OK" 14 | } 15 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/MissingBindingHintsShouldReportInternalOnlyIfInternal.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /module_main_MissingBindingHintsShouldReportInternalOnlyIfInternal.kt:(128,132): error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: Base 2 | 3 | Base is requested at 4 | [AppGraph] AppGraph.base 5 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/Binds_interface_ShouldNotHaveBodies.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // PUBLIC_PROVIDER_SEVERITY: WARN 3 | // DISABLE_TRANSFORM_PROVIDERS_TO_PRIVATE 4 | 5 | interface ExampleGraph { 6 | @Binds val Int.bind: Number get() = this 7 | @Binds fun String.bind(): CharSequence = this 8 | } 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidedInjectedClassesWithMatchingTypeKeysButDifferentScopesAreOk.kt: -------------------------------------------------------------------------------- 1 | @SingleIn(AppScope::class) 2 | @DependencyGraph 3 | interface ExampleGraph { 4 | val exampleClass: ExampleClass 5 | 6 | @Provides @SingleIn(AppScope::class) fun provideExampleClass(): ExampleClass = ExampleClass() 7 | } 8 | 9 | @Inject 10 | class ExampleClass 11 | -------------------------------------------------------------------------------- /.idea/kotlinTestDataPluginTestDataPaths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/ConfigurableMaxIrErrors.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /ConfigurableMaxIrErrors.kt:(233,237): error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: @dev.zacsweers.metro.Named("1") kotlin.Int 2 | 3 | @dev.zacsweers.metro.Named("1") kotlin.Int is requested at 4 | [AppGraph] AppGraph#int1 5 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/visibility/InternalVisibility.kt: -------------------------------------------------------------------------------- 1 | // Test direct invocation checks for internal members in same module 2 | 3 | @Inject class InternalClass internal constructor() 4 | 5 | @DependencyGraph 6 | abstract class AppGraph { 7 | @Provides internal fun provideInt(): Int = 42 8 | 9 | abstract val int: Int 10 | abstract val internalClass: InternalClass 11 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/aggregation/InternalHintsAreNotVisibleWithoutFriends.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /module_main_InternalHintsAreNotVisibleWithoutFriends.kt:(123,134): error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: ContributedInterface 2 | 3 | ContributedInterface is requested at 4 | [AppGraph] AppGraph#contributed 5 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/AssistedTypesCannotBeDirectlyQualified.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedTypesCannotBeDirectlyQualified.kt:(104,108): error: @AssistedInject-annotated classes cannot be annotated with qualifier annotations. 2 | 3 | /AssistedTypesCannotBeDirectlyQualified.kt:(295,300): error: @AssistedInject-annotated classes cannot be annotated with qualifier annotations. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeFinal.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | ) { 6 | @AssistedFactory 7 | class Factory { 8 | fun create(count: Int): ExampleClass { 9 | throw NotImplementedError() 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/PrivateProviderOption_Error.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // PUBLIC_PROVIDER_SEVERITY: ERROR 3 | // DISABLE_TRANSFORM_PROVIDERS_TO_PRIVATE 4 | 5 | interface ExampleGraph { 6 | @Provides val provideCharSequence: String get() = "Hello" 7 | @Provides fun provideString(): String = "Hello" 8 | } 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidedInjectedClassesWithMatchingTypeKeysAreReportedAsWarnings.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | interface ExampleGraph { 5 | val exampleClass: ExampleClass 6 | 7 | @Provides fun provideExampleClass(): ExampleClass = ExampleClass() 8 | } 9 | 10 | @Inject 11 | class ExampleClass 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesNamesMustBeUniqueInGraph.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesNamesMustBeUniqueInGraph.kt:(155,168): error: Class AppGraph cannot contain multiple @Provides callables with the same name 'provideNumber'. 2 | 3 | /ProvidesNamesMustBeUniqueInGraph.kt:(199,212): error: Class AppGraph cannot contain multiple @Provides callables with the same name 'provideNumber'. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/GraphImplClassAsReturnType.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_GRAPH_IMPL_CLASS_AS_RETURN_TYPE 2 | @GraphExtension(String::class) 3 | interface ChildGraph { 4 | @GraphExtension.Factory @ContributesTo(AppScope::class) 5 | fun interface Factory { 6 | fun create(): ChildGraph 7 | } 8 | } 9 | 10 | @DependencyGraph(AppScope::class) 11 | interface AppGraph 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/leniency/SomeUnusedAndSomeUsed.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | @DependencyGraph 4 | interface AppGraph { 5 | @Provides fun unusedString(int: Int): String { 6 | return int.toString() 7 | } 8 | 9 | @Binds val Int.unusedBinding: Number 10 | 11 | val number: Number 12 | } 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/Binds_interface_BoundTypesMustBeSubtypes.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /Binds_interface_BoundTypesMustBeSubtypes.kt:(181,185): error: Binds receiver type `kotlin.Number` is not a subtype of bound type `kotlin.Int`. 2 | 3 | /Binds_interface_BoundTypesMustBeSubtypes.kt:(217,221): error: Binds receiver type `kotlin.CharSequence` is not a subtype of bound type `kotlin.String`. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidedInjectedClassesWithMatchingTypeKeysAreREportedAsWarnings_Qualified.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidedInjectedClassesWithMatchingTypeKeysAreREportedAsWarnings_Qualified.kt:(170,189): warning: Provided type '@Named("hello") ExampleClass' is already constructor-injected and does not need to be provided explicitly. Consider removing this `@Provides` declaration. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/Provides_Interface_MayNotHaveTypeParameters.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | interface ExampleGraph { 4 | @Provides 5 | fun provideString(): String = "Hello" 6 | 7 | companion object { 8 | @Provides 9 | fun provideInt(): Int = 0 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/multibindings/MapProvidersParticipateInProviderRefcounting.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | @Provides fun provideInt(): Int = 3 4 | @Binds @IntoMap @IntKey(3) fun Int.bindInt(): Int 5 | 6 | // Int is used as a provider in both this accessor and the map, so we should refcount it 7 | val int: Provider 8 | val ints: Map> 9 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/aggregation/AnyIsAValidSupertype.kt: -------------------------------------------------------------------------------- 1 | @Inject @IntKey(3) @ContributesIntoMap(AppScope::class, binding = binding()) class Something 2 | 3 | @DependencyGraph(AppScope::class) 4 | interface AppGraph { 5 | @Multibinds val ints: Map 6 | } 7 | 8 | fun box(): String { 9 | assertTrue(createGraph().ints[3] is Something) 10 | return "OK" 11 | } 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoryMustTargetAssistedInjectTypesButMissingReturnType.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoryMustTargetAssistedInjectTypesButMissingReturnType.kt:(214,220): error: Invalid return type: kotlin.Unit. `@AssistedFactory` target classes must have a single `@AssistedInject`-annotated constructor or be annotated `@AssistedInject` with only a primary constructor. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesNamesMustBeUniqueInGraph.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | interface AppGraph { 5 | val number: Number 6 | val int: Int 7 | 8 | @Provides fun provideNumber(): Number = 3 9 | @Provides fun provideNumber(string: String): Int = string.length 10 | } 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesShouldBePrivate_InInterface.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // PUBLIC_PROVIDER_SEVERITY: WARN 3 | // DISABLE_TRANSFORM_PROVIDERS_TO_PRIVATE 4 | 5 | interface ExampleGraph { 6 | @Provides val provideCharSequence: String get() = "Hello" 7 | @Provides fun provideString(): String = "Hello" 8 | } 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/Provides_AbstractClass_MayNotHaveTypeParameters.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | abstract class ExampleGraph { 4 | @Provides 5 | fun provideString(): String = "Hello" 6 | 7 | companion object { 8 | @Provides 9 | fun provideInt(): Int = 0 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /samples/interop/dependencies-kotlinInject/src/test/kotlin/dev/zacsweers/metro/sample/StringComponent.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample 4 | 5 | import me.tatarka.inject.annotations.Component 6 | import me.tatarka.inject.annotations.Provides 7 | 8 | @Component abstract class StringComponent(@get:Provides val message: String) 9 | -------------------------------------------------------------------------------- /samples/weather-app/README.md: -------------------------------------------------------------------------------- 1 | Weather App 2 | =========== 3 | 4 | A simple sample weather app. 5 | 6 | To run the JVM CLI, run 7 | 8 | ```bash 9 | $ ./gradlew -p samples :weather-app:jvmRun -DmainClass=dev.zacsweers.metro.sample.weather.MainKt --quiet 10 | ``` 11 | 12 | To change the supplied location, add `--args="--location New York"` to the end, replacing "New York" with your own 13 | query. 14 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/ContributedContainersMustHaveNoArgConstructors.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ContributedContainersMustHaveNoArgConstructors.kt:(132,139): error: Contributed binding container BadContainer1's no-arg constructor must be public or internal. 2 | 3 | /ContributedContainersMustHaveNoArgConstructors.kt:(211,224): error: Contributed binding containers must have a no-arg constructor. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/GraphsCannotDirectlyExtendOtherGraphs.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | // MODULE: lib 4 | @DependencyGraph 5 | interface ParentGraph { 6 | val value: Int 7 | 8 | @Provides 9 | fun provideInt(): Int = 3 10 | } 11 | 12 | // MODULE: main(lib) 13 | @DependencyGraph 14 | interface ChildGraph : ParentGraph 15 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeAnnotationObjects.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | ) { 6 | @AssistedFactory 7 | object Factory { 8 | fun create(count: Int): ExampleClass { 9 | throw NotImplementedError() 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoryMustTargetAssistedInjectTypesButMissingConstructor.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedFactoryMustTargetAssistedInjectTypesButMissingConstructor.kt:(160,172): error: Invalid return type: ExampleClass. `@AssistedFactory` target classes must have a single `@AssistedInject`-annotated constructor or be annotated `@AssistedInject` with only a primary constructor. 2 | -------------------------------------------------------------------------------- /interop-guice/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.jvm) 5 | alias(libs.plugins.mavenPublish) 6 | alias(libs.plugins.testkit) 7 | } 8 | 9 | dependencies { 10 | api(project(":runtime")) 11 | // Guice dropped javax.inject in 7.0 12 | api(project(":interop-jakarta")) 13 | api(libs.guice) 14 | } 15 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/BindsWithBodiesShouldBePrivate_InInterface.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // PUBLIC_PROVIDER_SEVERITY: WARN 3 | // DISABLE_TRANSFORM_PROVIDERS_TO_PRIVATE 4 | 5 | interface ExampleGraph { 6 | @Binds val String.provideCharSequence: CharSequence get() = this 7 | @Binds fun Int.provideNumber(): Number = this 8 | } 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/DaggerReusable_IsUnsupported.kt: -------------------------------------------------------------------------------- 1 | // WITH_DAGGER 2 | // RENDER_DIAGNOSTICS_FULL_TEXT 3 | 4 | import dagger.Reusable 5 | 6 | interface ExampleGraph { 7 | @Reusable 8 | @Provides 9 | fun provideInt(): Int { 10 | return 0 11 | } 12 | 13 | @Reusable 14 | @Binds 15 | val Int.bind: Number 16 | } 17 | -------------------------------------------------------------------------------- /compiler/src/main/kotlin/dev/zacsweers/metro/compiler/graph/MissingBindingHints.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler.graph 4 | 5 | internal data class MissingBindingHints>( 6 | val messages: List = emptyList(), 7 | val similarBindings: Map = emptyMap(), 8 | ) 9 | -------------------------------------------------------------------------------- /interop-dagger/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.jvm) 5 | alias(libs.plugins.mavenPublish) 6 | alias(libs.plugins.testkit) 7 | } 8 | 9 | dependencies { 10 | api(project(":runtime")) 11 | api(project(":interop-javax")) 12 | api(project(":interop-jakarta")) 13 | api(libs.dagger.runtime) 14 | } 15 | -------------------------------------------------------------------------------- /benchmark/startup-android/benchmark/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/AbstractContainersCannotHaveProvides.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @BindingContainer 4 | interface ConfusedContainer { 5 | // This is not legal 6 | @Provides fun provideInt(): Int = 3 7 | 8 | companion object { 9 | // This is legal 10 | @Provides fun provideBoolean(): Boolean = false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/SuggestInjectClassOnSingleContructor.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /SuggestInjectClassOnSingleContructor.kt:(90,97): warning: There is only one @Inject-annotated constructor. Consider moving the annotation to the class instead. 2 | 3 | /SuggestInjectClassOnSingleContructor.kt:(145,152): warning: There is only one @Inject-annotated constructor. Consider moving the annotation to the class instead. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesNamesMustBeUniqueInContainer.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesNamesMustBeUniqueInContainer.kt:(120,133): error: Class ExampleBindings cannot contain multiple @Provides callables with the same name 'provideNumber'. 2 | 3 | /ProvidesNamesMustBeUniqueInContainer.kt:(164,177): error: Class ExampleBindings cannot contain multiple @Provides callables with the same name 'provideNumber'. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/fir/aggregation/ContributingGraphExtensions.kt: -------------------------------------------------------------------------------- 1 | abstract class LoggedInScope 2 | 3 | @GraphExtension(LoggedInScope::class) 4 | interface LoggedInGraph { 5 | @GraphExtension.Factory @ContributesTo(AppScope::class) 6 | interface Factory { 7 | fun createLoggedInGraph(): LoggedInGraph 8 | } 9 | } 10 | 11 | @DependencyGraph(scope = AppScope::class) 12 | interface ExampleGraph 13 | -------------------------------------------------------------------------------- /runtime/src/commonMain/kotlin/dev/zacsweers/metro/Includes.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro 4 | 5 | /** 6 | * This annotation is used on [DependencyGraph.Factory] creators to indicate that the annotated 7 | * parameter is a container of dependencies. 8 | */ 9 | @Target(AnnotationTarget.VALUE_PARAMETER) public annotation class Includes 10 | -------------------------------------------------------------------------------- /samples/interop/dependencies-kotlinInject/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.jvm) 5 | alias(libs.plugins.ksp) 6 | id("dev.zacsweers.metro") 7 | } 8 | 9 | dependencies { 10 | ksp(libs.kotlinInject.compiler) 11 | implementation(libs.kotlinInject.runtime) 12 | testImplementation(libs.kotlin.test) 13 | } 14 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/extensions/ExtensionsWithFactoriesMustUseThem.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ExtensionsWithFactoriesMustUseThem.kt:(389,402): error: Graph extension 'LoggedInGraph' has a creator type 'LoggedInGraph.Factory' that must be used to create its instances. Either make 'AppGraph' implement 'LoggedInGraph.Factory' or expose an accessor for 'LoggedInGraph.Factory' instead of 'LoggedInGraph' directly. 2 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoryMustTargetAssistedInjectTypesWithMatchingParameters.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | @Assisted val message: String, 6 | ) 7 | 8 | @AssistedFactory 9 | fun interface ExampleClassFactory { 10 | fun create(count: Int): ExampleClass 11 | } 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/BindsWithBodiesShouldBePrivate_InAbstractClass.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // PUBLIC_PROVIDER_SEVERITY: WARN 3 | // DISABLE_TRANSFORM_PROVIDERS_TO_PRIVATE 4 | 5 | abstract class ExampleGraph { 6 | @Binds val String.provideCharSequence: CharSequence get() = this 7 | @Binds fun Int.provideNumber(): Number = this 8 | } 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesMustHaveExplicitReturnTypes.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesMustHaveExplicitReturnTypes.kt:(278,291): error: Implicit return types are not allowed for `@Provides` declarations. Specify the return type explicitly. 2 | 3 | /ProvidesMustHaveExplicitReturnTypes.kt:(348,358): error: Implicit return types are not allowed for `@Provides` declarations. Specify the return type explicitly. 4 | -------------------------------------------------------------------------------- /runtime/src/commonMain/kotlin/dev/zacsweers/metro/internal/GraphFactoryInvokeFunctionMarker.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.internal 4 | 5 | import kotlin.annotation.AnnotationTarget.FUNCTION 6 | 7 | /** Marker for generated factories indicating their invoke function. */ 8 | @Target(FUNCTION) public annotation class GraphFactoryInvokeFunctionMarker 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/fir/aggregation/FirHintGenerationWorks_k22x.kt: -------------------------------------------------------------------------------- 1 | // GENERATE_CONTRIBUTION_HINTS_IN_FIR 2 | // COMPILER_VERSION: 2.2 3 | 4 | @ContributesTo(AppScope::class) 5 | interface ContributedInterface1 6 | 7 | @ContributesTo(Unit::class) 8 | interface ContributedInterface2 9 | 10 | // Repeated 11 | @ContributesTo(AppScope::class) 12 | @ContributesTo(Unit::class) 13 | interface ContributedInterface3 14 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/fir/aggregation/FirHintGenerationWorks_k23x.kt: -------------------------------------------------------------------------------- 1 | // GENERATE_CONTRIBUTION_HINTS_IN_FIR 2 | // COMPILER_VERSION: 2.3 3 | 4 | @ContributesTo(AppScope::class) 5 | interface ContributedInterface1 6 | 7 | @ContributesTo(Unit::class) 8 | interface ContributedInterface2 9 | 10 | // Repeated 11 | @ContributesTo(AppScope::class) 12 | @ContributesTo(Unit::class) 13 | interface ContributedInterface3 14 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/cycles/BindsCycleGraph.kt: -------------------------------------------------------------------------------- 1 | // DONT_SORT_DECLARATIONS 2 | interface Foo 3 | 4 | @Inject class Bar(val fooProvider: Provider) : Foo 5 | 6 | /** 7 | * A component with a cycle in which a `@Binds` binding depends on the binding that has to be 8 | * deferred. 9 | */ 10 | @DependencyGraph 11 | interface BindsCycleGraph { 12 | fun bar(): Bar 13 | 14 | @Binds fun foo(bar: Bar): Foo 15 | } -------------------------------------------------------------------------------- /compiler/src/main/kotlin/dev/zacsweers/metro/compiler/exceptions.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler 4 | 5 | /** An exception that signals to end processing but assumes all errors have been reported prior. */ 6 | internal class ExitProcessingException : RuntimeException() 7 | 8 | internal fun exitProcessing(): Nothing = throw ExitProcessingException() 9 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/kotlin/dev/zacsweers/metro/gradle/KotlinVersions.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.gradle 4 | 5 | import org.jetbrains.kotlin.tooling.core.KotlinToolingVersion 6 | 7 | internal object KotlinVersions { 8 | val kotlin230 = KotlinToolingVersion(2, 3, 0, null) 9 | val kotlin2320 = KotlinToolingVersion(2, 3, 20, null) 10 | } 11 | -------------------------------------------------------------------------------- /samples/interop/customAnnotations-guice/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.jvm) 5 | id("dev.zacsweers.metro") 6 | } 7 | 8 | metro { interop { includeGuice() } } 9 | 10 | dependencies { 11 | implementation(libs.guice) 12 | implementation(libs.guice.assistedInject) 13 | testImplementation(libs.kotlin.test) 14 | } 15 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/bindingcontainers/PrivateBindsProperty.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | val message: Message 4 | 5 | // Bind MessageImpl as Message 6 | @Binds private val MessageImpl.bind: Message get() = this 7 | } 8 | 9 | interface Message 10 | 11 | @Inject 12 | class MessageImpl : Message 13 | 14 | fun box(): String { 15 | assertNotNull(createGraph().message) 16 | return "OK" 17 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/ContributedContainersMustHaveNoArgConstructors.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @ContributesTo(AppScope::class) 4 | @BindingContainer 5 | class BadContainer1 private constructor() 6 | 7 | @ContributesTo(AppScope::class) 8 | @BindingContainer 9 | class BadContainer2(private val foo: String) 10 | 11 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/IncludedMustBeAContainer.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | interface SomeBindings { 4 | @Binds val Int.bind: Number 5 | } 6 | 7 | @BindingContainer(includes = [SomeBindings::class]) 8 | interface IncludingContainer 9 | 10 | @DependencyGraph(bindingContainers = [SomeBindings::class]) 11 | interface AppGraph 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/BindsMayNotHaveScopes.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /BindsMayNotHaveScopes.kt:(98,124): error: @Binds declarations may not have scopes. 2 | 3 | /BindsMayNotHaveScopes.kt:(164,190): error: @Binds declarations may not have scopes. 4 | 5 | /BindsMayNotHaveScopes.kt:(271,297): error: @Binds declarations may not have scopes. 6 | 7 | /BindsMayNotHaveScopes.kt:(346,372): error: @Binds declarations may not have scopes. 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidedInjectedClassesWithMatchingTypeKeysAreREportedAsWarnings_Qualified.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | interface ExampleGraph { 5 | val exampleClass: ExampleClass 6 | 7 | @Provides @Named("hello") fun provideExampleClass(): ExampleClass = ExampleClass() 8 | } 9 | 10 | @Named("hello") 11 | @Inject 12 | class ExampleClass 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/ExtensionsAreInnerClasses.kt: -------------------------------------------------------------------------------- 1 | @GraphExtension 2 | interface LoggedInGraph { 3 | val id: String 4 | val count: Int 5 | 6 | @GraphExtension.Factory 7 | interface Factory { 8 | fun createLoggedInGraph(@Provides id: String): LoggedInGraph 9 | } 10 | } 11 | 12 | @DependencyGraph 13 | interface AppGraph : LoggedInGraph.Factory { 14 | @Provides fun provideCount(): Int = 3 15 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/graph/LazyAssistedFactoryGraphAccessor.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /LazyAssistedFactoryGraphAccessor.kt:(214,237): error: Metro does not support injecting Lazy because MyAssistedFactory is an @AssistedFactory-annotated type. 2 | 3 | /LazyAssistedFactoryGraphAccessor.kt:(265,288): error: Metro does not support injecting Lazy because MyAssistedFactory is an @AssistedFactory-annotated type. 4 | -------------------------------------------------------------------------------- /metrox-android/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 10 | -------------------------------------------------------------------------------- /benchmark/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx8g -Dfile.encoding=UTF-8 2 | org.gradle.parallel=true 3 | org.gradle.caching=true 4 | # Included builds break KGP's annoying "fus" service 5 | org.gradle.configuration-cache=false 6 | 7 | kotlin.code.style=official 8 | 9 | # Android configuration 10 | android.useAndroidX=true 11 | android.enableJetifier=false 12 | # Enable R8 full mode for maximum optimization 13 | android.enableR8.fullMode=true -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/multibindings/MultibindingSourcesGetGettersThroughAliases.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/issues/1397 2 | 3 | abstract class Base 4 | 5 | @Inject class Foo : Base() 6 | @Inject class Bar : Base() 7 | 8 | @DependencyGraph 9 | interface AppGraph { 10 | val values: Set 11 | 12 | @Binds @IntoSet val Foo.bind: Any 13 | @Binds val Bar.bind2: Base 14 | @Binds @IntoSet val Base.bind3: Any 15 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/provides/SimpleFunctionProvider.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface ExampleGraph { 3 | val provider: Provider 4 | 5 | @Provides 6 | fun provideValue(): String = "Hello, world!" 7 | } 8 | 9 | fun box(): String { 10 | var provider = createGraph().provider 11 | assertEquals(provider.invoke(), "Hello, world!") 12 | assertEquals(provider.invoke(), "Hello, world!") 13 | return "OK" 14 | } 15 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/ContainersCannotExtendOtherContainers.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @BindingContainer 4 | interface AnotherContainer 5 | 6 | @BindingContainer 7 | interface ConfusedContainer : AnotherContainer 8 | 9 | interface Intermediate : AnotherContainer 10 | 11 | @BindingContainer 12 | interface ConfusedContainer2 : Intermediate 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/createGraph/CreateGraph_MustBeGraphFactory.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /CreateGraph_MustBeGraphFactory.kt:(253,276): error: `createGraphFactory` type argument 'ExampleGraphWithFactory' must be annotated with a `@DependencyGraph.Factory` annotation. 2 | 3 | /CreateGraph_MustBeGraphFactory.kt:(333,351): error: `createGraphFactory` type argument 'ExampleGraphWithFactory' must be annotated with a `@DependencyGraph.Factory` annotation. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoryWithMultipleSAMs.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | ) { 6 | @AssistedFactory 7 | interface Factory { 8 | fun create(count: Int): ExampleClass 9 | fun create2(count: Int): ExampleClass 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/interop/dagger/DoNotSuggestMovingInjectAnnotationToClassWhenUsingJavaxOrJakartaInject.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // ENABLE_DAGGER_INTEROP 3 | 4 | // Regression test for https://github.com/ZacSweers/metro/issues/365 5 | 6 | class JavaxInject @javax.inject.Inject constructor() 7 | class JakartaInject @jakarta.inject.Inject constructor() 8 | class MetroInject @Inject constructor() 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/cycles/CycleMapGraph.kt: -------------------------------------------------------------------------------- 1 | // DONT_SORT_DECLARATIONS 2 | @Inject class X(val y: Y) 3 | 4 | @Inject 5 | class Y( 6 | val mapOfProvidersOfX: Map>, 7 | val mapOfProvidersOfY: Map>, 8 | ) 9 | 10 | @DependencyGraph 11 | interface CycleMapGraph { 12 | fun y(): Y 13 | 14 | @Binds @IntoMap @StringKey("X") val X.x: X 15 | 16 | @Binds @IntoMap @StringKey("Y") val Y.y: Y 17 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/UnusedInstanceBindingsInUnextendedGraphGetNoProviderFields.kt: -------------------------------------------------------------------------------- 1 | @SingleIn(AppScope::class) 2 | @DependencyGraph 3 | interface AppGraph { 4 | @Provides private fun provideInt(): Int = 3 5 | 6 | val int: Int 7 | 8 | @DependencyGraph.Factory 9 | interface Factory { 10 | fun create( 11 | // Unused in AppGraph 12 | @Provides string: String 13 | ): AppGraph 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /compiler-tests/src/test/kotlin/dev/zacsweers/metro/compiler/KotlinTestImportPreprocessor.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler 4 | 5 | import org.jetbrains.kotlin.test.services.TestServices 6 | 7 | class KotlinTestImportPreprocessor(testServices: TestServices) : ImportsPreprocessor(testServices) { 8 | override val additionalImports = setOf("kotlin.test.*") 9 | } 10 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/bindingcontainers/MultibindsOnlyInContainer.kt: -------------------------------------------------------------------------------- 1 | @BindingContainer 2 | interface MyMultibinds { 3 | @Multibinds(allowEmpty = true) 4 | val ints: Set 5 | } 6 | 7 | @DependencyGraph(bindingContainers = [MyMultibinds::class]) 8 | interface AppGraph { 9 | val ints: Set 10 | } 11 | 12 | fun box(): String { 13 | val graph = createGraph() 14 | assertEquals(emptySet(), graph.ints) 15 | return "OK" 16 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/provides/JvmFieldProvidersUseFieldAccess.kt: -------------------------------------------------------------------------------- 1 | // In this scenario, generated provider factories' newInstance function gets the field directly 2 | // However, access cannot yet be directly invoked until we support inlining field access calls to 3 | // public fields 4 | @DependencyGraph 5 | abstract class AppGraph { 6 | @Provides @JvmField val stringField: String = "Hello" 7 | 8 | abstract val string: String 9 | } 10 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesShouldBePrivate_InAbstractClass.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // PUBLIC_PROVIDER_SEVERITY: WARN 3 | // DISABLE_TRANSFORM_PROVIDERS_TO_PRIVATE 4 | 5 | abstract class ExampleGraph { 6 | @Provides val provideInt: Int = 0 7 | @Provides val provideCharSequence: String get() = "Hello" 8 | @Provides fun provideString(): String = "Hello" 9 | } 10 | -------------------------------------------------------------------------------- /scripts/generate_docs_dokka.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Generate API documentation using Dokka 4 | # This script handles the API docs generation that's shared between CI and local builds 5 | 6 | set -e 7 | 8 | echo "Generating API docs using dokka..." 9 | 10 | # Generate the API docs 11 | # --rerun-tasks because Dokka has bugs :( 12 | ./gradlew :dokkaGenerate --rerun-tasks --no-build-cache --no-configuration-cache 13 | 14 | echo "API docs generation complete!" -------------------------------------------------------------------------------- /runtime/src/commonMain/kotlin/dev/zacsweers/metro/internal/MetroImplMarker.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.internal 4 | 5 | /** 6 | * Marker annotation for generated Metro impl classes. Useful for Metro to discover classes across 7 | * compilations. 8 | */ 9 | @Target(AnnotationTarget.CLASS) 10 | @Retention(AnnotationRetention.RUNTIME) 11 | public annotation class MetroImplMarker 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/CannotIncludeGenericContainer.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @BindingContainer 4 | class SomeBindings { 5 | @Provides fun provideInt(): Int = 0 6 | } 7 | 8 | @BindingContainer(includes = [SomeBindings::class]) 9 | interface IncludingContainer 10 | 11 | @DependencyGraph(bindingContainers = [SomeBindings::class]) 12 | interface AppGraph 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/MultipleRefsGetProviderFields.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | val long: Long 4 | val string: String 5 | 6 | @Provides fun provideLong(holder: IntHolder): Long = holder.int.toLong() 7 | @Provides fun provideString(holder: IntHolder): String = holder.int.toString() 8 | } 9 | 10 | // Should save a field because it's used multiple times 11 | @Inject class IntHolder { 12 | val int: Int = 3 13 | } -------------------------------------------------------------------------------- /samples/compose-viewmodels/app/src/jvmMain/kotlin/dev/zacsweers/metro/sample/composeviewmodels/app/Graphs.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample.composeviewmodels.app 4 | 5 | import dev.zacsweers.metro.AppScope 6 | import dev.zacsweers.metro.DependencyGraph 7 | import dev.zacsweers.metrox.viewmodel.ViewModelGraph 8 | 9 | @DependencyGraph(AppScope::class) interface AppGraph : ViewModelGraph 10 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/member/SimpleAncestorInjectionWithEmptyChild.kt: -------------------------------------------------------------------------------- 1 | @HasMemberInjections 2 | abstract class Parent { 3 | @Inject 4 | var int: Int = 0 5 | } 6 | 7 | @Inject 8 | class Child : Parent() 9 | 10 | @DependencyGraph 11 | interface AppGraph { 12 | @Provides fun provideInt(): Int = 3 13 | val child: Child 14 | } 15 | 16 | fun box(): String { 17 | val graph = createGraph() 18 | assertEquals(3, graph.child.int) 19 | return "OK" 20 | } -------------------------------------------------------------------------------- /runtime/src/commonMain/kotlin/dev/zacsweers/metro/internal/MetroContribution.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.internal 4 | 5 | import kotlin.annotation.AnnotationTarget.CLASS 6 | import kotlin.reflect.KClass 7 | 8 | /** Marker for generated nested classes for top-level declarations annotated with @Contributes_. */ 9 | @Target(CLASS) public annotation class MetroContribution(val scope: KClass<*>) 10 | -------------------------------------------------------------------------------- /samples/interop/dependencies-dagger/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.jvm) 5 | // alias(libs.plugins.kotlin.kapt) 6 | alias(libs.plugins.ksp) 7 | id("dev.zacsweers.metro") 8 | } 9 | 10 | // TODO add KSP/KAPT dual mode? 11 | dependencies { 12 | ksp(libs.dagger.compiler) 13 | implementation(libs.dagger.runtime) 14 | testImplementation(libs.kotlin.test) 15 | } 16 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/RequiredAnnotationResultsInMissingBindingMultiModule.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /module_main_RequiredAnnotationResultsInMissingBindingMultiModule.kt:(92,100): error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: kotlin.String? 2 | 3 | kotlin.String? is injected at 4 | [AppGraph] Example(…, value) 5 | Example is requested at 6 | [AppGraph] AppGraph.example 7 | -------------------------------------------------------------------------------- /compiler-tests/src/test/kotlin/dev/zacsweers/metro/compiler/MetroDefaultImportPreprocessor.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler 4 | 5 | import org.jetbrains.kotlin.test.services.TestServices 6 | 7 | class MetroDefaultImportPreprocessor(testServices: TestServices) : 8 | ImportsPreprocessor(testServices) { 9 | override val additionalImports: Set = setOf("dev.zacsweers.metro.*") 10 | } 11 | -------------------------------------------------------------------------------- /samples/graph-analysis/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | import dev.zacsweers.metro.gradle.DelicateMetroGradleApi 4 | 5 | plugins { 6 | alias(libs.plugins.kotlin.jvm) 7 | id("dev.zacsweers.metro") 8 | } 9 | 10 | @OptIn(DelicateMetroGradleApi::class) 11 | metro { reportsDestination.set(layout.buildDirectory.dir("reports/metro")) } 12 | 13 | kotlin { compilerOptions { optIn.add("kotlin.time.ExperimentalTime") } } 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask for help 4 | url: https://github.com/ZacSweers/metro/discussions/new?category=q-a 5 | about: If you have a usage or debugging question, please use the Q&A feature of the repo's Discussions section. 6 | - name: Create an issue without template 7 | url: https://github.com/ZacSweers/metro/issues/new?template=Blank+issue 8 | about: This option is only available for repository maintainers. -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/cycles/SelfCycle.kt: -------------------------------------------------------------------------------- 1 | @Suppress("MEMBERS_INJECT_WARNING") 2 | @Inject 3 | class S(val sProvider: Provider) { 4 | @Inject lateinit var sLazy: Lazy 5 | } 6 | 7 | @DependencyGraph 8 | interface SelfCycleGraph { 9 | fun s(): S 10 | } 11 | 12 | fun box(): String { 13 | val selfCycleGraph = createGraph() 14 | val s = selfCycleGraph.s() 15 | assertNotNull(s.sProvider()) 16 | assertNotNull(s.sLazy.value) 17 | return "OK" 18 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/OptionalBindingParamWarningIfDefault.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | interface AppGraph { 5 | @Provides 6 | fun provideString(@OptionalBinding value: Int = 3): String = value.toString() 7 | } 8 | 9 | @Inject 10 | class Example(@OptionalBinding val value: Int = 3) 11 | -------------------------------------------------------------------------------- /compiler/src/main/kotlin/dev/zacsweers/metro/compiler/OptionalBindingBehavior.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler 4 | 5 | /** See the analogous type in the Gradle plugin. */ 6 | public enum class OptionalBindingBehavior { 7 | DISABLED, 8 | DEFAULT, 9 | REQUIRE_OPTIONAL_BINDING; 10 | 11 | internal val requiresAnnotatedParameters: Boolean 12 | get() = this == REQUIRE_OPTIONAL_BINDING 13 | } 14 | -------------------------------------------------------------------------------- /interop-dagger/api/interop-dagger.api: -------------------------------------------------------------------------------- 1 | public final class dev/zacsweers/metro/interop/dagger/DaggerInteropKt { 2 | public static final fun asDaggerLazy (Lkotlin/Lazy;)Ldagger/Lazy; 3 | public static final fun asDaggerMembersInjector (Ldev/zacsweers/metro/MembersInjector;)Ldagger/MembersInjector; 4 | public static final fun asKotlinLazy (Ldagger/Lazy;)Lkotlin/Lazy; 5 | public static final fun asMetroMembersInjector (Ldagger/MembersInjector;)Ldev/zacsweers/metro/MembersInjector; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /compiler-tests/src/generator220/kotlin/dev/zacsweers/metro/compiler/MetroKotlinStandardLibrariesPathProvider.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler 4 | 5 | import org.jetbrains.kotlin.test.services.KotlinStandardLibrariesPathProvider 6 | 7 | // KotlinStandardLibrariesPathProvider was changed to an interface in 2.3.20 8 | abstract class MetroKotlinStandardLibrariesPathProvider : KotlinStandardLibrariesPathProvider() 9 | -------------------------------------------------------------------------------- /compiler-tests/src/generator230/kotlin/dev/zacsweers/metro/compiler/MetroKotlinStandardLibrariesPathProvider.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler 4 | 5 | import org.jetbrains.kotlin.test.services.KotlinStandardLibrariesPathProvider 6 | 7 | // KotlinStandardLibrariesPathProvider was changed to an interface in 2.3.20 8 | abstract class MetroKotlinStandardLibrariesPathProvider : KotlinStandardLibrariesPathProvider() 9 | -------------------------------------------------------------------------------- /compiler-tests/src/generator2320/kotlin/dev/zacsweers/metro/compiler/MetroKotlinStandardLibrariesPathProvider.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler 4 | 5 | import org.jetbrains.kotlin.test.services.KotlinStandardLibrariesPathProvider 6 | 7 | // KotlinStandardLibrariesPathProvider was changed to an interface in 2.3.20 8 | abstract class MetroKotlinStandardLibrariesPathProvider : KotlinStandardLibrariesPathProvider 9 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/aggregation/InternalContributionMissingHint.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /module_main_InternalContributionMissingHint.kt:(129,132): error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: Foo 2 | 3 | Foo is requested at 4 | [AppGraph] AppGraph#foo 5 | 6 | Similar bindings: 7 | - Foo (Contributed by 'FooImpl' but that class is internal to its module and its module is not a friend module to this one.) 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/LazyPropertiesHaveDeterministicOrder.kt: -------------------------------------------------------------------------------- 1 | // DONT_SORT_DECLARATIONS 2 | @DependencyGraph 3 | interface AppGraph { 4 | @Provides fun provideInt(): Int = 3 5 | @Binds @IntoSet fun Int.bindInt(): Int 6 | @Provides @IntoSet fun bindLong(int: Int): Long = int.toLong() 7 | @Provides @IntoSet fun bindDouble(int: Int): Double = int.toDouble() 8 | 9 | val intSet: Set 10 | val doubleSet: Set 11 | val longSet: Set 12 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/OptionalBindingsHaveValidFieldNames.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_INTEROP 2 | import java.util.Optional 3 | 4 | @DependencyGraph(AppScope::class, bindingContainers = [Bindings::class]) 5 | interface AppGraph { 6 | val optional: Optional 7 | 8 | @Provides @SingleIn(AppScope::class) val string: String get() = "Hello" 9 | } 10 | 11 | @dagger.Module 12 | interface Bindings { 13 | @dagger.BindsOptionalOf 14 | fun string(): String 15 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/AssistedTypesCannotBeProvidedWithoutQualifiers.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /AssistedTypesCannotBeProvidedWithoutQualifiers.kt:(262,266): error: [Metro/InvalidBinding] 'Taco' uses assisted injection and cannot be injected directly into 'test.ExampleGraph.exampleClass'. You must inject a corresponding @AssistedFactory type or provide a qualified instance on the graph instead. 2 | 3 | (Hint) 4 | It looks like the @AssistedFactory for 'Taco' may be 'Taco.Factory'. 5 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/assisted/AssistedFactoriesCannotBeEnums.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | ) { 6 | @AssistedFactory 7 | enum class Factory { 8 | INSTANCE { 9 | override fun create(count: Int): ExampleClass { 10 | throw NotImplementedError() 11 | } 12 | }; 13 | abstract fun create(count: Int): ExampleClass 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/DaggerReusable_IsUnsupported.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /DaggerReusable_IsUnsupported.kt:(128,137): error: Dagger's `@Reusable` is not supported in Metro. See https://zacsweers.github.io/metro/latest/faq#why-doesnt-metro-support-reusable for more information. 2 | 3 | /DaggerReusable_IsUnsupported.kt:(196,205): error: Dagger's `@Reusable` is not supported in Metro. See https://zacsweers.github.io/metro/latest/faq#why-doesnt-metro-support-reusable for more information. 4 | -------------------------------------------------------------------------------- /runtime/src/commonMain/kotlin/dev/zacsweers/metro/internal/InjectedFunctionClass.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.internal 4 | 5 | import kotlin.annotation.AnnotationTarget.CLASS 6 | import kotlin.annotation.AnnotationTarget.PROPERTY 7 | 8 | /** Marker for generated class wrappers for injected top level functions. */ 9 | @Target(CLASS, PROPERTY) public annotation class InjectedFunctionClass(val callableName: String) 10 | -------------------------------------------------------------------------------- /samples/interop/customAnnotations-dagger/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.jvm) 5 | id("dev.zacsweers.metro") 6 | } 7 | 8 | metro { 9 | interop { 10 | includeDagger() 11 | includeAnvilForDagger() 12 | } 13 | } 14 | 15 | dependencies { 16 | implementation(libs.anvil.annotations) 17 | implementation(libs.dagger.runtime) 18 | testImplementation(libs.kotlin.test) 19 | } 20 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/GraphFactoriesSupportGenericProviders.kt: -------------------------------------------------------------------------------- 1 | interface BaseFactory { 2 | fun create(@Provides value: T): R 3 | } 4 | 5 | @DependencyGraph 6 | interface ExampleGraph { 7 | val value: Int 8 | 9 | @DependencyGraph.Factory 10 | interface Factory : BaseFactory 11 | } 12 | 13 | fun box(): String { 14 | val graph = createGraphFactory().create(3) 15 | assertEquals(graph.value, 3) 16 | return "OK" 17 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/createGraph/CreateGraph_GraphHasFactory.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /CreateGraph_GraphHasFactory.kt:(262,285): error: `createGraph` type argument 'ExampleGraphWithFactory' has a factory at 'ExampleGraphWithFactory.Factory'. Use `createGraphFactory` with that type instead. 2 | 3 | /CreateGraph_GraphHasFactory.kt:(336,347): error: `createGraph` type argument 'ExampleGraphWithFactory' has a factory at 'ExampleGraphWithFactory.Factory'. Use `createGraphFactory` with that type instead. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/GraphAccessors.kt: -------------------------------------------------------------------------------- 1 | // Golden image test to ensure we don't generate unnecessary wrapping providers over accessors 2 | interface Accessors { 3 | val string: String 4 | val intProvider: Provider 5 | } 6 | 7 | @DependencyGraph 8 | interface ExampleGraph { 9 | val string: String 10 | val int: Int 11 | 12 | @DependencyGraph.Factory 13 | interface Factory { 14 | fun create(@Includes accessors: Accessors): ExampleGraph 15 | } 16 | } -------------------------------------------------------------------------------- /metrox-android/src/main/kotlin/dev/zacsweers/metrox/android/ServiceKey.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metrox.android 4 | 5 | import android.app.Service 6 | import dev.zacsweers.metro.MapKey 7 | import kotlin.reflect.KClass 8 | 9 | /** A [MapKey] annotation for binding a Service in a multibinding map. */ 10 | @MapKey 11 | @Target(AnnotationTarget.CLASS) 12 | public annotation class ServiceKey(val value: KClass) 13 | -------------------------------------------------------------------------------- /samples/interop/dependencies-dagger/src/test/kotlin/dev/zacsweers/metro/sample/StringComponent.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample 4 | 5 | import dagger.BindsInstance 6 | import dagger.Component 7 | 8 | @Component 9 | interface StringComponent { 10 | val message: String 11 | 12 | @Component.Factory 13 | interface Factory { 14 | fun create(@BindsInstance message: String): StringComponent 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/ContainersCannotExtendOtherContainers.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ContainersCannotExtendOtherContainers.kt:(156,172): error: Binding containers cannot extend other binding containers, use `includes` instead. Container 'ConfusedContainer' extends 'AnotherContainer'. 2 | 3 | /ContainersCannotExtendOtherContainers.kt:(245,263): error: Binding containers cannot extend other binding containers, use `includes` instead. Container 'ConfusedContainer2' extends 'AnotherContainer'. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/DisabledResultsInMissingBindings.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | // OPTIONAL_DEPENDENCY_BEHAVIOR: DISABLED 4 | 5 | @Inject 6 | class Example(val value: String? = null) 7 | 8 | @DependencyGraph 9 | interface AppGraph { 10 | val example: Example 11 | val int: Int 12 | 13 | @Provides 14 | fun provideInt(long: Long? = null): Int = long?.toInt() ?: 3 15 | } 16 | -------------------------------------------------------------------------------- /metrox-android/src/main/kotlin/dev/zacsweers/metrox/android/ActivityKey.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metrox.android 4 | 5 | import android.app.Activity 6 | import dev.zacsweers.metro.MapKey 7 | import kotlin.reflect.KClass 8 | 9 | /** A [MapKey] annotation for binding an Activity in a multibinding map. */ 10 | @MapKey 11 | @Target(AnnotationTarget.CLASS) 12 | public annotation class ActivityKey(val value: KClass) 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/createGraph/CreateGraph_GraphHasFactory.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | interface ExampleGraphWithFactory { 5 | @DependencyGraph.Factory 6 | interface Factory { 7 | fun create(): ExampleGraphWithFactory 8 | } 9 | } 10 | 11 | fun example() { 12 | val exampleGraph = createGraph<ExampleGraphWithFactory>() 13 | val exampleGraph2: ExampleGraphWithFactory = createGraph() 14 | } 15 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/createGraph/CreateGraph_MustBeGraphFactory.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | interface ExampleGraphWithFactory { 5 | interface Factory { 6 | fun create(): ExampleGraphWithFactory 7 | } 8 | } 9 | 10 | fun example() { 11 | val exampleGraphWithFactory = createGraphFactory<ExampleGraphWithFactory>() 12 | val exampleGraphFactory: ExampleGraphWithFactory = createGraphFactory() 13 | } 14 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/aggregation/InternalContributionMissingHint.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | // https://github.com/ZacSweers/metro/issues/887 4 | 5 | // MODULE: lib1 6 | interface Foo 7 | 8 | // MODULE: lib2(lib1) 9 | @ContributesBinding(AppScope::class) 10 | @Inject 11 | internal class FooImpl : Foo 12 | 13 | // MODULE: main(lib1 lib2) 14 | @DependencyGraph(AppScope::class) 15 | interface AppGraph { 16 | val foo: Foo 17 | } 18 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/OptionalBindingErrorIfDisabled.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // OPTIONAL_DEPENDENCY_BEHAVIOR: DISABLED 3 | 4 | @DependencyGraph 5 | interface AppGraph { 6 | @Provides 7 | fun provideString(@OptionalBinding value: Int = 3): String = value.toString() 8 | } 9 | 10 | @Inject 11 | class Example(@OptionalBinding val value: Int = 3) 12 | -------------------------------------------------------------------------------- /runtime/src/commonMain/kotlin/dev/zacsweers/metro/internal/AssistedMarker.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.internal 4 | 5 | /** 6 | * Marker annotation for generated assisted inject factory classes. This is used internally by Metro 7 | * to denote factories that were generated for assisted-injected types. 8 | */ 9 | @Target(AnnotationTarget.CLASS) 10 | @Retention(AnnotationRetention.RUNTIME) 11 | public annotation class AssistedMarker 12 | -------------------------------------------------------------------------------- /samples/interop/dependencies-dagger/src/test/kotlin/dev/zacsweers/metro/sample/StringGraph.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample 4 | 5 | import dev.zacsweers.metro.DependencyGraph 6 | import dev.zacsweers.metro.Provides 7 | 8 | @DependencyGraph 9 | interface StringGraph { 10 | val message: String 11 | 12 | @DependencyGraph.Factory 13 | interface Factory { 14 | fun create(@Provides message: String): StringGraph 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/AllDuplicateBindingsAreReported.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | 4 | @DependencyGraph 5 | interface AppGraph { 6 | @Provides fun provideString1(): String = "1" 7 | @Provides fun provideString2(): String = "2" 8 | @Provides fun provideString3(): String = "3" 9 | @Provides fun provideString4(): String = "4" 10 | @Provides fun provideString5(): String = "5" 11 | } 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/DisabledResultsInMissingBindingsEvenWithAnnotation.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | // OPTIONAL_DEPENDENCY_BEHAVIOR: DISABLED 4 | 5 | @Inject 6 | class Example(val value: String? = null) 7 | 8 | @DependencyGraph 9 | interface AppGraph { 10 | val example: Example 11 | val int: Int 12 | 13 | @Provides 14 | fun provideInt(long: Long? = null): Int = long?.toInt() ?: 3 15 | } 16 | -------------------------------------------------------------------------------- /samples/interop/dependencies-kotlinInject/src/test/kotlin/dev/zacsweers/metro/sample/StringGraph.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample 4 | 5 | import dev.zacsweers.metro.DependencyGraph 6 | import dev.zacsweers.metro.Provides 7 | 8 | @DependencyGraph 9 | interface StringGraph { 10 | val message: String 11 | 12 | @DependencyGraph.Factory 13 | interface Factory { 14 | fun create(@Provides message: String): StringGraph 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /compiler-compat/version-aliases.txt: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2025 Zac Sweers 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # Kotlin compiler versions to test against in CI 5 | # 6 | # This file must be an equal or superset of the available compiler-compat modules. 7 | # Each line is a Kotlin version that has a corresponding k* module. 8 | # Blank lines and comments (starting with #) are ignored. 9 | 10 | 2.2.20 11 | 2.2.21 12 | 2.3.0-Beta1 13 | 2.3.0-Beta2 14 | 2.3.0-RC 15 | 2.3.0-RC2 16 | 2.3.0-RC3 17 | 2.3.0 18 | 2.3.20-dev-5437 19 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/InjectedTypeInheritsAnAnnotatedAbstractClass.kt: -------------------------------------------------------------------------------- 1 | // Regression test for https://github.com/ZacSweers/metro/pull/1454 2 | @DependencyGraph 3 | interface AppGraph { 4 | val foo: FooImpl 5 | } 6 | 7 | @Inject 8 | class FooImpl: Foo() 9 | 10 | @AmazingApi 11 | abstract class Foo { 12 | val value = "foo" 13 | } 14 | 15 | annotation class AmazingApi 16 | 17 | fun box(): String { 18 | val appGraph = createGraph() 19 | assertSame(appGraph.foo.value, "foo") 20 | return "OK" 21 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/AssistedTypesCannotBeProvidedWithoutQualifiers.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @AssistedInject 4 | class Taco(@Assisted val seasoning: String) { 5 | @AssistedFactory 6 | interface Factory { 7 | fun create(seasoning: String): Taco 8 | } 9 | } 10 | 11 | @DependencyGraph 12 | interface AppGraph { 13 | val taco: Taco 14 | 15 | @Provides 16 | fun provideTaco(factory: Taco.Factory): Taco = factory.create("spicy") 17 | } 18 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/SuggestInjectClassOnSingleContructor.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | class SingleEmptyConstructor @Inject constructor() 3 | 4 | class SingleNonEmptyConstructor @Inject constructor(int: Int) 5 | 6 | class InjectPrimaryConstructor @Inject constructor(int: Int) { 7 | constructor() : this(0) 8 | } 9 | 10 | class InjectSecondaryConstructor internal constructor(int: Int) { 11 | @Inject constructor() : this(0) 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/build 2 | **/.idea/* 3 | !.idea/externalDependencies.xml 4 | !.idea/kotlinTestDataPluginTestDataPaths.xml 5 | .gradle 6 | .kotlin/ 7 | .iml 8 | .project 9 | .classpath 10 | *.iml 11 | local.properties 12 | .DS_Store 13 | 14 | gradle-plugin/docs/ 15 | docs/code-of-conduct.md 16 | docs/contributing.md 17 | docs/changelog.md 18 | docs/samples.md 19 | docs/metrox-android.md 20 | docs/metrox-viewmodel.md 21 | docs/metrox-viewmodel-compose.md 22 | docs/api/ 23 | site/ 24 | temp-clone/ 25 | /benchmark/ 26 | .cache/ 27 | tmp/ 28 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/ProvidingEmptyProviderMapDirectly.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/issues/1069 2 | @Inject class MyIntUser(val ints: Map>) 3 | 4 | @DependencyGraph 5 | interface AppGraph { 6 | val user: MyIntUser 7 | 8 | @Provides fun provideSomeMap(): Map> = emptyMap() 9 | } 10 | 11 | fun box(): String { 12 | val graph = createGraph() 13 | val user = graph.user 14 | assertTrue(user.ints.isEmpty()) 15 | return "OK" 16 | } 17 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/member/SimpleAncestorInjectionWithEmptyChildNoFactory.kt: -------------------------------------------------------------------------------- 1 | @HasMemberInjections 2 | abstract class Parent { 3 | @Inject 4 | var int: Int = 0 5 | } 6 | 7 | class Child : Parent() 8 | 9 | @DependencyGraph 10 | interface AppGraph { 11 | @Provides fun provideInt(): Int = 3 12 | 13 | fun inject(child: Child) 14 | } 15 | 16 | fun box(): String { 17 | val graph = createGraph() 18 | val child = Child() 19 | graph.inject(child) 20 | assertEquals(3, child.int) 21 | return "OK" 22 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/RequiredAnnotationResultsInMissingBindings.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | // OPTIONAL_DEPENDENCY_BEHAVIOR: REQUIRE_OPTIONAL_BINDING 4 | 5 | @Inject 6 | class Example(val value: String? = null) 7 | 8 | @DependencyGraph 9 | interface AppGraph { 10 | val example: Example 11 | val int: Int 12 | 13 | @Provides 14 | fun provideInt(long: Long? = null): Int = long?.toInt() ?: 3 15 | } 16 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/BindsNonThisReturningBodiesShouldError_Interface.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /BindsNonThisReturningBodiesShouldError_Interface.kt:(107,126): error: `@Binds` declarations with bodies should just return `this`. See https://zacsweers.github.io/metro/latest/bindings/#binds for more information. 2 | 3 | /BindsNonThisReturningBodiesShouldError_Interface.kt:(183,196): error: `@Binds` declarations with bodies should just return `this`. See https://zacsweers.github.io/metro/latest/bindings/#binds for more information. 4 | -------------------------------------------------------------------------------- /samples/compose-viewmodels/app/src/commonMain/kotlin/dev/zacsweers/metro/sample/composeviewmodels/app/Routes.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample.composeviewmodels.app 4 | 5 | import kotlinx.serialization.Serializable 6 | 7 | sealed interface Route 8 | 9 | @Serializable data object HomeRoute : Route 10 | 11 | @Serializable data class DetailsRoute(val data: String) : Route 12 | 13 | @Serializable data class SettingsRoute(val userId: String) : Route 14 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/leniency/UnusedProvidersInContainersAreNotValidated.kt: -------------------------------------------------------------------------------- 1 | @BindingContainer 2 | abstract class Bindings { 3 | @Binds abstract val Int.unusedBinding: Number 4 | 5 | companion object { 6 | @Provides 7 | fun unusedString(int: Int): String { 8 | return int.toString() 9 | } 10 | } 11 | } 12 | 13 | @DependencyGraph(bindingContainers = [Bindings::class]) interface AppGraph 14 | 15 | fun box(): String { 16 | val graph = createGraph() 17 | return "OK" 18 | } 19 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/member/MultiInheritanceMemberInject.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/issues/649 2 | 3 | @Inject class Foo 4 | 5 | @Inject class Bar 6 | 7 | @HasMemberInjections 8 | open class Parent { 9 | @Inject lateinit var foo: Foo 10 | } 11 | 12 | class Child : Parent() { 13 | @Inject lateinit var bar: Bar 14 | } 15 | 16 | @DependencyGraph(AppScope::class) 17 | interface TestGraph { 18 | fun inject(target: Child) 19 | } 20 | 21 | fun box(): String { 22 | // TODO() 23 | return "OK" 24 | } 25 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/DaggerFactoryClassCanBeLoaded.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_KSP 2 | 3 | // FILE: ExampleClass.java 4 | import javax.inject.Inject; 5 | 6 | public class ExampleClass { 7 | @Inject public ExampleClass() { 8 | 9 | } 10 | } 11 | 12 | // FILE: ExampleGraph.kt 13 | @DependencyGraph 14 | interface ExampleGraph { 15 | val exampleClass: ExampleClass 16 | } 17 | 18 | fun box(): String { 19 | val graph = createGraph() 20 | assertNotNull(graph.exampleClass) 21 | return "OK" 22 | } 23 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/CannotIncludeGenericContainer.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /CannotIncludeGenericContainer.kt:(175,194): error: Included binding container 'SomeBindings' is generic and thus cannot be included via annotation. Remove its generics or declare it as a graph factory parameter instead. 2 | 3 | /CannotIncludeGenericContainer.kt:(265,284): error: Included binding container 'SomeBindings' is generic and thus cannot be included via annotation. Remove its generics or declare it as a graph factory parameter instead. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/OptionalBindingParamRequiresDefaultValue.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // OPTIONAL_DEPENDENCY_BEHAVIOR: REQUIRE_OPTIONAL_BINDING 3 | 4 | @DependencyGraph 5 | interface AppGraph { 6 | @Provides 7 | fun provideString(@OptionalBinding value: Int): String = value.toString() 8 | } 9 | 10 | @Inject 11 | class Example(@OptionalBinding val value: Int) 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/member/SimpleAncestorInjectionWithEmptyChildWithParentInAnotherModule.kt: -------------------------------------------------------------------------------- 1 | // MODULE: lib 2 | @HasMemberInjections 3 | abstract class Parent { 4 | @Inject 5 | var int: Int = 0 6 | } 7 | 8 | // MODULE: main(lib) 9 | @Inject 10 | class Child : Parent() 11 | 12 | @DependencyGraph 13 | interface AppGraph { 14 | @Provides fun provideInt(): Int = 3 15 | val child: Child 16 | } 17 | 18 | fun box(): String { 19 | val graph = createGraph() 20 | assertEquals(3, graph.child.int) 21 | return "OK" 22 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/InternalBindings.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /module_main_InternalBindings.kt:(154,162): error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: SomeRepository 2 | 3 | SomeRepository is requested at 4 | [AppGraph.Impl.LoggedInGraphImpl] LoggedInGraph.someRepository 5 | 6 | Similar bindings: 7 | - SomeRepository (Contributed by 'SomeRepositoryImpl' but that class is internal to its module and its module is not a friend module to this one.) 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/MultipleMissingDeps.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | 4 | // Specifically a regression to make sure we don't duplicate "requestedAt" calls 5 | 6 | class Foo1 7 | class Foo2 8 | class Foo3 9 | 10 | @Inject 11 | class InjectedThing( 12 | foo1: Foo1, 13 | foo2: Foo2, 14 | foo3: Foo3, 15 | ) 16 | 17 | @DependencyGraph 18 | interface AppGraph { 19 | val injectedThing: InjectedThing 20 | } 21 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/leniency/SomeUnusedAndSomeUsed.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /SomeUnusedAndSomeUsed.kt:(226,229): error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: kotlin.Int 2 | 3 | kotlin.Int is injected at 4 | [AppGraph] AppGraph#(…, ) 5 | kotlin.Number is requested at 6 | [AppGraph] AppGraph#number 7 | 8 | Similar bindings: 9 | - Number (Supertype). Type: Alias. Source: SomeUnusedAndSomeUsed.kt:10:3 10 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/member/MissingMemberInjectionShouldFailBinding1.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /MissingMemberInjectionShouldFailBinding1.kt:(702,726): error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: Implementation 2 | 3 | Implementation is injected at 4 | [TestGraph.$$ContributedSubscopeGraph] SubscopeGraph#bindImplementation(…, instance) 5 | 6 | Similar bindings: 7 | - Base (Supertype). Type: Alias. Source: MissingMemberInjectionShouldFailBinding1.kt:28:3 8 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/member/MissingMemberInjectionShouldFailBinding2.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /MissingMemberInjectionShouldFailBinding2.kt:(505,559): error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: dev.zacsweers.metro.MembersInjector 2 | 3 | dev.zacsweers.metro.MembersInjector is injected at 4 | [TestGraph.$$ContributedSubscopeGraph] SubscopeMultibindingModule#bindClassWithoutMembersInjector(…, instance) 5 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/dependencygraph/MapBuildersUseInlineInstantiation.kt: -------------------------------------------------------------------------------- 1 | // DISABLE_TRANSFORM_PROVIDERS_TO_PRIVATE 2 | 3 | interface IntHolder 4 | 5 | @Inject 6 | @IntKey(3) 7 | @ContributesIntoMap(AppScope::class) 8 | class IntHolderImpl : IntHolder 9 | 10 | @DependencyGraph(AppScope::class) 11 | interface AppGraph { 12 | val ints: Map 13 | val intHolder: Map 14 | 15 | @Provides @IntKey(1) @IntoMap fun provideInt1(): Int = 1 16 | @Provides @IntKey(2) @IntoMap fun provideInt2(): Int = 2 17 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/DaggerFactoryClassCanBeLoadedJakarta.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_KSP 2 | 3 | // FILE: ExampleClass.java 4 | import jakarta.inject.Inject; 5 | 6 | public class ExampleClass { 7 | @Inject public ExampleClass() { 8 | 9 | } 10 | } 11 | 12 | // FILE: ExampleGraph.kt 13 | @DependencyGraph 14 | interface ExampleGraph { 15 | val exampleClass: ExampleClass 16 | } 17 | 18 | fun box(): String { 19 | val graph = createGraph() 20 | assertNotNull(graph.exampleClass) 21 | return "OK" 22 | } 23 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/BindsNonThisReturningBodiesShouldError_AbstractClass.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /BindsNonThisReturningBodiesShouldError_AbstractClass.kt:(112,131): error: `@Binds` declarations with bodies should just return `this`. See https://zacsweers.github.io/metro/latest/bindings/#binds for more information. 2 | 3 | /BindsNonThisReturningBodiesShouldError_AbstractClass.kt:(188,201): error: `@Binds` declarations with bodies should just return `this`. See https://zacsweers.github.io/metro/latest/bindings/#binds for more information. 4 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/kotlin/dev/zacsweers/metro/gradle/metroGradleUtil.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.gradle 4 | 5 | import java.util.Locale 6 | import org.gradle.api.Project 7 | 8 | internal fun String.capitalizeUS() = replaceFirstChar { 9 | if (it.isLowerCase()) it.titlecase(Locale.US) else it.toString() 10 | } 11 | 12 | internal val Project.logVerbosely: Boolean 13 | get() { 14 | return providers.gradleProperty("metro.logVerbosely").isPresent 15 | } 16 | -------------------------------------------------------------------------------- /samples/android-app/src/main/kotlin/dev/zacsweers/metro/sample/android/FragmentKey.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample.android 4 | 5 | import androidx.fragment.app.Fragment 6 | import dev.zacsweers.metro.MapKey 7 | import kotlin.reflect.KClass 8 | 9 | /** A [MapKey] annotation for binding Fragments in a multibinding map. */ 10 | @MapKey 11 | @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) 12 | annotation class FragmentKey(val value: KClass) 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesCannotHaveReceivers_Interface.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesCannotHaveReceivers_Interface.kt:(108,118): error: `@Provides` properties may not be extension properties. Use `@Binds` instead for these. See https://zacsweers.github.io/metro/latest/bindings/#binds for more information. 2 | 3 | /ProvidesCannotHaveReceivers_Interface.kt:(182,195): error: `@Provides` functions may not be extension functions. Use `@Binds` instead for these. See https://zacsweers.github.io/metro/latest/bindings/#binds for more information. 4 | -------------------------------------------------------------------------------- /metrox-android/src/main/kotlin/dev/zacsweers/metrox/android/BroadcastReceiverKey.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metrox.android 4 | 5 | import android.content.BroadcastReceiver 6 | import dev.zacsweers.metro.MapKey 7 | import kotlin.reflect.KClass 8 | 9 | /** A [MapKey] annotation for binding a BroadcastReceiver in a multibinding map. */ 10 | @MapKey 11 | @Target(AnnotationTarget.CLASS) 12 | public annotation class BroadcastReceiverKey(val value: KClass) 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/createGraph/GraphFactoriesMayNotHaveVarargs.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | interface AppGraph { 5 | @DependencyGraph.Factory 6 | interface Factory { 7 | fun create(@Provides vararg args: String): AppGraph 8 | } 9 | } 10 | 11 | @GraphExtension 12 | interface UnitGraph { 13 | @GraphExtension.Factory 14 | interface Factory { 15 | fun create(@Provides vararg args: String): UnitGraph 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/dynamic/CreateDynamicGraphCannotBeInLocalClasses.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /CreateDynamicGraphCannotBeInLocalClasses.kt:(389,442): error: `createDynamicGraphFactory` can only be called from a top-level function or concrete class (non-anonymous, non-local). Containing class 'Local' is a local class. 2 | 3 | /CreateDynamicGraphCannotBeInLocalClasses.kt:(522,575): error: `createDynamicGraphFactory` can only be called from a top-level function or concrete class (non-anonymous, non-local). This call is inside an anonymous object. 4 | -------------------------------------------------------------------------------- /runtime/src/commonMain/kotlin/dev/zacsweers/metro/internal/MultibindingElement.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.internal 4 | 5 | import dev.zacsweers.metro.Qualifier 6 | 7 | /** 8 | * Disambiguates between multiple elements of the same type in a set. Inspired by Guice. 9 | * 10 | * @param bindingId The ID of the set. 11 | * @param elementId The ID of the element. 12 | */ 13 | @Qualifier public annotation class MultibindingElement(val bindingId: String, val elementId: String) 14 | -------------------------------------------------------------------------------- /samples/compose-viewmodels/app/src/jvmMain/kotlin/dev/zacsweers/metro/sample/composeviewmodels/app/Main.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample.composeviewmodels.app 4 | 5 | import androidx.compose.ui.window.singleWindowApplication 6 | import dev.zacsweers.metro.createGraph 7 | 8 | fun main() { 9 | val appGraph = createGraph() 10 | 11 | singleWindowApplication(title = "Compose ViewModels Sample") { 12 | ComposeApp(appGraph.metroViewModelFactory) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /benchmark/startup-android/app/src/main/kotlin/dev/zacsweers/metro/benchmark/startup/android/MainActivity.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.benchmark.startup.android 4 | 5 | import android.app.Activity 6 | import android.os.Bundle 7 | 8 | class MainActivity : Activity() { 9 | override fun onCreate(savedInstanceState: Bundle?) { 10 | super.onCreate(savedInstanceState) 11 | // Signal that the app is fully drawn for startup benchmarking 12 | reportFullyDrawn() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/bindingcontainers/SimpleContainersWithHintsWork.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/issues/733 2 | @SingleIn(AppScope::class) 3 | @DependencyGraph(AppScope::class) 4 | interface AppGraph { 5 | val text: String 6 | } 7 | 8 | @ContributesTo(AppScope::class) 9 | @BindingContainer 10 | object SampleDependency { 11 | @Provides fun provideText(): String = "Hello, Metro!" 12 | } 13 | 14 | fun box(): String { 15 | val graph = createGraph() 16 | assertEquals("Hello, Metro!", graph.text) 17 | return "OK" 18 | } 19 | -------------------------------------------------------------------------------- /compiler/src/main/kotlin/dev/zacsweers/metro/compiler/graph/BaseTypeKey.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler.graph 4 | 5 | internal interface BaseTypeKey> : 6 | Comparable { 7 | val type: Type 8 | val qualifier: Qualifier? 9 | 10 | fun copy(type: Type = this.type, qualifier: Qualifier? = this.qualifier): Subtype 11 | 12 | fun render(short: Boolean, includeQualifier: Boolean = true): String 13 | } 14 | -------------------------------------------------------------------------------- /gradle-plugin/src/main/kotlin/dev/zacsweers/metro/gradle/DiagnosticSeverity.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.gradle 4 | 5 | public enum class DiagnosticSeverity { 6 | /** Emits no diagnostics/does not check. */ 7 | NONE, 8 | 9 | /** Emits a compiler warning if encountered. */ 10 | WARN, 11 | 12 | /** Emits a compiler error if encountered and fails compilation. */ 13 | ERROR; 14 | 15 | public val isEnabled: Boolean 16 | get() = this != DiagnosticSeverity.NONE 17 | } 18 | -------------------------------------------------------------------------------- /benchmark/startup-android/app/src/main/kotlin/dev/zacsweers/metro/benchmark/startup/android/BenchmarkApplication.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.benchmark.startup.android 4 | 5 | import android.app.Application 6 | import dev.zacsweers.metro.benchmark.app.component.createAndInitialize 7 | 8 | class BenchmarkApplication : Application() { 9 | override fun onCreate() { 10 | super.onCreate() 11 | // Initialize the Metro dependency graph 12 | createAndInitialize() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/extensions/ExtensionsCanBeDeclaredWithoutFactories.kt: -------------------------------------------------------------------------------- 1 | @GraphExtension 2 | interface LoggedInGraph { 3 | val int: Int 4 | } 5 | 6 | @DependencyGraph 7 | interface AppGraph { 8 | @Provides fun provideInt(): Int = 3 9 | 10 | fun loggedInGraph(): LoggedInGraph 11 | 12 | val loggedInGraphProp: LoggedInGraph 13 | } 14 | 15 | fun box(): String { 16 | val graph = createGraph() 17 | assertEquals(3, graph.loggedInGraph().int) 18 | assertEquals(3, graph.loggedInGraphProp.int) 19 | return "OK" 20 | } 21 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/member/AncestorInjectionWithEmptyDescendants.kt: -------------------------------------------------------------------------------- 1 | @HasMemberInjections 2 | abstract class Parent { 3 | @Inject 4 | var int: Int = 0 5 | } 6 | 7 | @HasMemberInjections 8 | abstract class Child : Parent() 9 | 10 | @Inject 11 | class GrandChild : Child() 12 | 13 | @DependencyGraph 14 | interface AppGraph { 15 | @Provides fun provideInt(): Int = 3 16 | 17 | val grandChild: GrandChild 18 | } 19 | 20 | fun box(): String { 21 | val graph = createGraph() 22 | assertEquals(3, graph.grandChild.int) 23 | return "OK" 24 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesCannotHaveReceivers_AbstractClass.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesCannotHaveReceivers_AbstractClass.kt:(113,123): error: `@Provides` properties may not be extension properties. Use `@Binds` instead for these. See https://zacsweers.github.io/metro/latest/bindings/#binds for more information. 2 | 3 | /ProvidesCannotHaveReceivers_AbstractClass.kt:(187,200): error: `@Provides` functions may not be extension functions. Use `@Binds` instead for these. See https://zacsweers.github.io/metro/latest/bindings/#binds for more information. 4 | -------------------------------------------------------------------------------- /samples/compose-viewmodels/app/src/androidMain/kotlin/dev/zacsweers/metro/sample/composeviewmodels/app/Graphs.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample.composeviewmodels.app 4 | 5 | import dev.zacsweers.metro.AppScope 6 | import dev.zacsweers.metro.DependencyGraph 7 | import dev.zacsweers.metrox.android.MetroAppComponentProviders 8 | import dev.zacsweers.metrox.viewmodel.ViewModelGraph 9 | 10 | @DependencyGraph(AppScope::class) interface AppGraph : MetroAppComponentProviders, ViewModelGraph 11 | -------------------------------------------------------------------------------- /runtime/src/commonMain/kotlin/dev/zacsweers/metro/Named.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2024 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro 4 | 5 | /** A simple [Qualifier] that disambiguates based on the [name] value. */ 6 | @Target( 7 | AnnotationTarget.CLASS, 8 | AnnotationTarget.FIELD, 9 | AnnotationTarget.FUNCTION, 10 | AnnotationTarget.PROPERTY, 11 | AnnotationTarget.PROPERTY_GETTER, 12 | AnnotationTarget.VALUE_PARAMETER, 13 | AnnotationTarget.TYPE, 14 | ) 15 | @Qualifier 16 | public annotation class Named(val name: String) 17 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/assisted/ImplsAreVisibleAcrossModules.kt: -------------------------------------------------------------------------------- 1 | // MODULE: lib 2 | @AssistedInject 3 | class Example(@Assisted val input: String) { 4 | @AssistedFactory 5 | interface Factory { 6 | fun create(input: String): Example 7 | } 8 | } 9 | 10 | // MODULE: main(lib) 11 | @DependencyGraph 12 | interface AppGraph { 13 | val factory: Example.Factory 14 | } 15 | 16 | fun box(): String { 17 | val graph = createGraph() 18 | val instance = graph.factory.create("Hello") 19 | assertEquals("Hello", instance.input) 20 | return "OK" 21 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/DaggerComponentModulesAnnotationInterop.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_INTEROP 2 | // Similar to DaggerModulesAnnotationInterop.kt but covers components too 3 | import dagger.Component 4 | import dagger.Module 5 | 6 | @Module 7 | class IntModule { 8 | @Provides fun provideInt(): Int = 3 9 | } 10 | 11 | @Component(modules = [IntModule::class]) 12 | interface AppComponent { 13 | val int: Int 14 | } 15 | 16 | fun box(): String { 17 | val graph = createGraph() 18 | assertEquals(3, graph.int) 19 | return "OK" 20 | } 21 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/MismatchedSingleInScopesDisambiguateSameNameScopes.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /MismatchedSingleInScopesDisambiguateSameNameScopes.kt:(406,418): error: [Metro/IncompatiblyScopedBindings] test.graph.ExampleGraph (scopes '@dev.zacsweers.metro.SingleIn(test.graph.AppScope::class)') may not reference bindings from different scopes: 2 | test.graph.MyClass (scoped to '@dev.zacsweers.metro.SingleIn(dev.zacsweers.metro.AppScope::class)') 3 | test.graph.MyClass is requested at 4 | [test.graph.ExampleGraph] test.graph.ExampleGraph.myClass 5 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/BindsMayNotHaveScopes.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | interface BindsInterface { 4 | @Binds @SingleIn(AppScope::class) val String.bind: CharSequence 5 | @Binds @SingleIn(AppScope::class) fun String.bindFunction(): CharSequence 6 | } 7 | 8 | abstract class BindsClass { 9 | @Binds @SingleIn(AppScope::class) abstract val String.bind: CharSequence 10 | @Binds @SingleIn(AppScope::class) abstract fun String.bindFunction(): CharSequence 11 | } 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/injectconstructor/ConstructorFunctionSignatures.kt: -------------------------------------------------------------------------------- 1 | // Golden image to validate that we generate the correct signature for 2 | // constructorFunction() IR breadcrumbs 3 | 4 | @Inject class SimpleClass 5 | @Inject class ClassWithBounds 6 | @Inject class ClassWithNullable 7 | @Inject class ClassWithMultiple 8 | @Inject class ClassWithBackRefs 9 | @Inject class ClassWithWheres where E : V 10 | @Inject class ComplexMonster where E : V, V : T, T : Any -------------------------------------------------------------------------------- /metrox-android/src/main/kotlin/dev/zacsweers/metrox/android/ContentProviderKey.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metrox.android 4 | 5 | import android.content.ContentProvider 6 | import dev.zacsweers.metro.MapKey 7 | import kotlin.reflect.KClass 8 | 9 | /** 10 | * A [MapKey] annotation for binding [ContentProviders][ContentProvider] into a multibinding map. 11 | */ 12 | @MapKey 13 | @Target(AnnotationTarget.CLASS) 14 | public annotation class ContentProviderKey(val value: KClass) 15 | -------------------------------------------------------------------------------- /samples/compose-viewmodels/screen-home/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.multiplatform) 5 | alias(libs.plugins.kotlin.plugin.compose) 6 | alias(libs.plugins.compose) 7 | id("dev.zacsweers.metro") 8 | } 9 | 10 | kotlin { 11 | jvm() 12 | 13 | sourceSets { 14 | commonMain.dependencies { 15 | api("dev.zacsweers.metro:metrox-viewmodel-compose") 16 | implementation(compose.material3) 17 | implementation(compose.runtime) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/dynamic/GraphsAreCachedByType.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface ExampleGraph 3 | 4 | @BindingContainer 5 | object Bindings 6 | 7 | fun example( 8 | graph: ExampleGraph = createDynamicGraph(Bindings), 9 | graph2: ExampleGraph = createDynamicGraph(Bindings), 10 | ): Pair { 11 | return graph to graph2 12 | } 13 | 14 | fun box(): String { 15 | val (graph1, graph2) = example() 16 | assertEquals(graph1::class.qualifiedName, graph2::class.qualifiedName) 17 | return "OK" 18 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/UsefulHintsForMissingImplDeps.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | 4 | // MODULE: core 5 | interface Base 6 | 7 | // MODULE: lib1(core) 8 | @Inject 9 | class FooImpl : Base 10 | 11 | // MODULE: lib2(lib1 core) 12 | @ContributesTo(AppScope::class) 13 | @BindingContainer 14 | interface Bindings { 15 | @Binds val FooImpl.bind: Base 16 | } 17 | 18 | // MODULE: main(lib2 core) 19 | @DependencyGraph(AppScope::class) 20 | interface AppGraph { 21 | val base: Base 22 | } 23 | -------------------------------------------------------------------------------- /samples/compose-viewmodels/screen-details/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.multiplatform) 5 | alias(libs.plugins.kotlin.plugin.compose) 6 | alias(libs.plugins.compose) 7 | id("dev.zacsweers.metro") 8 | } 9 | 10 | kotlin { 11 | jvm() 12 | 13 | sourceSets { 14 | commonMain.dependencies { 15 | api("dev.zacsweers.metro:metrox-viewmodel-compose") 16 | implementation(compose.material3) 17 | implementation(compose.runtime) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/DaggerMultibindsAllowEmptyByDefault.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_INTEROP 2 | 3 | // Regression test for https://github.com/ZacSweers/metro/issues/334 4 | 5 | import dagger.multibindings.Multibinds 6 | 7 | @DependencyGraph 8 | interface ExampleGraph { 9 | @Multibinds fun emptySet(): Set 10 | @Multibinds fun emptyMap(): Map 11 | } 12 | 13 | fun box(): String { 14 | val graph = createGraph() 15 | assertTrue(graph.emptySet().isEmpty()) 16 | assertTrue(graph.emptyMap().isEmpty()) 17 | return "OK" 18 | } 19 | -------------------------------------------------------------------------------- /samples/integration-tests/src/androidUnitTest/kotlin/dev/zacsweers/metro/test/integration/replaces/AndroidPlatformContribution.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.test.integration.replaces 4 | 5 | import dev.zacsweers.metro.AppScope 6 | import dev.zacsweers.metro.ContributesBinding 7 | import dev.zacsweers.metro.Inject 8 | 9 | @ContributesBinding(AppScope::class, replaces = [DefaultPlatform::class]) 10 | @Inject 11 | class AndroidPlatform : Platform { 12 | override val platformName: String = "android" 13 | } 14 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/provides/JvmFieldProvidersAreRespected.kt: -------------------------------------------------------------------------------- 1 | // In this scenario, generated provider factories' newInstance function gets the field directly 2 | @DependencyGraph 3 | abstract class AppGraph { 4 | @Provides @JvmField val stringField: String = "Hello" 5 | // Normal property 6 | @Provides val intAccessor: Int get() = 3 7 | 8 | abstract val string: String 9 | abstract val int: Int 10 | } 11 | 12 | fun box(): String { 13 | val graph = createGraph() 14 | assertEquals("Hello", graph.string) 15 | assertEquals(3, graph.int) 16 | return "OK" 17 | } -------------------------------------------------------------------------------- /samples/android-app/src/main/kotlin/dev/zacsweers/metro/sample/android/WorkerKey.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample.android 4 | 5 | import androidx.work.ListenableWorker 6 | import dev.zacsweers.metro.MapKey 7 | import kotlin.reflect.KClass 8 | 9 | /** A [MapKey] annotation for binding Worker in a multibinding map. */ 10 | @MapKey 11 | @Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY) 12 | @Retention(AnnotationRetention.RUNTIME) 13 | annotation class WorkerKey(val value: KClass) 14 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/member/MemberInjectorRequest.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/discussions/593 2 | class Foo { 3 | @Inject lateinit var message: String 4 | } 5 | 6 | @DependencyGraph 7 | interface AppGraph { 8 | val fooInjector: MembersInjector 9 | 10 | @Provides 11 | fun provideMessage(): String = "message" 12 | } 13 | 14 | fun box(): String { 15 | val graph = createGraph() 16 | val injector = graph.fooInjector 17 | val foo = Foo() 18 | injector.injectMembers(foo) 19 | assertEquals("message", foo.message) 20 | return "OK" 21 | } 22 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/aggregation/InternalHintsAreNotVisibleWithoutFriends.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | // https://github.com/ZacSweers/metro/issues/694 4 | // The syntax goes name(deps)(friends)(dependsOn) 5 | 6 | // MODULE: lib 7 | interface ContributedInterface 8 | 9 | @ContributesBinding(AppScope::class) 10 | @Inject 11 | internal class Impl : ContributedInterface 12 | 13 | // MODULE: main(lib) 14 | @DependencyGraph(AppScope::class) 15 | interface AppGraph { 16 | val contributed: ContributedInterface 17 | } 18 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/DisabledResultsInMissingBindingMultiModule.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | // OPTIONAL_DEPENDENCY_BEHAVIOR: DISABLED 4 | 5 | // MODULE: lib 6 | @Inject 7 | class Example(val value: String? = null) 8 | 9 | interface Base { 10 | val int: Int 11 | 12 | @Provides 13 | fun provideInt(long: Long? = null): Int = long?.toInt() ?: 3 14 | } 15 | 16 | // MODULE: main(lib) 17 | @DependencyGraph 18 | interface AppGraph : Base { 19 | val example: Example 20 | } 21 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/bindingcontainers/BindingContainerViaAnnotationCycleIsOk.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph(bindingContainers = [StringBindings::class]) 2 | interface AppGraph { 3 | val string: String 4 | } 5 | 6 | // Simple self-referencing container 7 | @BindingContainer(includes = [StringBindings::class]) 8 | class StringBindings { 9 | @Provides 10 | fun provideString(): String { 11 | return "string value" 12 | } 13 | } 14 | 15 | fun box(): String { 16 | val graph = createGraph() 17 | assertEquals("string value", graph.string) 18 | return "OK" 19 | } 20 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/assisted/NoAssistedArgsInAssistedInject.kt: -------------------------------------------------------------------------------- 1 | // Regression test for https://github.com/ZacSweers/metro/issues/1235 2 | 3 | @AssistedInject 4 | class Example(val dep: Dependency) { 5 | @AssistedFactory 6 | interface Factory { 7 | fun create(): Example 8 | } 9 | } 10 | 11 | @Inject class Dependency 12 | 13 | @DependencyGraph 14 | interface AppGraph { 15 | val factory: Example.Factory 16 | } 17 | 18 | fun box(): String { 19 | val instance = assertNotNull(createGraph().factory.create()) 20 | assertNotNull(instance.dep) 21 | return "OK" 22 | } 23 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/bindingcontainer/NoProvidesOnParams.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @Suppress("ANNOTATION_WILL_BE_APPLIED_ALSO_TO_PROPERTY_OR_FIELD") 4 | @BindingContainer 5 | class InjectedFromConstructorParameter( 6 | @Provides val default: String, 7 | @param:Provides val parameter: String, 8 | @get:Provides val getter: Int, 9 | @property:Provides val property: Long, 10 | @field:Provides val field: Long, 11 | ) 12 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/aggregation/ContributorsWithSameSimpleNames.kt: -------------------------------------------------------------------------------- 1 | // MODULE: lib 2 | 3 | // FILE: Impl1.kt 4 | package test1 5 | 6 | @ContributesTo(AppScope::class) 7 | interface ContributedInterface 8 | 9 | // FILE: Impl2.kt 10 | package test2 11 | 12 | @ContributesTo(AppScope::class) 13 | interface ContributedInterface 14 | 15 | // MODULE: main(lib) 16 | 17 | // Note the compiler test framework is ok with generating duplicate IR files, so we do this 18 | // IR dump test to golden image it to watch for regressions 19 | @DependencyGraph(scope = AppScope::class) 20 | interface ExampleGraph -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/aggregation/ExcludesWithOrigin.kt: -------------------------------------------------------------------------------- 1 | interface Foo 2 | 3 | @Origin(RealFoo::class) 4 | @Inject 5 | @ContributesBinding(AppScope::class) 6 | class GeneratedRealFoo : RealFoo() 7 | 8 | abstract class RealFoo : Foo 9 | 10 | @Inject 11 | @ContributesBinding(AppScope::class) 12 | class FakeFoo : Foo 13 | 14 | @DependencyGraph(AppScope::class, excludes = [RealFoo::class]) 15 | interface AppGraph { 16 | val foo: Foo 17 | } 18 | 19 | fun box(): String { 20 | val graph = createGraph() 21 | assertEquals("FakeFoo", graph.foo::class.qualifiedName) 22 | return "OK" 23 | } 24 | -------------------------------------------------------------------------------- /samples/compose-viewmodels/screen-settings/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.multiplatform) 5 | alias(libs.plugins.kotlin.plugin.compose) 6 | alias(libs.plugins.compose) 7 | id("dev.zacsweers.metro") 8 | } 9 | 10 | kotlin { 11 | jvm() 12 | 13 | sourceSets { 14 | commonMain { 15 | dependencies { 16 | api("dev.zacsweers.metro:metrox-viewmodel-compose") 17 | implementation(compose.material3) 18 | implementation(compose.runtime) 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/MismatchedSingleInScopesDisambiguateSameNameScopes.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | // https://github.com/ZacSweers/metro/pull/1565 4 | package test.graph 5 | 6 | // Uses metro's AppScope 7 | @SingleIn(dev.zacsweers.metro.AppScope::class) 8 | @Inject 9 | class MyClass 10 | 11 | // Graph uses a custom AppScope 12 | abstract class AppScope private constructor() 13 | 14 | @SingleIn(AppScope::class) 15 | @DependencyGraph(AppScope::class) 16 | interface ExampleGraph { 17 | val myClass: MyClass 18 | } 19 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/provides/ProvidesWithExtensionsAndNonThisReturningBodiesShouldError.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /ProvidesWithExtensionsAndNonThisReturningBodiesShouldError.kt:(115,134): error: `@Provides` properties may not be extension properties. Use `@Binds` instead for these. See https://zacsweers.github.io/metro/latest/bindings/#binds for more information. 2 | 3 | /ProvidesWithExtensionsAndNonThisReturningBodiesShouldError.kt:(185,198): error: `@Provides` functions may not be extension functions. Use `@Binds` instead for these. See https://zacsweers.github.io/metro/latest/bindings/#binds for more information. 4 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/aggregation/InternalHintsInGraph.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/issues/694 2 | // The syntax goes name(deps)(friends)(dependsOn) 3 | 4 | // MODULE: lib 5 | interface ContributedInterface 6 | 7 | @ContributesBinding(AppScope::class) 8 | @Inject 9 | internal class Impl : ContributedInterface 10 | 11 | // MODULE: main()(lib) 12 | @DependencyGraph(AppScope::class) 13 | internal interface AppGraph { 14 | val contributed: ContributedInterface 15 | } 16 | 17 | fun box(): String { 18 | val graph = createGraph() 19 | assertNotNull(graph.contributed) 20 | return "OK" 21 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/guice/InjectedGuiceProviderInteropWorks.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_GUICE_INTEROP 2 | import com.google.inject.Inject 3 | import com.google.inject.Provider 4 | 5 | @DependencyGraph 6 | interface ExampleGraph { 7 | val fooBar: FooBar 8 | } 9 | 10 | class Foo @Inject constructor() 11 | 12 | class FooBar @Inject constructor(val provider: Provider) 13 | 14 | fun box(): String { 15 | val graph = createGraph() 16 | val fooInstance = graph.fooBar.provider 17 | assertNotNull(fooInstance) 18 | assertEquals(fooInstance.get().javaClass.name, "Foo") 19 | return "OK" 20 | } 21 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/function/LazyAssistedFactoryFunctionInjection.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @AssistedFactory 4 | interface MyAssistedFactory { 5 | fun create(param: String): MyClass 6 | } 7 | 8 | @AssistedInject 9 | class MyClass( 10 | @Assisted val param: String, 11 | val dependency: String 12 | ) 13 | 14 | // Function injection with lazy-wrapped assisted factory parameter should be an error 15 | @Inject 16 | fun injectFunction( 17 | factory: Lazy, 18 | other: String 19 | ) { 20 | // Function body 21 | } 22 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/aggregation/ReplacementsWithOrigin.kt: -------------------------------------------------------------------------------- 1 | interface Foo 2 | 3 | @Origin(RealFoo::class) 4 | @Inject 5 | @ContributesBinding(AppScope::class) 6 | class GeneratedRealFoo : RealFoo() 7 | 8 | abstract class RealFoo : Foo 9 | 10 | @Inject 11 | @ContributesBinding(scope = AppScope::class, replaces = [RealFoo::class]) 12 | class FakeFoo : Foo 13 | 14 | @DependencyGraph(AppScope::class) 15 | interface AppGraph { 16 | val foo: Foo 17 | } 18 | 19 | fun box(): String { 20 | val graph = createGraph() 21 | assertEquals("FakeFoo", graph.foo::class.qualifiedName) 22 | return "OK" 23 | } 24 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/assisted/AssistedTypesCanBeProvidedWithQualifiers.kt: -------------------------------------------------------------------------------- 1 | @AssistedInject 2 | class Taco(@Assisted val seasoning: String) { 3 | @AssistedFactory 4 | interface Factory { 5 | fun create(seasoning: String): Taco 6 | } 7 | } 8 | 9 | @DependencyGraph 10 | interface AppGraph { 11 | @Named("qualified") val taco: Taco 12 | 13 | @Provides @Named("qualified") 14 | fun provideTaco(factory: Taco.Factory): Taco = factory.create("spicy") 15 | } 16 | 17 | fun box(): String { 18 | val graph = createGraph() 19 | assertEquals("spicy", graph.taco.seasoning) 20 | return "OK" 21 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/member/GenericMemberInjectorRequest.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/discussions/593 2 | class Foo { 3 | @Inject lateinit var message: T 4 | } 5 | 6 | @DependencyGraph 7 | interface AppGraph { 8 | val fooInjector: MembersInjector> 9 | 10 | @Provides 11 | fun provideMessage(): String = "message" 12 | } 13 | 14 | fun box(): String { 15 | val graph = createGraph() 16 | val injector = graph.fooInjector 17 | val foo = Foo() 18 | injector.injectMembers(foo) 19 | assertEquals("message", foo.message) 20 | return "OK" 21 | } 22 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/createGraph/CreateGraph_OkCase.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface ExampleGraph 3 | 4 | @DependencyGraph 5 | interface ExampleGraphWithFactory { 6 | @DependencyGraph.Factory 7 | interface Factory { 8 | fun create(): ExampleGraphWithFactory 9 | } 10 | } 11 | 12 | fun example() { 13 | val exampleGraph = createGraph() 14 | val exampleGraphWithFactory = createGraphFactory().create() 15 | val exampleGraph2: ExampleGraph = createGraph() 16 | val exampleGraphFactory: ExampleGraphWithFactory.Factory = createGraphFactory() 17 | } 18 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/optional/RequiredAnnotationResultsInMissingBindingMultiModule.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | // OPTIONAL_DEPENDENCY_BEHAVIOR: REQUIRE_OPTIONAL_BINDING 4 | 5 | // MODULE: lib 6 | @Inject 7 | class Example(val value: String? = null) 8 | 9 | interface Base { 10 | val int: Int 11 | 12 | @Provides 13 | fun provideInt(@OptionalBinding long: Long? = null): Int = long?.toInt() ?: 3 14 | } 15 | 16 | // MODULE: main(lib) 17 | @DependencyGraph 18 | interface AppGraph : Base { 19 | val example: Example 20 | } 21 | -------------------------------------------------------------------------------- /samples/compose-viewmodels/app/src/androidMain/kotlin/dev/zacsweers/metro/sample/composeviewmodels/app/MetroApp.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample.composeviewmodels.app 4 | 5 | import android.app.Application 6 | import dev.zacsweers.metro.createGraph 7 | import dev.zacsweers.metrox.android.MetroAppComponentProviders 8 | import dev.zacsweers.metrox.android.MetroApplication 9 | 10 | class MetroApp : Application(), MetroApplication { 11 | override val appComponentProviders: MetroAppComponentProviders by lazy { createGraph() } 12 | } 13 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/AnotherBindsOptionalPresentTest.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_INTEROP 2 | import java.util.Optional 3 | 4 | @DependencyGraph(AppScope::class, bindingContainers = [Bindings::class]) 5 | interface AppGraph { 6 | val optional: Optional 7 | 8 | @Provides @SingleIn(AppScope::class) val string: String get() = "Hello" 9 | } 10 | 11 | @dagger.Module 12 | interface Bindings { 13 | @dagger.BindsOptionalOf 14 | fun string(): String 15 | } 16 | 17 | fun box(): String { 18 | val graph = createGraph() 19 | assertEquals("Hello", graph.optional.get()) 20 | return "OK" 21 | } 22 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/fir/private-provides-status-transformation/ProvidersAreMadePrivate.kt: -------------------------------------------------------------------------------- 1 | interface ExampleProviders { 2 | @Provides 3 | fun shouldBePrivate(): String = "hello" 4 | 5 | @Provides 6 | public fun shouldNotBePrivate1(): String = "hello" 7 | 8 | @Provides 9 | private fun shouldBePrivate2(): String = "hello" 10 | 11 | companion object { 12 | @Provides 13 | fun shouldBePrivate(): String = "hello" 14 | 15 | @Provides 16 | public fun shouldNotBePrivate1(): String = "hello" 17 | 18 | @Provides 19 | internal fun shouldNotBePrivate2(): String = "hello" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/dump/ir/visibility/InternalVisibilityDifferentModule.kt: -------------------------------------------------------------------------------- 1 | // Test direct invocation checks for internal members in different module 2 | // Internal bindings from another module should not support direct invocation 3 | 4 | // MODULE: lib 5 | @Inject class InternalClass internal constructor() 6 | 7 | @BindingContainer 8 | object IntProvider { 9 | @Provides internal fun provideInt(): Int = 42 10 | } 11 | 12 | // MODULE: main(lib) 13 | @DependencyGraph(bindingContainers = [IntProvider::class]) 14 | abstract class AppGraph { 15 | abstract val int: Int 16 | abstract val internalClass: InternalClass 17 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/ExposingIncludedGraphsDirectly.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/issues/1144 2 | 3 | @DependencyGraph 4 | interface PushComponent { 5 | fun foo(): Foo 6 | 7 | @DependencyGraph.Factory 8 | interface Factory { 9 | fun create(@Includes foo: Foo): PushComponent 10 | } 11 | } 12 | 13 | interface Foo { 14 | val a: String 15 | } 16 | 17 | fun box(): String { 18 | val foo = object : Foo { 19 | override val a: String = "hello" 20 | } 21 | val graph = createGraphFactory().create(foo) 22 | assertSame(foo, graph.foo()) 23 | return "OK" 24 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/provides/CapitalizedProvides.kt: -------------------------------------------------------------------------------- 1 | /* 2 | Regression test for https://github.com/ZacSweers/metro/issues/456 3 | */ 4 | 5 | @DependencyGraph(AppScope::class) 6 | interface App { 7 | val suit: Suit 8 | } 9 | 10 | enum class Suit { 11 | HEARTS, 12 | DIAMONDS, 13 | CLUBS, 14 | SPADES, 15 | } 16 | 17 | @ContributesTo(AppScope::class) 18 | interface SuitProvider { 19 | // note the capital S in "fun Suit()" 20 | @Provides @SingleIn(AppScope::class) fun Suit(): Suit = Suit.SPADES 21 | } 22 | 23 | fun box(): String { 24 | assertEquals(createGraph().suit, Suit.SPADES) 25 | return "OK" 26 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/MixedCycleParams.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /MixedCycleParams.kt:(501,511): error: [Metro/DependencyCycle] Found a dependency cycle while processing 'CycleGraph'. 2 | Cycle: 3 | RealA --> B --> FakeA --> A --> RealA 4 | 5 | Trace: 6 | RealA is injected at 7 | [CycleGraph] B() 8 | B is injected at 9 | [CycleGraph] FakeA(…, b) 10 | FakeA is injected at 11 | [CycleGraph] FakeA.$$MetroContributionToUnit#bindsAsA(…, instance) 12 | A is injected at 13 | [CycleGraph] RealA() 14 | RealA is injected at 15 | [CycleGraph] B() 16 | ... 17 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/ProvidingEmptyMultibindingsDirectly.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/issues/1069 2 | @Inject class MyIntUser(val ints: Set, val intsMap: Map) 3 | 4 | @DependencyGraph 5 | interface AppGraph { 6 | val user: MyIntUser 7 | 8 | @Provides fun provideSomeMap(): Map = emptyMap() 9 | 10 | @Provides fun provideInts(): Set = emptySet() 11 | } 12 | 13 | fun box(): String { 14 | val graph = createGraph() 15 | val user = graph.user 16 | assertTrue(user.ints.isEmpty()) 17 | assertTrue(user.intsMap.isEmpty()) 18 | return "OK" 19 | } 20 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/interop/dagger/MemberInjectionQualifiersAreLookedUp.fir.ir.diag.txt: -------------------------------------------------------------------------------- 1 | /ExampleGraph.kt:(126,138): error: [Metro/MissingBinding] Cannot find an @Inject constructor or @Provides-annotated function/property for: @javax.inject.Named("qualified") Dependency 2 | 3 | @javax.inject.Named("qualified") Dependency is injected at 4 | [ExampleGraph] ExampleGraph.inject() 5 | dev.zacsweers.metro.MembersInjector is requested at 6 | [ExampleGraph] ExampleGraph.inject() 7 | 8 | Similar bindings: 9 | - Dependency (Different qualifier). Type: Alias. Source: DependencyImpl.kt:26:1 10 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/interop/dagger/PositionalAnnotationArgsError.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /PositionalAnnotationArgsError.kt:(283,298): error: Interop annotation @MergeComponent should use named arguments instead of positional arguments for better compatibility in Metro. 2 | 3 | /PositionalAnnotationArgsError.kt:(318,335): error: Interop annotation @MergeComponent should use named arguments instead of positional arguments for better compatibility in Metro. 4 | 5 | /PositionalAnnotationArgsError.kt:(360,378): error: Interop annotation @MergeComponent should use named arguments instead of positional arguments for better compatibility in Metro. 6 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/interop/dagger/PositionalAnnotationArgsError.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // WITH_DAGGER 3 | // WITH_ANVIL 4 | // INTEROP_ANNOTATIONS_NAMED_ARG_SEVERITY: ERROR 5 | 6 | import com.squareup.anvil.annotations.MergeComponent 7 | 8 | interface Providers 9 | 10 | @dagger.Module 11 | interface Bindings 12 | 13 | @MergeComponent( 14 | /* scope = */ AppScope::class, 15 | /* modules = */ [Bindings::class], 16 | /* dependencies = */ [Providers::class] 17 | ) 18 | interface AppComponent 19 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/assisted/DefaultAssistedFactoryIsGeneratedInFIR.kt: -------------------------------------------------------------------------------- 1 | // GENERATE_ASSISTED_FACTORIES 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int, 5 | val message: String, 6 | ) 7 | 8 | @DependencyGraph 9 | interface AppGraph { 10 | val factory: ExampleClass.Factory 11 | @Provides val string: String get() = "Hello, " 12 | } 13 | 14 | fun box(): String { 15 | val factory = createGraph().factory 16 | // Smoke test to ensure that the FIR-generated 17 | assertEquals(2, factory.create(count = 2).count) 18 | assertEquals(3, factory.create(count = 3).count) 19 | return "OK" 20 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/interop/dagger/PositionalAnnotationArgsWarning.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // WITH_DAGGER 3 | // WITH_ANVIL 4 | // INTEROP_ANNOTATIONS_NAMED_ARG_SEVERITY: WARN 5 | 6 | import com.squareup.anvil.annotations.MergeComponent 7 | 8 | interface Providers 9 | 10 | @dagger.Module 11 | interface Bindings 12 | 13 | @MergeComponent( 14 | /* scope = */ AppScope::class, 15 | /* modules = */ [Bindings::class], 16 | /* dependencies = */ [Providers::class] 17 | ) 18 | interface AppComponent 19 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/aggregation/ContributingMultibileNullableBindings.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/issues/779 2 | interface SomeRepo 3 | 4 | @ContributesBinding(AppScope::class, binding = binding()) 5 | @ContributesBinding(AppScope::class, binding = binding()) 6 | @Inject 7 | class SomeRepoImpl : SomeRepo 8 | 9 | @DependencyGraph(AppScope::class) 10 | interface AppGraph { 11 | val repo: SomeRepo 12 | val nullableRepo: SomeRepo? 13 | } 14 | 15 | fun box(): String { 16 | val graph = createGraph() 17 | assertNotNull(graph.repo) 18 | assertNotNull(graph.nullableRepo) 19 | return "OK" 20 | } -------------------------------------------------------------------------------- /benchmark/startup-jvm/minified-jar/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Keep the createAndInitialize function as the entry point for benchmarks 2 | -keep class dev.zacsweers.metro.benchmark.app.component.AppComponentKt { 3 | public static *** createAndInitialize(); 4 | } 5 | 6 | # Keep AppComponent and its public methods since it's the return type of createAndInitialize 7 | -keep class dev.zacsweers.metro.benchmark.app.component.AppComponent { 8 | public *; 9 | } 10 | 11 | # Don't warn about missing classes 12 | -dontwarn javax.annotation.** 13 | -dontwarn org.jetbrains.annotations.** 14 | 15 | # Optimization settings 16 | -allowaccessmodification 17 | -dontobfuscate -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/InjectedJavaxProviderInteropWorks.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_INTEROP 2 | package test 3 | 4 | import javax.inject.Inject 5 | import javax.inject.Provider 6 | 7 | @DependencyGraph 8 | interface ExampleGraph { 9 | val fooBar: FooBar 10 | } 11 | 12 | class Foo @Inject constructor() 13 | 14 | class FooBar @Inject constructor( 15 | val provider: Provider 16 | ) 17 | 18 | fun box(): String { 19 | val graph = createGraph() 20 | val fooInstance = graph.fooBar.provider 21 | assertNotNull(fooInstance) 22 | assertEquals(fooInstance.get().javaClass.name, "test.Foo") 23 | return "OK" 24 | } 25 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/JavaxProviderShouldWorkInSet.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_INTEROP 2 | // Ref https://github.com/ZacSweers/metro/pull/666 3 | import javax.inject.Provider 4 | 5 | @DependencyGraph(AppScope::class) 6 | interface AppGraph { 7 | val urlHandlers: Set 8 | } 9 | 10 | interface UrlHandler 11 | 12 | @Inject 13 | @ContributesIntoSet(AppScope::class) 14 | class PostUrlHandler : UrlHandler { 15 | fun handle(url: String) { 16 | url.toString() 17 | } 18 | } 19 | 20 | fun box(): String { 21 | val graph = createGraph() 22 | assertNotNull(graph.urlHandlers.single()) 23 | return "OK" 24 | } 25 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/guice/InjectedKotlinLazyFromGuiceProviderWorks.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_GUICE_INTEROP 2 | import com.google.inject.Inject 3 | 4 | @DependencyGraph 5 | interface ExampleGraph { 6 | val fooBar: FooBar 7 | } 8 | 9 | class Foo @Inject constructor() 10 | 11 | class FooBar @Inject constructor(val lazy: Lazy) 12 | 13 | fun box(): String { 14 | val graph = createGraph() 15 | val fooInstance = graph.fooBar.lazy 16 | assertNotNull(fooInstance) 17 | // Verify it's a Kotlin Lazy 18 | assertTrue(fooInstance is Lazy<*>) 19 | assertEquals(fooInstance.value.javaClass.name, "Foo") 20 | return "OK" 21 | } 22 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/AssistedTypesCannotBeDirectlyQualified.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @Named("qualified") 4 | @AssistedInject 5 | class Taco(@Assisted val seasoning: String) { 6 | @AssistedFactory 7 | interface Factory { 8 | fun create(seasoning: String): Taco 9 | } 10 | } 11 | 12 | @Suppress("SUGGEST_CLASS_INJECTION") 13 | @Named("qualified") 14 | class Taco2 @AssistedInject constructor(@Assisted val seasoning: String) { 15 | @AssistedFactory 16 | interface Factory { 17 | fun create(seasoning: String): Taco 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/member/MembersInjectorParameterWithNoDefaultShouldError.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | // Repro https://github.com/ZacSweers/metro/issues/659 4 | class ClassWithoutMembersInjector 5 | 6 | @DependencyGraph(AppScope::class) 7 | interface TestGraph { 8 | 9 | val injector: MembersInjector<*> 10 | 11 | @Provides 12 | fun provideGenericMembersInjector( 13 | // No default value, we should report this missing 14 | instance: MembersInjector 15 | ): MembersInjector<*> { 16 | return instance 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/interop/dagger/PositionalAnnotationArgsWarning.fir.diag.txt: -------------------------------------------------------------------------------- 1 | /PositionalAnnotationArgsWarning.kt:(282,297): warning: Interop annotation @MergeComponent should use named arguments instead of positional arguments for better compatibility in Metro. 2 | 3 | /PositionalAnnotationArgsWarning.kt:(317,334): warning: Interop annotation @MergeComponent should use named arguments instead of positional arguments for better compatibility in Metro. 4 | 5 | /PositionalAnnotationArgsWarning.kt:(359,377): warning: Interop annotation @MergeComponent should use named arguments instead of positional arguments for better compatibility in Metro. 6 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/QualifiedDaggerFactoryClassCanBeLoaded.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_KSP 2 | 3 | // FILE: ExampleClass.java 4 | import javax.inject.Inject; 5 | import javax.inject.Named; 6 | 7 | @Named("qualifier") 8 | public class ExampleClass { 9 | @Inject public ExampleClass() { 10 | 11 | } 12 | } 13 | 14 | // FILE: ExampleGraph.kt 15 | import javax.inject.Named 16 | 17 | @DependencyGraph 18 | interface ExampleGraph { 19 | @Named("qualifier") val exampleClass: ExampleClass 20 | } 21 | 22 | fun box(): String { 23 | val graph = createGraph() 24 | assertNotNull(graph.exampleClass) 25 | return "OK" 26 | } 27 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/inject/ProvidingAConstructorInjectedTypeHasASpecificWarning.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // Originally from for https://github.com/ZacSweers/metro/issues/1193 3 | 4 | @DependencyGraph 5 | interface AComponent { 6 | val bar: Bar 7 | 8 | @Provides 9 | fun text(): String = "Hola" 10 | } 11 | 12 | @Inject 13 | class Bar(text: String) 14 | 15 | @DependencyGraph 16 | interface BComponent { 17 | val bar: Bar 18 | 19 | @Provides 20 | fun aComponent(): AComponent = createGraph() 21 | 22 | @Provides 23 | fun bar(aComponent: AComponent): Bar = aComponent.bar 24 | } 25 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/cycles/BindsCycleGraph.kt: -------------------------------------------------------------------------------- 1 | interface Foo 2 | 3 | @Inject class Bar(val fooProvider: Provider) : Foo 4 | 5 | /** 6 | * A component with a cycle in which a `@Binds` binding depends on the binding that has to be 7 | * deferred. 8 | */ 9 | @DependencyGraph 10 | interface BindsCycleGraph { 11 | fun bar(): Bar 12 | 13 | @Binds fun foo(bar: Bar): Foo 14 | } 15 | 16 | /** 17 | * Tests that a cycle where a `@Binds` binding depends on a binding that has to be deferred works. 18 | */ 19 | fun box(): String { 20 | val bindsCycleGraph = createGraph() 21 | assertNotNull(bindsCycleGraph.bar()) 22 | return "OK" 23 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/assisted/DefaultAssistedFactoryWithDefaultValues.kt: -------------------------------------------------------------------------------- 1 | // GENERATE_ASSISTED_FACTORIES 2 | @AssistedInject 3 | class ExampleClass( 4 | @Assisted val count: Int = 2, 5 | val message: String, 6 | ) 7 | 8 | @DependencyGraph 9 | interface AppGraph { 10 | val factory: ExampleClass.Factory 11 | @Provides val string: String get() = "hello" 12 | } 13 | 14 | fun box(): String { 15 | val factory = createGraph().factory 16 | // Smoke test to ensure that the FIR-generated create() supports default args 17 | val created = factory.create() 18 | // Default value 19 | assertEquals(2, created.count) 20 | return "OK" 21 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/inject/member/MemberInjectorRequestAsProvidesParam.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/discussions/593 2 | class Foo { 3 | @Inject lateinit var message: String 4 | } 5 | 6 | @DependencyGraph 7 | interface AppGraph { 8 | val foo: Foo 9 | 10 | @Provides fun provideFoo(fooInjector: MembersInjector): Foo { 11 | return Foo().apply { fooInjector.injectMembers(this) } 12 | } 13 | 14 | @Provides 15 | fun provideMessage(): String = "message" 16 | } 17 | 18 | fun box(): String { 19 | val graph = createGraph() 20 | val foo = graph.foo 21 | assertEquals("message", foo.message) 22 | return "OK" 23 | } 24 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/MissingBindingHintsShouldReportInternalOnlyIfInternal.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | 4 | // Ensures we don't try to mis-report indirect upstream modules as not visible 5 | 6 | // MODULE: core 7 | interface Base 8 | 9 | // MODULE: lib1(core) 10 | @Inject 11 | @ContributesBinding(String::class) 12 | class FooImpl : Base 13 | 14 | // MODULE: main(lib1 core) 15 | @DependencyGraph(AppScope::class) 16 | interface AppGraph { 17 | val base: Base 18 | 19 | val stringGraph: StringGraph 20 | } 21 | 22 | @GraphExtension(String::class) 23 | interface StringGraph -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/extensions/ExtensionsUsingDeferredTypesAreValid.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/pull/977 2 | @GraphExtension 3 | interface LoggedInGraph { 4 | val foo: Foo 5 | } 6 | 7 | @DependencyGraph 8 | @SingleIn(AppScope::class) 9 | interface AppGraph { 10 | val loggedInGraph: LoggedInGraph 11 | } 12 | 13 | @Inject @SingleIn(AppScope::class) class Foo(val fooProvider: Provider) 14 | 15 | fun box(): String { 16 | val graph = createGraph() 17 | val loggedInGraph = graph.loggedInGraph 18 | assertNotNull(loggedInGraph.foo) 19 | assertSame(loggedInGraph.foo, loggedInGraph.foo) 20 | return "OK" 21 | } 22 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/extensions/SimpleExtension.kt: -------------------------------------------------------------------------------- 1 | @GraphExtension 2 | interface LoggedInGraph { 3 | val id: String 4 | val count: Int 5 | 6 | @GraphExtension.Factory 7 | interface Factory { 8 | fun createLoggedInGraph(@Provides id: String): LoggedInGraph 9 | } 10 | } 11 | 12 | @DependencyGraph 13 | interface AppGraph : LoggedInGraph.Factory { 14 | @Provides fun provideCount(): Int = 3 15 | } 16 | 17 | fun box(): String { 18 | val graph = createGraph() 19 | val loggedInGraph = graph.createLoggedInGraph("123") 20 | assertEquals("123", loggedInGraph.id) 21 | assertEquals(3, loggedInGraph.count) 22 | return "OK" 23 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/graph/LazyAssistedFactoryGraphAccessor.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | 3 | @DependencyGraph 4 | interface MyGraph { 5 | // Graph accessor returning a lazy-wrapped assisted factory should be an error 6 | abstract fun assistedFactory(): Lazy 7 | val assistedFactoryProp: Lazy 8 | } 9 | 10 | @AssistedFactory 11 | interface MyAssistedFactory { 12 | fun create(param: String): MyClass 13 | } 14 | 15 | @AssistedInject 16 | class MyClass( 17 | @Assisted val param: String, 18 | val dependency: String 19 | ) 20 | -------------------------------------------------------------------------------- /compiler-compat/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { alias(libs.plugins.kotlin.jvm) } 4 | 5 | kotlin { 6 | compilerOptions { 7 | freeCompilerArgs.add("-Xcontext-parameters") 8 | optIn.addAll( 9 | "org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi", 10 | "org.jetbrains.kotlin.ir.symbols.UnsafeDuringIrConstructionAPI", 11 | ) 12 | } 13 | } 14 | 15 | dependencies { 16 | compileOnly(libs.kotlin.compiler) 17 | compileOnly(libs.kotlin.stdlib) 18 | 19 | testImplementation(libs.junit) 20 | testImplementation(libs.kotlin.test) 21 | testImplementation(libs.truth) 22 | } 23 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/interop/dagger/BindsOptionalOfDiagnostics.kt: -------------------------------------------------------------------------------- 1 | // RENDER_DIAGNOSTICS_FULL_TEXT 2 | // ENABLE_DAGGER_INTEROP 3 | 4 | import dagger.BindsOptionalOf 5 | import java.util.Optional 6 | 7 | @BindingContainer 8 | interface Bindings { 9 | @BindsOptionalOf 10 | fun providerString(): Provider 11 | 12 | @BindsOptionalOf 13 | fun lazyInt(): Lazy 14 | 15 | @BindsOptionalOf 16 | fun providerOfLazyLong(): Provider> 17 | 18 | @BindsOptionalOf 19 | fun optionalOptional(): Optional 20 | } 21 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/aggregation/ContributedBindingContainerReplacements.kt: -------------------------------------------------------------------------------- 1 | // Similar to the BindingContainerViaAnnotation test but contributed 2 | @DependencyGraph(AppScope::class) 3 | interface AppGraph { 4 | val int: Int 5 | } 6 | 7 | @ContributesTo(AppScope::class) 8 | @BindingContainer 9 | object IntBinding1 { 10 | @Provides fun provideInt(): Int = 1 11 | } 12 | 13 | @ContributesTo(AppScope::class, replaces = [IntBinding1::class]) 14 | @BindingContainer 15 | object IntBinding2 { 16 | @Provides fun provideInt(): Int = 2 17 | } 18 | 19 | fun box(): String { 20 | val graph = createGraph() 21 | assertEquals(2, graph.int) 22 | return "OK" 23 | } 24 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/provides/QualifiersOnDifferentAnnotationSites.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/issues/807 2 | @DependencyGraph 3 | interface Graph { 4 | @Multibinds(allowEmpty = true) 5 | val set1: Set 6 | 7 | @Named("s2") 8 | val set2: Set 9 | 10 | @Provides 11 | @IntoSet 12 | @Named("s2") 13 | val provideValue1: Int 14 | get() = 1 15 | 16 | @Provides 17 | @IntoSet 18 | @get:Named("s2") 19 | val provideValue2: Int 20 | get() = 2 21 | } 22 | 23 | fun box(): String { 24 | val graph = createGraph() 25 | assertEquals(emptySet(), graph.set1) 26 | assertEquals(setOf(1, 2), graph.set2) 27 | return "OK" 28 | } -------------------------------------------------------------------------------- /samples/interop/customAnnotations-kotlinInject/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | plugins { 4 | alias(libs.plugins.kotlin.multiplatform) 5 | id("dev.zacsweers.metro") 6 | } 7 | 8 | kotlin { 9 | jvm() 10 | 11 | sourceSets { 12 | commonMain { 13 | dependencies { 14 | implementation(libs.kotlinInject.runtime) 15 | implementation(libs.kotlinInject.anvil.runtime) 16 | } 17 | } 18 | commonTest { dependencies { implementation(libs.kotlin.test) } } 19 | } 20 | } 21 | 22 | metro { 23 | interop { 24 | includeKotlinInject() 25 | includeAnvilForKotlinInject() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/OverrideCompatibleAccessorsFromContributedInterface.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface ExampleGraph { 3 | 4 | @DependencyGraph.Factory 5 | interface Factory { 6 | fun create(@Includes serviceProvider: ServiceProvider): ExampleGraph 7 | } 8 | } 9 | 10 | @DependencyGraph(AppScope::class) 11 | interface AppGraph { 12 | val int: Int 13 | 14 | @Provides 15 | fun providesInt(): Int = 3 16 | } 17 | 18 | @ContributesTo(AppScope::class) 19 | interface ServiceProvider { 20 | val int: Int 21 | } 22 | 23 | fun box(): String { 24 | val appGraph = createGraph() 25 | assertEquals(appGraph.int, 3) 26 | return "OK" 27 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/extensions/FieldInjectorInGraphExtensionContainer.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph(AppScope::class) 2 | interface MainGraph { 3 | val childGraph: ChildGraph 4 | } 5 | 6 | @GraphExtension(bindingContainers = [ChildModule::class]) 7 | interface ChildGraph { 8 | fun injectFoo(instance: Foo) 9 | } 10 | 11 | @BindingContainer 12 | object ChildModule { 13 | @Provides fun provideTitle(): String = "Foo" 14 | } 15 | 16 | class Foo { 17 | @Inject lateinit var title: String 18 | } 19 | 20 | fun box(): String { 21 | val foo = Foo() 22 | createGraph().childGraph.injectFoo(foo) 23 | assertEquals("Foo", foo.title) 24 | return "OK" 25 | } 26 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/extensions/MultipleExtensionFactoriesAreValid.kt: -------------------------------------------------------------------------------- 1 | // https://github.com/ZacSweers/metro/issues/1143 2 | 3 | @DependencyGraph(AppScope::class) 4 | interface AppGraph { 5 | val loggedInGraphFactory: LoggedInGraph.Factory 6 | 7 | fun userGraphFactory(): LoggedInGraph.Factory 8 | } 9 | 10 | @GraphExtension 11 | interface LoggedInGraph { 12 | @GraphExtension.Factory 13 | interface Factory { 14 | fun create(): LoggedInGraph 15 | } 16 | } 17 | 18 | fun box(): String { 19 | val graph = createGraph() 20 | assertNotNull(graph.loggedInGraphFactory) 21 | assertNotNull(graph.userGraphFactory()) 22 | return "OK" 23 | } 24 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/bindingcontainers/BindingContainerViaCreator.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | val string: String 4 | 5 | @DependencyGraph.Factory 6 | interface Factory { 7 | fun create(@Includes stringBindings: StringBindings): AppGraph 8 | } 9 | } 10 | 11 | @BindingContainer 12 | class StringBindings(private val value: String) { 13 | @Provides 14 | fun provideString(): String { 15 | return "string value: $value" 16 | } 17 | } 18 | 19 | fun box(): String { 20 | val graph = createGraphFactory().create(StringBindings("hello")) 21 | assertEquals("string value: hello", graph.string) 22 | return "OK" 23 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/multibindings/LazyMemberInjectedBindings.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph 2 | interface AppGraph { 3 | fun inject(target: ExampleClass) 4 | 5 | @Provides @IntoSet fun provideInt(): Int = 3 6 | @Provides @IntoMap @IntKey(3) fun provideIntIntoMap(): Int = 3 7 | } 8 | 9 | class ExampleClass { 10 | @Inject lateinit var intSet: Lazy> 11 | @Inject lateinit var intMap: Lazy> 12 | } 13 | 14 | fun box(): String { 15 | val graph = createGraph() 16 | val instance = ExampleClass() 17 | graph.inject(instance) 18 | assertEquals(setOf(3), instance.intSet.value) 19 | assertEquals(mapOf(3 to 3), instance.intMap.value) 20 | return "OK" 21 | } -------------------------------------------------------------------------------- /compiler-tests/src/test/kotlin/dev/zacsweers/metro/compiler/interop/Jsr330Utils.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.compiler.interop 4 | 5 | import java.io.File 6 | 7 | internal val javaxInteropClasspath = 8 | System.getProperty("javaxInterop.classpath")?.split(File.pathSeparator)?.map(::File) 9 | ?: error("Unable to get a valid classpath from 'javaxInterop.classpath' property") 10 | 11 | internal val jakartaInteropClasspath = 12 | System.getProperty("jakartaInterop.classpath")?.split(File.pathSeparator)?.map(::File) 13 | ?: error("Unable to get a valid classpath from 'jakartaInterop.classpath' property") 14 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/GenericDaggerFactoryClassCanBeLoaded.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_KSP 2 | 3 | // FILE: ExampleClass.java 4 | import javax.inject.Inject; 5 | 6 | public class ExampleClass { 7 | public final T value; 8 | 9 | @Inject public ExampleClass(T value) { 10 | this.value = value; 11 | } 12 | } 13 | 14 | // FILE: ExampleGraph.kt 15 | @DependencyGraph 16 | interface ExampleGraph { 17 | val exampleClass: ExampleClass 18 | 19 | @Provides val int: Int get() = 3 20 | } 21 | 22 | fun box(): String { 23 | val graph = createGraph() 24 | val intClass = graph.exampleClass 25 | assertEquals(3, intClass.value) 26 | return "OK" 27 | } 28 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/JavaxProviderShouldWorkInMap.kt: -------------------------------------------------------------------------------- 1 | // ENABLE_DAGGER_INTEROP 2 | // Ref https://github.com/ZacSweers/metro/pull/666 3 | import javax.inject.Provider 4 | 5 | @DependencyGraph(AppScope::class) 6 | interface AppGraph { 7 | val urlHandlers: Map> 8 | } 9 | 10 | interface UrlHandler 11 | 12 | @Inject 13 | @ContributesIntoMap(AppScope::class) 14 | @StringKey("post") 15 | class PostUrlHandler : UrlHandler { 16 | fun handle(url: String) { 17 | url.toString() 18 | } 19 | } 20 | 21 | fun box(): String { 22 | val graph = createGraph() 23 | assertNotNull(graph.urlHandlers["post"]?.get()) 24 | return "OK" 25 | } 26 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/diagnostic/dependencygraph/MixedCycleParams.kt: -------------------------------------------------------------------------------- 1 | // RUN_PIPELINE_TILL: FIR2IR 2 | // RENDER_IR_DIAGNOSTICS_FULL_TEXT 3 | 4 | // Regression test for https://github.com/ZacSweers/metro/pull/1121#issuecomment-3374140082 5 | 6 | interface A { 7 | val isReal: Boolean 8 | } 9 | 10 | @Inject class B(a: A) 11 | 12 | @Inject 13 | class RealA(b: Lazy) : A { 14 | override val isReal: Boolean get() = true 15 | } 16 | 17 | @ContributesBinding(Unit::class) 18 | @Inject 19 | class FakeA(b: B, realA: RealA) : A { 20 | override val isReal: Boolean get() = false 21 | } 22 | 23 | @DependencyGraph(Unit::class) 24 | interface CycleGraph { 25 | val a: A 26 | } 27 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/interop/dagger/ZeroArgConstructorInjectionGeneratedByAnvil.kt: -------------------------------------------------------------------------------- 1 | // MODULE: lib 2 | // ENABLE_ANVIL_KSP 3 | // DISABLE_METRO 4 | 5 | // FILE: ExampleClass.kt 6 | package test 7 | 8 | import javax.inject.Inject 9 | 10 | class ExampleClass @Inject constructor() { 11 | // No constructor parameters - anvil-ksp should generate an object Factory 12 | } 13 | 14 | // MODULE: main(lib) 15 | // ENABLE_DAGGER_INTEROP 16 | package test 17 | 18 | @DependencyGraph 19 | interface ExampleGraph { 20 | val exampleClass: ExampleClass 21 | } 22 | 23 | fun box(): String { 24 | val graph = createGraph() 25 | assertNotNull(graph.exampleClass) 26 | return "OK" 27 | } 28 | -------------------------------------------------------------------------------- /samples/circuit-app/src/wasmJsMain/kotlin/dev/zacsweers/metro/sample/circuit/main.kt: -------------------------------------------------------------------------------- 1 | // Copyright (C) 2025 Zac Sweers 2 | // SPDX-License-Identifier: Apache-2.0 3 | package dev.zacsweers.metro.sample.circuit 4 | 5 | import androidx.compose.ui.ExperimentalComposeUiApi 6 | import androidx.compose.ui.window.ComposeViewport 7 | import dev.zacsweers.metro.createGraph 8 | 9 | @OptIn(ExperimentalComposeUiApi::class) 10 | fun main() { 11 | try { 12 | val app = createGraph().app 13 | ComposeViewport { app() } 14 | } catch (ex: Throwable) { 15 | // Annoyingly this is the only way to get a useful stacktrace in the web console 16 | ex.printStackTrace() 17 | throw ex 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /compiler-tests/src/test/data/box/dependencygraph/extensions/ManagedBindingContainerInstancesPlumbDown.kt: -------------------------------------------------------------------------------- 1 | @DependencyGraph(bindingContainers = [Bindings::class]) 2 | interface AppGraph { 3 | fun childGraphFactory(): ChildGraph.Factory 4 | } 5 | 6 | @BindingContainer 7 | class Bindings { 8 | @Provides fun provideInt(): Int = 3 9 | } 10 | 11 | @GraphExtension 12 | interface ChildGraph { 13 | val int: Int 14 | 15 | @GraphExtension.Factory 16 | interface Factory { 17 | fun create(): ChildGraph 18 | } 19 | } 20 | 21 | fun box(): String { 22 | val parent = createGraph() 23 | val child = parent.childGraphFactory().create() 24 | assertEquals(3, child.int) 25 | return "OK" 26 | } 27 | --------------------------------------------------------------------------------