From f3482d12518a658874867cff3214fdba3b3ce326 Mon Sep 17 00:00:00 2001 From: Bradley Smith Date: Thu, 1 Nov 2018 18:59:21 +0000 Subject: [PATCH] Register KotlinModelBuilder for kotlin-android plugin --- .../kotlin/gradle/model/KotlinProjectIT.kt | 47 ++++++++++++++++++- .../model/builder/KotlinModelBuilder.kt | 31 ++++++++++-- .../kotlin/gradle/plugin/KotlinPlugin.kt | 6 ++- .../gradle/plugin/KotlinPluginWrapper.kt | 2 +- 4 files changed, 78 insertions(+), 8 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/model/KotlinProjectIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/model/KotlinProjectIT.kt index f95f480f59c..cf20163bcb7 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/model/KotlinProjectIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/model/KotlinProjectIT.kt @@ -7,14 +7,23 @@ package org.jetbrains.kotlin.gradle.model import org.jetbrains.kotlin.gradle.BaseGradleIT import org.jetbrains.kotlin.gradle.GradleVersionRequired +import org.jetbrains.kotlin.test.KotlinTestUtils import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertFalse +import kotlin.test.assertNotEquals import kotlin.test.assertTrue class KotlinProjectIT : BaseGradleIT() { override val defaultGradleVersion: GradleVersionRequired - get() = GradleVersionRequired.AtLeast("4.0") + get() = GradleVersionRequired.AtLeast("4.1") + + override fun defaultBuildOptions(): BuildOptions { + return super.defaultBuildOptions().copy( + androidGradlePluginVersion = "3.0.0", + androidHome = KotlinTestUtils.findAndroidSdk() + ) + } @Test fun testKotlinProject() { @@ -25,7 +34,8 @@ class KotlinProjectIT : BaseGradleIT() { "kotlinProject", defaultBuildOptions().kotlinVersion, KotlinProject.ProjectType.PLATFORM_JVM, - "DEFAULT") + "DEFAULT" + ) assertTrue(kotlinProject.expectedByDependencies.isEmpty()) assertEquals(2, kotlinProject.sourceSets.size) @@ -120,6 +130,39 @@ class KotlinProjectIT : BaseGradleIT() { assertEquals(project.projectDir.resolve("libJs/build/resources/test"), testJsSourceSet.resourcesOutputDirectory) } + @Test + fun testAndroidProject() { + val project = Project("AndroidExtensionsProject") + val kotlinProject = project.getModels(KotlinProject::class.java).getModel(":app")!! + + kotlinProject.assertBasics( + "app", + defaultBuildOptions().kotlinVersion, + KotlinProject.ProjectType.PLATFORM_JVM, + "DEFAULT" + ) + + val expectedSourceSetNames = listOf("release", "debug", "releaseUnitTest", "debugUnitTest", "debugAndroidTest") + assertTrue(kotlinProject.expectedByDependencies.isEmpty()) + assertEquals(5, kotlinProject.sourceSets.size) + + fun verifySourceSet(sourceSet: SourceSet) { + // These are unused in Android projects so will be empty. + assertEquals(0, sourceSet.sourceDirectories.size) + assertEquals(0, sourceSet.resourcesDirectories.size) + assertEquals(project.projectDir.resolve("build/tmp/kotlin-classes/${sourceSet.name}"), sourceSet.classesOutputDirectory) + // This value is just a placeholder since this information is obtained from the Android Plugin models. + assertEquals(project.projectDir.resolve("build/tmp/kotlin-classes/${sourceSet.name}"), sourceSet.resourcesOutputDirectory) + assertNotEquals(0, sourceSet.compilerArguments.currentArguments.size) + assertNotEquals(0, sourceSet.compilerArguments.defaultArguments.size) + } + + assertEquals(0, kotlinProject.sourceSets.filter { + verifySourceSet(it) + expectedSourceSetNames.contains(it.name) + }.size) + } + @Test fun testCoroutinesProjectDSL() { val project = Project("coroutinesProjectDSL") diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KotlinModelBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KotlinModelBuilder.kt index 9d0c6c84979..9e29b7a05ac 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KotlinModelBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KotlinModelBuilder.kt @@ -26,7 +26,7 @@ import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile /** * [ToolingModelBuilder] for [KotlinProject] models. - * This model builder is registered for base Kotlin JVM, Kotlin JS and Kotlin Common plugins. + * This model builder is registered for base Kotlin JVM (including Android), Kotlin JS and Kotlin Common plugins. */ class KotlinModelBuilder(private val kotlinPluginVersion: String) : ToolingModelBuilder { @@ -42,7 +42,9 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String) : ToolingModel project.name, kotlinPluginVersion, projectType, - kotlinCompileTasks.mapNotNull { it.createSourceSet(project, projectType) }, + kotlinCompileTasks.mapNotNull { + if (project.isAndroid()) it.createAndroidSourceSet() else it.createSourceSet(project, projectType) + }, getExpectedByDependencies(project), kotlinCompileTasks.first()!!.createExperimentalFeatures() ) @@ -51,9 +53,14 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String) : ToolingModel } companion object { + private fun Project.isAndroid(): Boolean { + return project.plugins.hasPlugin("kotlin-android") + } private fun getProjectType(project: Project): KotlinProject.ProjectType { - return if (project.plugins.hasPlugin("kotlin") || project.plugins.hasPlugin("kotlin-platform-jvm")) { + return if (project.plugins.hasPlugin("kotlin") || project.plugins.hasPlugin("kotlin-platform-jvm") || + project.isAndroid() + ) { KotlinProject.ProjectType.PLATFORM_JVM } else if (project.plugins.hasPlugin("kotlin2js") || project.plugins.hasPlugin("kotlin-platform-js")) { KotlinProject.ProjectType.PLATFORM_JS @@ -91,6 +98,24 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String) : ToolingModel } else null } + /** + * The [SourceSet] returned by this method is not intended to be complete, most of the information here is exposed by the + * Android Gradle plugin and as such is not populated here. The important information here that is required by + * Android Studio are the [CompilerArguments]. + */ + private fun AbstractKotlinCompile<*>.createAndroidSourceSet(): SourceSet { + return SourceSetImpl( + sourceSetName, + if (sourceSetName.contains("test", true)) SourceSet.SourceSetType.TEST else SourceSet.SourceSetType.PRODUCTION, + findFriendSourceSets(), + emptyList(), // Obtained from the Android model + emptyList(), // Obtained from the Android model + destinationDir, + destinationDir, // Obtained from the Android model + createCompilerArguments() + ) + } + private fun AbstractKotlinCompile<*>.findFriendSourceSets(): Collection { val friendSourceSets = ArrayList() friendTask?.sourceSetName?.let { friendSourceSets.add(it) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 4a41b88b583..2c0953a192e 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -559,7 +559,8 @@ internal open class Kotlin2JsPlugin( } internal open class KotlinAndroidPlugin( - private val kotlinPluginVersion: String + private val kotlinPluginVersion: String, + private val registry: ToolingModelBuilderRegistry ) : Plugin { override fun apply(project: Project) { @@ -570,6 +571,7 @@ internal open class KotlinAndroidPlugin( project, androidTarget, tasksProvider, kotlinPluginVersion ) + registry.register(KotlinModelBuilder(kotlinPluginVersion)) } companion object { @@ -733,7 +735,7 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationT kotlinTask.destinationDir = File(project.buildDir, "tmp/kotlin-classes/$variantDataName") kotlinTask.description = "Compiles the $variantDataName kotlin." - // Register the source only after the task is created, because tne task is required for that: + // Register the source only after the task is created, because the task is required for that: compilation.source(defaultSourceSet) configureSources(kotlinTask, variantData, compilation) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt index 3b5e4060980..de7e6ad4805 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt @@ -116,7 +116,7 @@ open class KotlinAndroidPluginWrapper @Inject constructor( protected val registry: ToolingModelBuilderRegistry ) : KotlinBasePluginWrapper(fileResolver) { override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = - KotlinAndroidPlugin(kotlinPluginVersion) + KotlinAndroidPlugin(kotlinPluginVersion, registry) } open class Kotlin2JsPluginWrapper @Inject constructor(