[Gradle] Implement KotlinJvmWithJavaAndroidCompatibilityChecker to fail when 'withJava' is used together with AGP

As both (AGP and 'withJava') are using project global names like
'main' and 'test' which will lead to clashes  (e.g. configuration names
are the same for both)

^KT-59595 Verification Pending
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt
index 148d388..8acc7f0 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt
@@ -113,7 +113,7 @@
             KotlinSourceSetTreeDependsOnMismatchChecker,
             PlatformSourceSetConventionsChecker,
             AndroidMainSourceSetConventionsChecker,
-            IosSourceSetConventionChecker
+            IosSourceSetConventionChecker,
         )
     }
 }
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt
index 5ccf922..bddfb98 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt
@@ -530,6 +530,22 @@
             """.trimIndent()
         )
     }
+
+    object JvmWithJavaIsIncompatibleWithAndroid : ToolingDiagnosticFactory(FATAL) {
+        operator fun invoke(androidPluginId: String, trace: Throwable?) = build(
+            """
+                'withJava()' is not compatible with Android Plugins
+                Incompatible Android Plugin applied: '$androidPluginId'
+                
+                  kotlin {
+                      jvm {
+                          withJava() /* <- cannot be used when the Android Plugin is present */
+                      }
+                  }
+            """.trimIndent(),
+            throwable = trace
+        )
+    }
 }
 
 private fun String.indentLines(nSpaces: Int = 4, skipFirstLine: Boolean = true): String {
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnosticsCollector.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnosticsCollector.kt
index f48c4d8..4e728f0 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnosticsCollector.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnosticsCollector.kt
@@ -68,12 +68,15 @@
             return
         }
 
-        if (diagnostic.severity == ToolingDiagnostic.Severity.FATAL) {
-            throw InvalidUserCodeException(diagnostic.message)
-        }
         rawDiagnosticsFromProject.compute(project.path) { _, previousListIfAny ->
             previousListIfAny?.apply { add(diagnostic) } ?: mutableListOf(diagnostic)
         }
+
+        if (diagnostic.severity == ToolingDiagnostic.Severity.FATAL) {
+            if (diagnostic.throwable != null)
+                throw InvalidUserCodeException(diagnostic.message, diagnostic.throwable)
+            else throw InvalidUserCodeException(diagnostic.message)
+        }
     }
 }
 
diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTarget.kt
index 96bcbab..bc3802f 100644
--- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTarget.kt
+++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTarget.kt
@@ -10,9 +10,7 @@
 import org.gradle.api.Project
 import org.gradle.api.file.ConfigurableFileCollection
 import org.gradle.api.file.DuplicatesStrategy
-import org.gradle.api.internal.tasks.JvmConstants
 import org.gradle.api.plugins.JavaBasePlugin
-import org.gradle.api.plugins.JavaPlugin
 import org.gradle.api.tasks.SourceSet
 import org.gradle.api.tasks.compile.AbstractCompile
 import org.gradle.language.jvm.tasks.ProcessResources
@@ -21,6 +19,8 @@
 import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
 import org.jetbrains.kotlin.gradle.plugin.*
 import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinaliseDsl
+import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
+import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnostic
 import org.jetbrains.kotlin.gradle.plugin.internal.JavaSourceSetsAccessor
 import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
 import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
@@ -32,6 +32,7 @@
 import org.jetbrains.kotlin.gradle.tasks.withType
 import org.jetbrains.kotlin.gradle.utils.Future
 import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
+import org.jetbrains.kotlin.gradle.utils.findAppliedAndroidPluginIdOrNull
 import org.jetbrains.kotlin.gradle.utils.future
 import org.jetbrains.kotlin.utils.addToStdlib.cast
 import java.util.concurrent.Callable
@@ -92,6 +93,7 @@
     var withJavaEnabled = false
         private set
 
+
     @Suppress("unused") // user DSL
     fun withJava() {
         if (withJavaEnabled)
@@ -105,6 +107,25 @@
                 )
             }
 
+
+        /**
+         * Reports diagnostic in the case of
+         * ```kotlin
+         * kotlin {
+         *     jvm().withJava()
+         * }
+         * ```
+         *
+         * is used together with the Android Gradle Plugin.
+         * This case is incompatible so far, as the 'withJava' implementation is still using 'global' namespaces
+         * (like main/test, etc), which will clash with the global names used by AGP (also occupying main, test, etc).
+         */
+        val trace = Throwable()
+        project.launchInStage(AfterFinaliseDsl) check@{
+            val androidPluginId = project.findAppliedAndroidPluginIdOrNull() ?: return@check
+            project.reportDiagnostic(KotlinToolingDiagnostics.JvmWithJavaIsIncompatibleWithAndroid(androidPluginId, trace))
+        }
+
         withJavaEnabled = true
 
         project.plugins.apply(JavaBasePlugin::class.java)
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/diagnosticsTests/JvmWithJavaIsIncompatibleWithAndroidDiagnosticTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/diagnosticsTests/JvmWithJavaIsIncompatibleWithAndroidDiagnosticTest.kt
new file mode 100644
index 0000000..5abce9e
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/diagnosticsTests/JvmWithJavaIsIncompatibleWithAndroidDiagnosticTest.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+@file:Suppress("FunctionName")
+
+package org.jetbrains.kotlin.gradle.unitTests.diagnosticsTests
+
+import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
+import org.jetbrains.kotlin.gradle.util.androidApplication
+import org.jetbrains.kotlin.gradle.util.androidLibrary
+import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
+import org.jetbrains.kotlin.gradle.util.checkDiagnostics
+import kotlin.test.Test
+import kotlin.test.assertFails
+
+class JvmWithJavaIsIncompatibleWithAndroidDiagnosticTest {
+
+    @Test
+    fun `test - withJava and android library`() {
+        val project = buildProjectWithMPP()
+        project.androidLibrary { compileSdk = 33 }
+        project.multiplatformExtension.jvm().withJava()
+        project.multiplatformExtension.androidTarget()
+
+        assertFails { project.evaluate() }
+        project.checkDiagnostics("JvmWithJavaIsIncompatibleWithAndroid-withJava-withAndroidLibrary")
+    }
+
+    @Test
+    fun `test - withJava and android application`() {
+        val project = buildProjectWithMPP()
+        project.androidApplication { compileSdk = 33 }
+        project.multiplatformExtension.jvm().withJava()
+        project.multiplatformExtension.androidTarget()
+        assertFails { project.evaluate() }
+
+        project.checkDiagnostics("JvmWithJavaIsIncompatibleWithAndroid-withJava-withAndroidApplication")
+    }
+
+    @Test
+    fun `test - withJava - without android plugin`() {
+        val project = buildProjectWithMPP()
+        project.androidLibrary { compileSdk = 33 }
+        project.multiplatformExtension.jvm()
+        project.multiplatformExtension.androidTarget()
+        project.evaluate()
+
+        project.checkDiagnostics("JvmWithJavaIsIncompatibleWithAndroid-withJava-withoutAndroidPlugin")
+    }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/expectedDiagnostics/JvmWithJavaIsIncompatibleWithAndroid-withJava-withAndroidApplication.txt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/expectedDiagnostics/JvmWithJavaIsIncompatibleWithAndroid-withJava-withAndroidApplication.txt
new file mode 100644
index 0000000..aa8726f
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/expectedDiagnostics/JvmWithJavaIsIncompatibleWithAndroid-withJava-withAndroidApplication.txt
@@ -0,0 +1,8 @@
+[JvmWithJavaIsIncompatibleWithAndroid | FATAL] 'withJava()' is not compatible with Android Plugins
+Incompatible Android Plugin applied: 'com.android.application'
+
+  kotlin {
+      jvm {
+          withJava() /* <- cannot be used when the Android Plugin is present */
+      }
+  }
diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/expectedDiagnostics/JvmWithJavaIsIncompatibleWithAndroid-withJava-withAndroidLibrary.txt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/expectedDiagnostics/JvmWithJavaIsIncompatibleWithAndroid-withJava-withAndroidLibrary.txt
new file mode 100644
index 0000000..0c2ae72
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/resources/expectedDiagnostics/JvmWithJavaIsIncompatibleWithAndroid-withJava-withAndroidLibrary.txt
@@ -0,0 +1,8 @@
+[JvmWithJavaIsIncompatibleWithAndroid | FATAL] 'withJava()' is not compatible with Android Plugins
+Incompatible Android Plugin applied: 'com.android.library'
+
+  kotlin {
+      jvm {
+          withJava() /* <- cannot be used when the Android Plugin is present */
+      }
+  }