Add missing attribute when setting up DexingWithFullClasspathTransform

When querying for classes to set up the classpath of
DexingWithFullClasspathTransform, we need to check whether ASM
instrumentation is enabled and add the corresponding attributes
accordingly.

Bug: 335449140
Test: New test in DesugarCompileOnlyDependencyTest
Change-Id: Icb11bacf8ed1eb78ef256ccf63c58cdb857a09f9
diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dependency/DexingTransform.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dependency/DexingTransform.kt
index f7859ae..19e7981 100644
--- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dependency/DexingTransform.kt
+++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/dependency/DexingTransform.kt
@@ -384,10 +384,21 @@
 }
 
 /**
- * Dexing transform which uses the full classpath. This classpath consists of all external artifacts
- * ([com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactScope.EXTERNAL])
- * in addition to the input artifact's dependencies provided by Gradle through
- * [org.gradle.api.artifacts.transform.InputArtifactDependencies].
+ * Dexing transform which uses the full classpath (to address bugs such as b/230454566).
+ *
+ * Normally we can obtain this full classpath by querying for CLASSES with scope
+ * [com.android.build.gradle.internal.publishing.AndroidArtifacts.ArtifactScope.ALL]. However, this
+ * would impact build performance, especially for incremental builds where `PROJECT` classes often
+ * change, causing all dexing transforms to rerun.
+ *
+ * To mitigate this performance impact while keeping the build correct, the full classpath will
+ * consist of the following instead:
+ *   1. All external artifacts ([Parameters.externalArtifacts])
+ *   2. The input artifact's dependencies provided by Gradle ([inputArtifactDependencies]) -- This
+ *   will ensure that if some of the input artifact's dependencies have `PROJECT` scope (i.e., they
+ *   are not part of [Parameters.externalArtifacts]), they will still be included in the full
+ *   classpath. (The downside is that if some of the input artifact's dependencies have `EXTERNAL`
+ *   scope, they will overlap with [Parameters.externalArtifacts], but that is fine.)
  */
 @CacheableTransform
 abstract class DexingWithFullClasspathTransform :
@@ -589,7 +600,10 @@
                     creationConfig.variantDependencies.getArtifactCollection(
                         AndroidArtifacts.ConsumedConfigType.RUNTIME_CLASSPATH,
                         AndroidArtifacts.ArtifactScope.EXTERNAL,
-                        inputArtifactType
+                        inputArtifactType,
+                        attributes = AsmClassesTransform.getAttributesForConfig(creationConfig).takeIf {
+                            component.dependenciesClassesAreInstrumented
+                        }
                     ).artifactFiles
                 )
             }
diff --git a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/desugar/DesugarCompileOnlyDependencyTest.kt b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/desugar/DesugarCompileOnlyDependencyTest.kt
index 48245cd..f30148c 100644
--- a/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/desugar/DesugarCompileOnlyDependencyTest.kt
+++ b/build-system/integration-test/application/src/test/java/com/android/build/gradle/integration/desugar/DesugarCompileOnlyDependencyTest.kt
@@ -74,6 +74,44 @@
         }
     }
 
+    /** Regression test for bug 335449140. */
+    @Test
+    fun `desugar library having compileOnly dependency with ASM instrumentation enabled`() {
+        project.buildFile.appendText("\n" +
+            """
+            import com.android.build.api.instrumentation.*
+            import org.objectweb.asm.ClassVisitor
+
+            abstract class AsmClassVisitorFactoryImpl implements AsmClassVisitorFactory<InstrumentationParameters> {
+
+                ClassVisitor createClassVisitor(ClassContext classContext, ClassVisitor nextClassVisitor) {
+                    TODO("Not yet implemented")
+                }
+
+                boolean isInstrumentable(ClassData classData) {
+                    return false
+                }
+            }
+
+            androidComponents {
+                onVariants(selector().all(), {
+                    it.instrumentation.transformClassesWith(AsmClassVisitorFactoryImpl.class, InstrumentationScope.ALL) {}
+                    it.instrumentation.setAsmFramesComputationMode(FramesComputationMode.COPY_FRAMES)
+                })
+            }
+            """.trimIndent()
+        )
+        project.executor()
+            .with(BooleanOption.USE_FULL_CLASSPATH_FOR_DEXING_TRANSFORM, true)
+            .run("assembleDebug")
+        project.getApk(GradleTestProject.ApkType.DEBUG).use { apk ->
+            assertThat(apk)
+                .hasClass(ImplOfInterfaceWithDefaultMethod::class.java)
+                .that()
+                .hasMethod("myDefaultMethod")
+        }
+    }
+
 }
 
 @Suppress("unused") // Used in this test