### Report Verification Setup Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/README.md Example of setting up a test file to verify Metro's diagnostic report outputs. The CHECK_REPORTS directive specifies which reports to verify. ```kotlin // CHECK_REPORTS: merging-unmatched-replacements-fir/dev/zacsweers/metro/AppScope @DependencyGraph(AppScope::class) interface AppGraph ``` -------------------------------- ### PathsToRootResult Example Path Source: https://github.com/zacsweers/metro/blob/main/gradle-plugin/src/main/kotlin/dev/zacsweers/metro/gradle/analysis/ANALYSIS.md Illustrates the format of a path to the root, which is a list of node keys starting from the current node and ending at the graph root. ```kotlin Each path is a list from the node to root, e.g., ["MyService", "MyRepository", "AppGraph"]. ``` -------------------------------- ### Multi-module Compilation Example Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/README.md Illustrates setting up multiple modules for compilation using the MODULE directive. This is used for testing multi-module compilation and dependencies. ```kotlin // MODULE: lib @Inject class Example // FILE: main(lib) @DependencyGraph interface AppGraph { val example: Example } ``` -------------------------------- ### Duplicate String Bindings Example Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/diagnostic/rich/DuplicateBindingsRich.rich.ir.diag.txt This example demonstrates a common scenario where two separate @Provides functions are defined to return a String, leading to a DuplicateBinding error. The diagnostic highlights the conflicting definitions. ```kotlin @Provides fun provideString1(): String = "1" @Provides fun provideString2(): String = "2" ``` -------------------------------- ### Multi-file Compilation Example Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/README.md Demonstrates how to define multiple files for compilation using the FILE directive. This is useful for testing multi-file compilation scenarios. ```kotlin // FILE: Example.kt @Inject class Example // FILE: AppGraph.kt @DependencyGraph interface AppGraph { val example: Example } ``` -------------------------------- ### AssistedInject with Named Parameters Example Source: https://github.com/zacsweers/metro/blob/main/docs/designdoc.html This example demonstrates a potential syntax for using @AssistedInject with named parameters for constructor arguments, allowing for clearer distinction between assisted dependencies. ```kotlin class MyClass @AssistedInject constructor( @Assisted("p1") p1: String, @Assisted("p2") p2: Int, ) { @AssistedInject.Factory interface MyFactory } ``` -------------------------------- ### Create and Use Dependency Graph Source: https://github.com/zacsweers/metro/blob/main/README.md Instantiate the dependency graph and access its members. This example shows how to create the graph and retrieve a repository instance. ```kotlin val graph = createGraph() val repository = graph.repository ``` -------------------------------- ### Set Multibinding Example Source: https://github.com/zacsweers/metro/blob/main/docs/bindings.md Demonstrates how to create a set multibinding by providing individual elements and sets of elements annotated with @IntoSet or @ElementsIntoSet. ```kotlin import com.metro.core.DependencyGraph import com.metro.core.Provides import com.metro.core.IntoSet import com.metro.core.ElementsIntoSet @DependencyGraph interface SetMultibinding { // contains a set of [1, 2, 3, 4] val ints: Set @Provides @IntoSet fun provideInt1() = 1 @Provides @IntoSet fun provideInt2() = 2 @Provides @ElementsIntoSet fun provideInts() = setOf(3, 4) } ``` -------------------------------- ### Assisted Injection Setup Source: https://github.com/zacsweers/metro/blob/main/docs/injection-types.md Use @AssistedInject for types with dynamic dependencies, @Assisted for dynamic parameters, and an @AssistedFactory interface to provide these inputs. ```kotlin @AssistedInject class HttpClient( @Assisted val timeout: Duration, val cache: Cache ) { @AssistedFactory fun interface Factory { fun create(timeout: Duration): HttpClient } } ``` -------------------------------- ### Installing aria2 for Faster Downloads Source: https://github.com/zacsweers/metro/blob/main/ide-integration-tests/README.md Instructions for installing aria2 on macOS and Linux to accelerate IDE downloads. ```bash brew install aria2 # macOS apt install aria2 # Linux ``` -------------------------------- ### Dependency Cycle Diagnostic Example Source: https://github.com/zacsweers/metro/blob/main/docs/validation-and-error-reporting.md Shows the structured output for a dependency cycle error, including the cycle path, trace, and suggested fix. ```text ExampleGraph.kt:7:11: error: [Metro/DependencyCycle] Found a dependency cycle while processing test.ExampleGraph cycle: +-> Double -> String -> Int --+ +-----------------------------+ trace (in test.ExampleGraph): Double is injected at test.ExampleGraph.provideInt(…, double) String is injected at test.ExampleGraph.provideDouble(…, string) Int is injected at test.ExampleGraph.provideString(…, int) Double is injected at test.ExampleGraph.provideInt(…, double) ... help: break the cycle by injecting a deferred type at one edge, e.g. `() -> Double` or `Lazy` docs: https://zacsweers.github.io/metro/latest/diagnostics/#dependencycycle ``` -------------------------------- ### Define ExampleGraph Interface Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/fir/aggregation/ContributingGraphExtensions_k23x.fir.txt Defines an example dependency graph interface that extends LoggedInGraph.Factory.MetroContributionToAppScope. ```kotlin @R|dev/zacsweers/metro/DependencyGraph|(scope = (Q|dev/zacsweers/metro/AppScope|)) public abstract interface ExampleGraph : R|kotlin/Any|, R|LoggedInGraph.Factory.MetroContributionToAppScope| { @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroImplMarker|() public final class Impl : R|ExampleGraph| { private constructor(): R|ExampleGraph.Impl| { super() } } public final companion object Companion : R|kotlin/Any| { @R|dev/zacsweers/metro/internal/GraphFactoryInvokeFunctionMarker|() @R|kotlin/jvm/JvmStatic|() @R|kotlin/js/JsStatic|() public final operator fun invoke(): R|ExampleGraph| private constructor(): R|ExampleGraph.Companion| { super() } } } ``` -------------------------------- ### AppGraph Impl constructor delegate setup Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/dependencygraph/MixedUseFactoryAcrossMultipleMultis.kt.txt Sets up the delegate for CommonAppHeadersInterceptor in the AppGraph Impl constructor. ```kotlin DelegateFactory/* companion */.setDelegate(delegateFactory = .#commonAppHeadersInterceptorProvider, delegate = CommonAppHeadersInterceptor.MetroFactory/* companion */.create(additionalHeaders = .(), lazyDelegate = .#commonAppHeadersInterceptorProvider)) ``` -------------------------------- ### Switching Providers in Kotlin Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/dependencygraph/switchingproviders/SwitchingProvidersAcrossExtensions.kt.txt This snippet shows a basic example of switching providers in Kotlin. It's useful for managing different states or configurations within an application. ```kotlin package com.example.app import com.example.lib.ExtensionProvider import com.example.lib.Provider object SwitchingProvidersAcrossExtensions { @JvmStatic fun main(args: Array) { val provider = Provider() val extensionProvider = ExtensionProvider() // Switch to the extension provider provider.switchProvider(extensionProvider) // Perform operations using the extension provider extensionProvider.doSomething() } } ``` -------------------------------- ### Example Usage of Dynamic Graph Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/dependencygraph/dynamic/SimpleDynamicGraph.kt.txt A simple function that demonstrates how to instantiate and use a dynamic dependency graph to retrieve an integer value. ```kotlin fun example() { check(value = EQEQ(arg0 = 5, arg1 = Example.DynamicAppGraphImpl_s15c0(container0 = TestIntProvider(value = 5)).())) } ``` -------------------------------- ### Creating a Singleton Map with MapFactory Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/multibindings/SingletonMapFactory.kt.txt This example demonstrates creating a singleton map of integers to integers using MapFactory.singleton. It specifies the key, and the provider for the value, which is created using ProvideValueMetroFactory. ```kotlin return MapFactory/* companion */.singleton(key = 1, provider = ProvideValueMetroFactory/* companion */.create(instance = .#thisGraphInstance)) ``` -------------------------------- ### Example of Lazy usage Source: https://github.com/zacsweers/metro/blob/main/docs/designdoc.html Illustrates the concise syntax for using Lazy when injecting a dependency. This pattern simplifies the declaration compared to using Provider. ```kotlin class Example(foo: Lazy) ``` -------------------------------- ### Dependency Graph Sharding with Multibindings Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/dependencygraph/sharding/ShardingWithMultibindings.kt.txt Illustrates the construction of a dependency graph with sharding and multibindings. This setup is used for managing services across different shards. ```kotlin internal val setOfAnyProvider: Provider> internal get(): Provider> { return { // BLOCK val tmp0_builder: SetFactory.Builder = SetFactory/* companion */.builder(individualProviderSize = 2, collectionProviderSize = 0) tmp0_builder.addProvider(individualProvider = .#graph.#shard1.#provideService1Provider) tmp0_builder.addProvider(individualProvider = .#provideService2Provider) tmp0_builder.build() } } ``` -------------------------------- ### Run All Startup Benchmarks Source: https://github.com/zacsweers/metro/blob/main/benchmark/README.md Execute all startup benchmarks, including JVM, JVM-R8, and Android. Results are aggregated and saved to a dedicated directory. ```bash # Run all startup benchmarks (includes JVM, JVM-R8, and Android) ./run_startup_benchmarks.sh all # Run only JVM benchmarks ./run_startup_benchmarks.sh jvm # Run only JVM R8-minified benchmarks (Metro only) ./run_startup_benchmarks.sh jvm-r8 # Run multiplatform benchmarks (Metro only, kotlinx-benchmark) ./run_startup_benchmarks.sh multiplatform ./run_startup_benchmarks.sh multiplatform --target jvm # specific target # Run only Android benchmarks (requires device) ./run_startup_benchmarks.sh android # Results are saved to startup-benchmark-results/ ``` -------------------------------- ### Build and Run Android Startup Benchmarks Source: https://github.com/zacsweers/metro/blob/main/benchmark/README.md Build the Android benchmark app and run connected tests on a device or emulator. Results are saved in the specified output directory. ```bash # Build and run benchmarks (requires connected device/emulator) ./gradlew :startup-android:app:assembleBenchmark ./gradlew :startup-android:benchmark:connectedBenchmarkAndroidTest # Results are saved to startup-android/benchmark/build/outputs/connected_android_test_additional_output/ ``` -------------------------------- ### Run Sample Project Tests Source: https://github.com/zacsweers/metro/blob/main/AGENTS.md Execute tests for all sample projects using the Gradle wrapper. Ensure you are in the project root directory. ```bash ./gradlew -p samples check ``` -------------------------------- ### Install aria2 for Faster Downloads Source: https://github.com/zacsweers/metro/blob/main/ide-integration-tests/README.md Install aria2 using Homebrew to enable 16x parallel connections for faster downloads. This can help mitigate slow download issues. ```bash brew install aria2 ``` -------------------------------- ### Run Multiplatform Startup Benchmarks (kotlinx-benchmark) Source: https://github.com/zacsweers/metro/blob/main/benchmark/README.md Executes multiplatform benchmarks using kotlinx-benchmark across various Kotlin targets (JVM, JS, WasmJS, Native). Results are saved in the specified directory. ```bash # Run kotlinx-benchmark for all targets ./gradlew :startup-multiplatform:benchmark # Run for specific targets ./gradlew :startup-multiplatform:jvmBenchmark ./gradlew :startup-multiplatform:jsBenchmark ./gradlew :startup-multiplatform:wasmJsBenchmark ./gradlew :startup-multiplatform:macosArm64Benchmark # or macosX64Benchmark, linuxX64Benchmark # Results are saved to startup-multiplatform/build/reports/benchmarks/ ``` -------------------------------- ### Building a Map of Providers Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/dependencygraph/MapsUseMapBuilderIfNoProvider.kt.txt This example demonstrates constructing a `Map>` where the values are functions (providers) that can supply `Int`s. It uses `buildMap` and references a `Provider` for the map's value. ```kotlin private val mapOfIntToInt2: Map> private get(): Map> { return buildMap>(capacity = 1, builderAction = local fun MutableMap>.() { $receiver.put(key = 3, value = .#provideIntProvider) } ) } ``` -------------------------------- ### Manually Install for Functional Test Source: https://github.com/zacsweers/metro/blob/main/ide-integration-tests/README.md If issues persist with stale Metro artifacts, manually run the :installForFunctionalTest Gradle task. This ensures the necessary components are installed for functional testing. ```bash ../gradlew :installForFunctionalTest ``` -------------------------------- ### Example Graph Interface Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/MultibindingsHaveConsistentOrderAcrossContributedGraph.kt.txt Defines the dependency graph interface that contributes multibindings to the application scope. ```kotlin @DependencyGraph(scope = AppScope::class) interface ExampleGraph : LoggedInGraph.Factory1.MetroContributionToAppScope { @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @ComptimeOnly abstract class BindsMirror { private constructor() /* primary */ { super/*Any*/() /* () */ } @Binds @IntoSet @CallableMetadata(callableName = "", propertyName = "bind", startOffset = 313, endOffset = 337) fun TaskImpl1.bind_property_intoset(): Task { return error(message = "Never called") } @Binds @IntoSet @CallableMetadata(callableName = "", propertyName = "bind", startOffset = 270, endOffset = 294) fun TaskImpl2.bind_property_intoset(): Task { return error(message = "Never called") } } @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) @MetroImplMarker class Impl : ExampleGraph { private val thisGraphInstance: Impl field = @DependencyGraph(scope = Unit::class) private class LoggedInGraphImpl : LoggedInGraph { private val exampleGraphImpl: Impl field = exampleGraphImpl constructor(exampleGraphImpl: Impl) /* primary */ { super/*Any*/() /* () */ } private val setOfTask: Set private get(): Set { return { // BLOCK buildSet(capacity = 4, builderAction = local fun MutableSet.() { $receiver.add(element = .#exampleGraphImpl.provide4()) $receiver.add(element = .#exampleGraphImpl.provide3()) $receiver.add(element = TaskImpl1()) $receiver.add(element = TaskImpl2()) } ) } } override val tasksFromParent: Set override get(): Set { return .() } } private constructor() /* primary */ { super/*Any*/() /* () */ } override fun createLoggedInGraph(): LoggedInGraph { return LoggedInGraphImpl(exampleGraphImpl = ) } private val setOfTask: Set private get(): Set { return { // BLOCK buildSet(capacity = 4, builderAction = local fun MutableSet.() { $receiver.add(element = .#thisGraphInstance.provide4()) $receiver.add(element = .#thisGraphInstance.provide3()) $receiver.add(element = TaskImpl1()) $receiver.add(element = TaskImpl2()) } ) } } override val tasks: Set override get(): Set { return .() } } companion object Companion { private constructor() /* primary */ { super/*Any*/(); /* () */ } @GraphFactoryInvokeFunctionMarker @JvmStatic @JsStatic ``` -------------------------------- ### Define ExampleGraph Interface Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/fir/aggregation/ContributingGraphExtensions_k24x.fir.txt Defines an example graph interface that extends LoggedInGraph.Factory.MetroContributionToAppScope and is annotated with @DependencyGraph. ```kotlin @R|dev/zacsweers/metro/DependencyGraph|(scope = (Q|dev/zacsweers/metro/AppScope|) [evaluated = (Q|dev/zacsweers/metro/AppScope|)]) public abstract interface ExampleGraph : R|kotlin/Any|, R|LoggedInGraph.Factory.MetroContributionToAppScope| { @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroImplMarker|() public final class Impl : R|ExampleGraph| { private constructor(): R|ExampleGraph.Impl| { super() } } public final companion object Companion : R|kotlin/Any| { @R|dev/zacsweers/metro/internal/GraphFactoryInvokeFunctionMarker|() @R|kotlin/jvm/JvmStatic|() @R|kotlin/js/JsStatic|() public final operator fun invoke(): R|ExampleGraph| private constructor(): R|ExampleGraph.Companion| { super() } } } ``` -------------------------------- ### Create a Dependency Graph Factory Instance Source: https://github.com/zacsweers/metro/blob/main/docs/dependency-graphs.md Demonstrates how to create an instance of a dependency graph's factory and then use it to create the graph itself, passing the required input. ```kotlin ```kotlin val messageGraph = createGraphFactory() .create("Hello, world!") ``` ``` -------------------------------- ### Run Circuit App on JVM Source: https://github.com/zacsweers/metro/blob/main/samples/circuit-app/README.md Use this command to run the Circuit sample application on the JVM. ```bash ./gradlew -p samples :circuit-app:jvmRun ``` -------------------------------- ### Pre-downloading IDEs for Faster Test Runs Source: https://github.com/zacsweers/metro/blob/main/ide-integration-tests/README.md Scripts to download IDEs, useful for CI environments to speed up test execution. ```bash # Download all IDEs listed in ide-versions.txt ./download-ides.sh ``` ```bash # Dry-run to see what would be downloaded ./download-ides.sh --dry-run ``` ```bash # Force re-download even if cached ./download-ides.sh --force ``` ```bash # Control parallel downloads (default: 4) ./download-ides.sh --jobs 8 ``` -------------------------------- ### Get Baseline Label Source: https://github.com/zacsweers/metro/blob/main/docs/benchmark_assets/build-benchmark-report.html Retrieves the framework name for the currently selected baseline from the benchmark data. ```javascript function getBaselineLabel() { const result = benchmarkData.benchmarks[0]?.results.find(r => r.key === selectedBaseline); return result?.framework || 'Baseline'; } ``` -------------------------------- ### Build the Benchmark Project Source: https://github.com/zacsweers/metro/blob/main/benchmark/README.md Builds the entire benchmark project using Gradle. This command compiles all generated modules and prepares the project for execution. ```bash ./gradlew build ``` -------------------------------- ### Contribute Test Network Providers Source: https://github.com/zacsweers/metro/blob/main/docs/designdoc.html Example of contributing test network providers that supersede real implementations. ```java @ContributesTo(AppScope::class) interface NetworkProviders { @Provides fun provideHttpClient(): HttpClient } ``` -------------------------------- ### Run Multiplatform Startup Benchmarks with Runner Script Source: https://github.com/zacsweers/metro/blob/main/benchmark/README.md Uses a runner script to execute multiplatform benchmarks for specific targets or all targets. Results are saved in a timestamped directory. ```bash # Run all targets ./run_startup_benchmarks.sh multiplatform # Run specific target ./run_startup_benchmarks.sh multiplatform --target jvm ./run_startup_benchmarks.sh multiplatform --target js ./run_startup_benchmarks.sh multiplatform --target wasmJs ./run_startup_benchmarks.sh multiplatform --target native # Results are saved to startup-benchmark-results/{timestamp}/multiplatform-{target}_metro/ ``` -------------------------------- ### Kotlin Private Constructor for MetroFactory Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/dependencygraph/RefCountingFollowsAliases.kt.txt A private constructor for MetroFactory, used internally for dependency injection setup. ```kotlin @HiddenFromObjC private constructor(baz: Provider) /* primary */ { super/*Any*/() /* () */ } ``` -------------------------------- ### Listing Available Android Studio Versions Source: https://github.com/zacsweers/metro/blob/main/ide-integration-tests/README.md Command to list available Android Studio versions using the helper script. ```bash ./list-android-studio-versions.sh ``` -------------------------------- ### Chart Rendering Initialization Source: https://github.com/zacsweers/metro/blob/main/docs/benchmark_assets/startup-benchmark-report.html Initializes the chart rendering process by getting the canvas context for each benchmark chart. ```javascript const charts = []; function renderChart(benchmark, idx) { const ctx = document.getElementById(`chart-${idx}`).getContext('2d'); const labels = [], data = [], backgroundColors = ``` -------------------------------- ### Get Baseline Framework Label Source: https://github.com/zacsweers/metro/blob/main/docs/benchmark_assets/startup-benchmark-report.html Retrieves the framework name of the currently selected baseline for display purposes. ```javascript function getBaselineLabel() { const result = benchmarkData.benchmarks[0]?.results.find(r => r.key === selectedBaseline); return result?.framework || 'Baseline'; } ``` -------------------------------- ### Generate Project with Legacy Provider Multibindings Source: https://github.com/zacsweers/metro/blob/main/benchmark/README.md Generates the benchmark project using Metro mode, with an option to wrap multibinding accessors in the legacy `Provider>` form. This is specifically for benchmarking `SetFactory`/`MapFactory` behavior against explicit `Provider` types. ```bash kotlin generate-projects.main.kts --mode metro --provider-multibindings ``` -------------------------------- ### Constructor Injection Example Source: https://github.com/zacsweers/metro/blob/main/docs/injection-types.md Annotate a class with a single primary constructor or a specific constructor with @Inject for constructor injection. ```kotlin class ClassInjected class SpecificConstructorInjection(val text: String) { @Inject constructor(value: Int) : this(value.toString()) } ``` -------------------------------- ### Interface with MetroContributionToAppScope Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/fir/contributionProvidersShouldNotGenerateForContributesTo.fir.txt Illustrates an interface `ContributedInterface` that inherits from `MetroContributionToAppScope`. This serves as an example for how Metro handles contribution providers. ```kotlin FILE: contributionProvidersShouldNotGenerateForContributesTo.kt @R|dev/zacsweers/metro/ContributesTo|(scope = (Q|dev/zacsweers/metro/AppScope|)) public abstract interface ContributedInterface : R|kotlin/Any| { @R|kotlin/Deprecated|(message = String(This synthesized declaration should not be used directly), level = Q|kotlin/DeprecationLevel|.R|kotlin/DeprecationLevel.HIDDEN|) @R|dev/zacsweers/metro/internal/MetroContribution|(scope = (Q|dev/zacsweers/metro/AppScope|)) public abstract interface MetroContributionToAppScope : R|ContributedInterface| { } } ``` -------------------------------- ### Define Dagger Component with Metro Graph Dependency Source: https://github.com/zacsweers/metro/blob/main/docs/designdoc.html Example of a Dagger component that depends on a Metro graph, demonstrating interoperability. ```java @DependencyGraph interface MessageGraph { val message: String // ... } // Dagger @Component(dependencies = [MetroGraph::class]) interface DaggerComponent { val message: String @Component.Factory fun interface Factory { fun create(messageGraph: MessageGraph): DaggerComponent } } // kotlin-inject @ComponentAbstract class KotlinInjectComponent( @Component val messageGraph: MessageGraph ) { val message: String } ``` -------------------------------- ### Define Metro Graph with Dagger Component Dependency Source: https://github.com/zacsweers/metro/blob/main/docs/designdoc.html Example of a Metro graph that depends on a Dagger component, showcasing interoperability. ```java @DependencyGraph interface MetroGraph { val message: String @DependencyGraph.Factory fun interface Factory { fun create( daggerComponent: DaggerComponent ): MetroGraph } } @dagger.Component interface DaggerComponent { val message: String @dagger.Component.Factory fun interface Factory { fun create(@Provides message: String): DaggerComponent } } ``` -------------------------------- ### Service17 Factory and Instance Creation Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/dependencygraph/InitsAreChunked.kt.txt Illustrates the factory implementation for Service17, mirroring the pattern used for Service16. This includes methods for creating and instantiating the service, highlighting dependency management. ```kotlin @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) class MetroFactory : Factory { private /* final field */ val s16: Provider = s16 companion object Companion { private constructor() /* primary */ { super/*Any*/() /* () */ } @HiddenFromObjC @JvmStatic @JsStatic fun create(s16: Provider): MetroFactory { return MetroFactory(s16 = s16) } @HiddenFromObjC @JvmStatic @JsStatic fun newInstance(s16: Service16): Service17 { return Service17(s16 = s16) } } @HiddenFromObjC private constructor(s16: Provider) /* primary */ { super/*Any*/() /* () */ } @HiddenFromObjC override operator fun invoke(): Service17 { return MetroFactory/* companion */.newInstance(s16 = .#s16.invoke()) } @SingleIn(scope = AppScope::class) @ComptimeOnly @HiddenFromObjC fun mirrorFunction(s16: Service16): Service17 { return error(message = "Never called") } } constructor(s16: Service16) /* primary */ { super/*Any*/() /* () */ } } ``` -------------------------------- ### Switching Providers for Deferred Class Loading Source: https://github.com/zacsweers/metro/blob/main/docs/dependency-graphs.md Switching providers defer class loading to reduce graph initialization time, analogous to Dagger's `fastInit`. This optimization should be used only after benchmarking shows a meaningful difference. The example shows the generated structure for a graph with switching providers. ```kotlin // The graph @DependencyGraph(AppScope::class) interface AppGraph { @Provides @SingleIn(AppScope::class) fun provideString(): String = "Hello, world!" @Provides @SingleIn(AppScope::class) fun provideInt(string: String): Int = string.length val stringLength: Int } ``` ```kotlin // Generated structure for a graph with switching providers class AppGraph$Impl : AppGraph { private val provider1: Provider DoubleCheck.provider(SwitchingProvider(this, 0)) private val provider2: Provider DoubleCheck.provider(SwitchingProvider(this, 1)) @Provides private class SwitchingProvider(private val graph: Impl, private val id: Int) : Provider { override operator fun invoke(): T { when (id) { 0 -> StringFactory.newInstance(...) as T 1 -> IntFactory.newInstance(graph.provider1()) as T } } } } ``` -------------------------------- ### Graph-Private Binding Example Source: https://github.com/zacsweers/metro/blob/main/docs/dependency-graphs.md Illustrates the use of @GraphPrivate to restrict bindings to the graph they are provided in, preventing them from being exposed or visible to extensions. ```kotlin @DependencyGraph(AppScope::class) interface AppGraph { @GraphPrivate @Provides @SingleIn(AppScope::class) fun provideCoroutineScope(): CoroutineScope = ... // Error — cannot expose a @GraphPrivate binding as an accessor val coroutineScope: CoroutineScope val loggedInGraph: LoggedInGraph } @GraphExtension interface LoggedInGraph { // Error — CoroutineScope is @GraphPrivate in the parent and not visible here val coroutineScope: CoroutineScope } ``` -------------------------------- ### Binding Optional String with @BindsOptionalOf Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/dependencygraph/interop/BindsOptionalOfUsesLazyProviders.kt.txt Binds an optional String dependency. Similar to the Int example, the implementation is an error placeholder. ```kotlin @BindsOptionalOf @CallableMetadata(callableName = "optionalString", propertyName = "", startOffset = 171, endOffset = 199) fun optionalString_opt(): String { return error(message = "Never called") } ``` -------------------------------- ### Pre-cache IDEs for Test Runs Source: https://github.com/zacsweers/metro/blob/main/ide-integration-tests/README.md Use the download-ides.sh script to pre-cache IDEs before test runs. This helps avoid timeouts during test execution, especially on the first run. ```bash ./download-ides.sh ``` -------------------------------- ### AFragment Class Definition Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/multibindings/MultibindingInParentMemberInjectedClass.kt.txt Defines a Fragment with a ViewModelFactory member and its synthesized MembersInjector. This class is part of a dependency injection setup. ```kotlin class AFragment : Fragment { lateinit var viewModelFactory: ViewModelFactory get set @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) class MetroMembersInjector : MembersInjector { private /* final field */ val viewModelFactory: Provider = viewModelFactory companion object Companion { private constructor() /* primary */ { super/*Any*/() /* () */ } @HiddenFromObjC @JvmStatic @JsStatic fun create(viewModelFactory: Provider): MembersInjector { return MetroMembersInjector(viewModelFactory = viewModelFactory) } @JvmStatic @JsStatic fun injectViewModelFactory(@Assisted instance: AFragment, viewModelFactory: ViewModelFactory) { return instance.#viewModelFactory = viewModelFactory } } private constructor(viewModelFactory: Provider) /* primary */ { super/*Any*/() /* () */ } override fun injectMembers(instance: AFragment) { MetroMembersInjector/* companion */.injectViewModelFactory(instance = instance, viewModelFactory = .#viewModelFactory.invoke()) } } constructor() /* primary */ { super/*Fragment*/() /* () */ } } ``` -------------------------------- ### Install Metro Gradle Plugin Source: https://github.com/zacsweers/metro/blob/main/docs/quickstart.md Apply the Metro Gradle plugin to your project. This adds runtime dependencies and configures compiler plugins. ```kotlin plugins { kotlin("multiplatform") // or jvm, android, etc id("dev.zacsweers.metro") version "1.2.1" } ``` -------------------------------- ### Run All Modes Including Baselines Source: https://github.com/zacsweers/metro/blob/main/benchmark/README.md Runs all benchmark modes along with baseline benchmarks (vanilla + metro-noop) using the `run_benchmarks.sh` script. This includes pure Kotlin and Metro plugin overhead tests. ```bash ./run_benchmarks.sh all --include-baselines ``` -------------------------------- ### ProvideInt2MetroFactory Creation Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/multibindings/MultibindingSourcesGetRefcountedViaFactoryPath.kt.txt Demonstrates the static factory method `create` for `ProvideInt2MetroFactory`, used to instantiate the factory with its dependencies. ```kotlin @HiddenFromObjC @JvmStatic @JsStatic fun create(instance: TestGraph, base: Provider): ProvideInt2MetroFactory { return ProvideInt2MetroFactory(instance = instance, base = base) } ``` -------------------------------- ### Implement MetroIrContributionExtension Source: https://github.com/zacsweers/metro/blob/main/compiler/API.md Example implementation of MetroIrContributionExtension to contribute binding containers and supertypes. This is useful when interop metadata is only available from the compile classpath. ```kotlin class MyIrContributionExtension( private val pluginContext: IrPluginContext, ) : MetroIrContributionExtension { override fun contributeBindingContainers( scope: ClassId, callingDeclaration: IrDeclaration, ): List { return findModuleClassIds(scope).mapNotNull { classId -> pluginContext.referenceClass(classId)?.owner } } override fun contributeSupertypes( scope: ClassId, callingDeclaration: IrDeclaration, ): List { return findEntryPointClassIds(scope).mapNotNull { classId -> pluginContext.referenceClass(classId)?.owner?.defaultType } } class Factory : MetroIrContributionExtension.Factory { override fun create( pluginContext: IrPluginContext, options: MetroOptions, ): MetroIrContributionExtension = MyIrContributionExtension(pluginContext) } } ``` -------------------------------- ### Example: Frontend Diagnostic Test Directive Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/README.md Use this directive for frontend-only diagnostic tests. These tests are fast as they only execute the frontend of the compiler. ```kotlin // RENDER_DIAGNOSTICS_FULL_TEXT ``` -------------------------------- ### Adding a New IntelliJ IDEA Version to Test Source: https://github.com/zacsweers/metro/blob/main/ide-integration-tests/README.md Steps to add a new IntelliJ IDEA version, including updating ide-versions.txt and pre-downloading. ```bash IU:2025.3.2 ``` ```bash ./download-ides.sh ``` ```bash ./gradlew test ``` -------------------------------- ### Run All Benchmark Modes Source: https://github.com/zacsweers/metro/blob/main/benchmark/README.md Executes all benchmark modes (metro, dagger-ksp, dagger-kapt, kotlin-inject-anvil, koin) on the current branch using the `run_benchmarks.sh` script. This provides a comprehensive performance overview. ```bash ./run_benchmarks.sh all ``` -------------------------------- ### Provide Bar Binding Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/aggregation/ContributionProviders_ScopedMultipleBindings.kt.txt A @Provides function that binds an instance named 'metro_scoped_Impl' to the Bar type. This is part of the dependency injection setup. ```kotlin @Provides fun provideImplAsBar(@Named(name = "metro_scoped_Impl") instance: Any?): Bar { return instance /*as Bar */ } ``` -------------------------------- ### Adding a New Android Studio Version to Test Source: https://github.com/zacsweers/metro/blob/main/ide-integration-tests/README.md Steps to add a new Android Studio version, including updating ide-versions.txt and pre-downloading. ```bash AS:2025.2.3.9 ``` ```bash AS:2025.3.1.6:android-studio-panda1-rc1 ``` ```bash ./download-ides.sh ``` ```bash ./gradlew test ``` -------------------------------- ### TestGraph Impl init() Method Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/dependencygraph/CreatorParamsDoNotGetChunked.kt.txt Initializes various service providers using `DoubleCheck.provider`. Each provider is delegated to a factory method that creates the respective service, often depending on previously created providers. ```kotlin private fun init() { .#service1Provider = DoubleCheck/* companion */.provider, Service1>(delegate = Service1.MetroFactory/* companion */.create(providedExample = InstanceFactory/* companion */.invoke(value = .#providedExampleInstance))) .#service2Provider = DoubleCheck/* companion */.provider, Service2>(delegate = Service2.MetroFactory/* companion */.create(s1 = .#service1Provider)) .#service3Provider = DoubleCheck/* companion */.provider, Service3>(delegate = Service3.MetroFactory/* companion */.create(s2 = .#service2Provider)) .#service4Provider = DoubleCheck/* companion */.provider, Service4>(delegate = Service4.MetroFactory/* companion */.create(s3 = .#service3Provider)) .#service5Provider = DoubleCheck/* companion */.provider, Service5>(delegate = Service5.MetroFactory/* companion */.create(s4 = .#service4Provider)) .#service6Provider = DoubleCheck/* companion */.provider, Service6>(delegate = Service6.MetroFactory/* companion */.create(s5 = .#service5Provider)) .#service7Provider = DoubleCheck/* companion */.provider, Service7>(delegate = Service7.MetroFactory/* companion */.create(s6 = .#service6Provider)) .#service8Provider = DoubleCheck/* companion */.provider, Service8>(delegate = Service8.MetroFactory/* companion */.create(s7 = .#service7Provider)) ``` -------------------------------- ### IDE Versions Configuration Format Source: https://github.com/zacsweers/metro/blob/main/ide-integration-tests/README.md Defines the format for entries in the ide-versions.txt file, specifying product, version, and optional filename prefix. ```text :[:] ``` -------------------------------- ### Run New Compiler Tests Source: https://github.com/zacsweers/metro/blob/main/AGENTS.md Execute new compiler tests using the Gradle wrapper. Ensure you are in the project root directory. ```bash ./gradlew :compiler-tests:test ``` -------------------------------- ### Run Performance Benchmarks Source: https://github.com/zacsweers/metro/blob/main/AGENTS.md Navigate to the benchmark directory and execute the benchmark script for the Metro project. Ensure you are in the project root directory before changing directories. ```bash cd benchmark && ./run_benchmarks.sh metro ``` -------------------------------- ### Target Class with Multibindings Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/multibindings/InjectorFunctionsDoNotTriggerProviderGets.kt.txt Defines a Target class that holds a map of strings, managed by a MembersInjector. This is a core component for dependency injection setup. ```kotlin class Target { lateinit var strings: Map> get set @Deprecated(message = "This synthesized declaration should not be used directly", level = DeprecationLevel.HIDDEN) class MetroMembersInjector : MembersInjector { private /* final field */ val strings: Provider>> = strings companion object Companion { private constructor() /* primary */ { super/*Any*/() /* () */ } @HiddenFromObjC @JvmStatic @JsStatic fun create(strings: Provider>>): MembersInjector { return MetroMembersInjector(strings = strings) } @JvmStatic @JsStatic fun injectStrings(@Assisted instance: Target, strings: Map>) { return instance.#strings = strings } } private constructor(strings: Provider>>) /* primary */ { super/*Any*/() /* () */ } override fun injectMembers(instance: Target) { MetroMembersInjector/* companion */.injectStrings(instance = instance, strings = .#strings.invoke()) } } constructor() /* primary */ { super/*Any*/() /* () */ } } ``` -------------------------------- ### Example of lazy(foo) usage with Provider Source: https://github.com/zacsweers/metro/blob/main/docs/designdoc.html Shows an alternative implementation using a Provider and Kotlin's built-in lazy delegate. This is a more verbose approach compared to directly using Lazy. ```kotlin class Example(foo: Provider) { private val foo by lazy(foo) } ``` -------------------------------- ### ProvideInt1MetroFactory Invocation Source: https://github.com/zacsweers/metro/blob/main/compiler-tests/src/test/data/dump/ir/multibindings/MultibindingSourcesGetRefcountedViaFactoryPath.kt.txt Illustrates the `invoke` method of `ProvideInt1MetroFactory`, which calls the companion object's `provideInt1` method to get the actual `Int` value. ```kotlin @HiddenFromObjC override operator fun invoke(): Int { return ProvideInt1MetroFactory/* companion */.provideInt1(instance = .#instance, base = .#base.invoke()) } ``` -------------------------------- ### Run JMH JVM Startup Benchmarks Source: https://github.com/zacsweers/metro/blob/main/benchmark/README.md Executes the Java Microbenchmark Harness (JMH) benchmarks for JVM startup performance. Results are saved in the specified directory. ```bash # Run JMH benchmarks ./gradlew :startup-jvm:jmh # Results are saved to startup-jvm/build/results/jmh/ ```