diff --git a/libraries/examples/kotlin-gradle-subplugin-example/src/main/kotlin/example/ExampleSubplugin.kt b/libraries/examples/kotlin-gradle-subplugin-example/src/main/kotlin/example/ExampleSubplugin.kt index 742f93ef0b3..2c555ad2775 100644 --- a/libraries/examples/kotlin-gradle-subplugin-example/src/main/kotlin/example/ExampleSubplugin.kt +++ b/libraries/examples/kotlin-gradle-subplugin-example/src/main/kotlin/example/ExampleSubplugin.kt @@ -33,6 +33,7 @@ class ExampleSubplugin : KotlinGradleSubplugin { kotlinCompile: AbstractCompile, javaCompile: AbstractCompile, variantData: Any?, + androidProjectHandler: Any?, javaSourceSet: SourceSet? ): List { println("ExampleSubplugin loaded") diff --git a/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt b/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt index f216feb91a6..03375c2a011 100644 --- a/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt +++ b/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt @@ -79,6 +79,7 @@ class AllOpenKotlinGradleSubplugin : KotlinGradleSubplugin { kotlinCompile: AbstractCompile, javaCompile: AbstractCompile, variantData: Any?, + androidProjectHandler: Any?, javaSourceSet: SourceSet? ): List { if (!AllOpenGradleSubplugin.isEnabled(project)) return emptyList() diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt index bab262875c1..f0894b98132 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt @@ -22,7 +22,7 @@ import org.gradle.api.tasks.compile.AbstractCompile class SubpluginOption(val key: String, val value: String) -interface KotlinGradleSubplugin { +interface KotlinGradleSubplugin { fun isApplicable(project: Project, task: KotlinCompile): Boolean fun apply( @@ -30,6 +30,7 @@ interface KotlinGradleSubplugin { kotlinCompile: KotlinCompile, javaCompile: AbstractCompile, variantData: Any?, + androidProjectHandler: Any?, javaSourceSet: SourceSet? ): List diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt index 35a5ea2f2b1..a545f70e27b 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt @@ -210,6 +210,16 @@ fun getSomething() = 10 } } + @Test + fun testAndroidExtensionsManyVariants() { + val project = Project("AndroidExtensionsManyVariants", gradleVersion) + val options = defaultBuildOptions().copy(incremental = false) + + project.build("assemble", options = options) { + assertSuccessful() + } + } + @Test fun testAndroidKaptChangingDependencies() { val project = Project("AndroidKaptChangingDependencies", gradleVersion) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/build.gradle new file mode 100644 index 00000000000..e26f3013ced --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 23 + buildToolsVersion "25.0.2" + defaultConfig { + applicationId "org.example.manyvariants" + minSdkVersion 15 + targetSdkVersion 23 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + } + } + + flavorDimensions "color" + + productFlavors { + demo { + dimension "color" + applicationIdSuffix ".demo" + versionNameSuffix "-demo" + } + full { + dimension "color" + applicationIdSuffix ".full" + versionNameSuffix "-full" + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/debug/java/debug.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/debug/java/debug.kt new file mode 100644 index 00000000000..b0e6855ab3a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/debug/java/debug.kt @@ -0,0 +1,10 @@ +package org.example.manyvariants + +import android.app.Activity +import kotlinx.android.synthetic.debug.activity_debug.* +import kotlinx.android.synthetic.main.activity_main.* + +fun Activity.debug() { + viewMain + viewDebug +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/debug/res/layout/activity_debug.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/debug/res/layout/activity_debug.xml new file mode 100644 index 00000000000..bcac5c6d528 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/debug/res/layout/activity_debug.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demo/java/demo.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demo/java/demo.kt new file mode 100644 index 00000000000..a60cb42d525 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demo/java/demo.kt @@ -0,0 +1,10 @@ +package org.example.manyvariants + +import android.app.Activity +import kotlinx.android.synthetic.demo.activity_demo.* +import kotlinx.android.synthetic.main.activity_main.* + +fun Activity.demo() { + viewMain + viewDemo +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demo/res/layout/activity_demo.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demo/res/layout/activity_demo.xml new file mode 100644 index 00000000000..e385430bc36 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demo/res/layout/activity_demo.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demoDebug/java/demoDebug.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demoDebug/java/demoDebug.kt new file mode 100644 index 00000000000..1d075e7fb96 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demoDebug/java/demoDebug.kt @@ -0,0 +1,14 @@ +package org.example.manyvariants + +import android.app.Activity +import kotlinx.android.synthetic.debug.activity_debug.* +import kotlinx.android.synthetic.demo.activity_demo.* +import kotlinx.android.synthetic.demoDebug.activity_demo_debug.* +import kotlinx.android.synthetic.main.activity_main.* + +fun Activity.demoDebug() { + viewMain + viewDemo + viewDebug + viewDemoDebug +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demoDebug/res/layout/activity_demo_debug.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demoDebug/res/layout/activity_demo_debug.xml new file mode 100644 index 00000000000..4de6c56b593 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/demoDebug/res/layout/activity_demo_debug.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/full/java/full.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/full/java/full.kt new file mode 100644 index 00000000000..a3417c79745 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/full/java/full.kt @@ -0,0 +1,10 @@ +package org.example.manyvariants + +import android.app.Activity +import kotlinx.android.synthetic.full.activity_full.* +import kotlinx.android.synthetic.main.activity_main.* + +fun Activity.full() { + viewMain + viewFull +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/full/res/layout/activity_full.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/full/res/layout/activity_full.xml new file mode 100644 index 00000000000..ecb3053087d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/full/res/layout/activity_full.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/fullRelease/java/fullRelease.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/fullRelease/java/fullRelease.kt new file mode 100644 index 00000000000..09bf11d1f7d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/fullRelease/java/fullRelease.kt @@ -0,0 +1,14 @@ +package org.example.manyvariants + +import android.app.Activity +import kotlinx.android.synthetic.full.activity_full.* +import kotlinx.android.synthetic.fullRelease.activity_full_release.* +import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.android.synthetic.release.activity_release.* + +fun Activity.fullRelease() { + viewMain + viewFull + viewRelease + viewFullRelease +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/fullRelease/res/layout/activity_full_release.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/fullRelease/res/layout/activity_full_release.xml new file mode 100644 index 00000000000..c00bad64db4 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/fullRelease/res/layout/activity_full_release.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/main/AndroidManifest.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..e9c317347f1 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/main/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/main/java/MainActivity.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/main/java/MainActivity.kt new file mode 100644 index 00000000000..aab20643e48 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/main/java/MainActivity.kt @@ -0,0 +1,13 @@ +package org.example.manyvariants + +import android.app.Activity +import android.os.Bundle +import kotlinx.android.synthetic.main.activity_main.* + +class MainActivity : Activity() { + override fun onCreate(savedInstanceState: Bundle) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_main) + viewMain + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/main/res/layout/activity_main.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000000..9174f1b66f5 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/release/java/release.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/release/java/release.kt new file mode 100644 index 00000000000..890a9015f42 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/release/java/release.kt @@ -0,0 +1,10 @@ +package org.example.manyvariants + +import android.app.Activity +import kotlinx.android.synthetic.release.activity_release.* +import kotlinx.android.synthetic.main.activity_main.* + +fun Activity.release() { + viewMain + viewRelease +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/release/res/layout/activity_release.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/release/res/layout/activity_release.xml new file mode 100644 index 00000000000..5e331cc6ee2 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/app/src/release/res/layout/activity_release.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/build.gradle new file mode 100644 index 00000000000..85de90425dd --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/build.gradle @@ -0,0 +1,23 @@ +buildscript { + repositories { + mavenLocal() + jcenter() + maven { url 'https://maven.google.com' } + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "com.android.tools.build:gradle:$android_tools_version" + } +} + +allprojects { + repositories { + mavenLocal() + jcenter() + maven { url 'https://maven.google.com' } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/gradle.properties b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/gradle.properties new file mode 100644 index 00000000000..5fcc74643cf --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-ea -XX:MaxPermSize=512m \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/settings.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/settings.gradle new file mode 100644 index 00000000000..e7b4def49cb --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/AndroidExtensionsManyVariants/settings.gradle @@ -0,0 +1 @@ +include ':app' diff --git a/libraries/tools/kotlin-gradle-plugin/src/agp25/kotlin/org/jetbrains/kotlin/gradle/plugin/android/Android25ProjectHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/agp25/kotlin/org/jetbrains/kotlin/gradle/plugin/android/Android25ProjectHandler.kt index 4f5557cb5b9..f7e4d793808 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/agp25/kotlin/org/jetbrains/kotlin/gradle/plugin/android/Android25ProjectHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/agp25/kotlin/org/jetbrains/kotlin/gradle/plugin/android/Android25ProjectHandler.kt @@ -2,7 +2,9 @@ package org.jetbrains.kotlin.gradle.plugin import com.android.build.gradle.* import com.android.build.gradle.api.* +import com.android.build.gradle.tasks.MergeResources import com.android.builder.model.SourceProvider +import com.android.ide.common.res2.ResourceSet import org.gradle.api.Project import org.gradle.api.file.FileCollection import org.gradle.api.tasks.compile.AbstractCompile @@ -117,6 +119,10 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools // to some degree -- the dependent projects will rebuild non-incrementally when a library project changes } + override fun getResDirectories(variantData: BaseVariant): List { + return variantData.mergeResources?.computeResourceSetList0()?.flatMap { it.sourceFiles } ?: emptyList() + } + private inner class KaptVariant(variantData: BaseVariant) : KaptVariantData(variantData) { override val name: String = getVariantName(variantData) override val sourceProviders: Iterable = getSourceProviders(variantData) @@ -137,6 +143,22 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools } } + //TODO once the Android plugin reaches its 3.0.0 release, consider compiling against it (remove the reflective call) + //TODO this is a private API for now + private fun MergeResources.computeResourceSetList0(): List? { + val computeResourceSetListMethod = MergeResources::class.java.declaredMethods + .firstOrNull { it.name == "computeResourceSetList" && it.parameterCount == 0 } ?: return null + + val oldIsAccessible = computeResourceSetListMethod.isAccessible + try { + computeResourceSetListMethod.isAccessible = true + @Suppress("UNCHECKED_CAST") + return computeResourceSetListMethod.invoke(this) as? List + } finally { + computeResourceSetListMethod.isAccessible = oldIsAccessible + } + } + //TODO once the Android plugin reaches its 3.0.0 release, consider compiling against it (remove the reflective call) private val BaseVariant.dataBindingDependencyArtifactsIfSupported: FileCollection? get() = ReflectionUtil.findMethod( diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt index c89997c7f84..2fd96d9a496 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt @@ -18,6 +18,10 @@ package org.jetbrains.kotlin.gradle.internal import com.android.build.gradle.BaseExtension import com.android.build.gradle.api.AndroidSourceSet +import com.android.build.gradle.api.BaseVariant +import com.android.build.gradle.api.TestVariant +import com.android.build.gradle.internal.variant.BaseVariantData +import com.android.build.gradle.internal.variant.TestVariantData import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.UnknownDomainObjectException @@ -25,7 +29,6 @@ import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin import org.jetbrains.kotlin.gradle.plugin.SubpluginOption -import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.w3c.dom.Document import java.io.File @@ -54,38 +57,96 @@ class AndroidSubplugin : KotlinGradleSubplugin { project: Project, kotlinCompile: KotlinCompile, javaCompile: AbstractCompile, - variantData: Any?, + variantData: Any?, + androidProjectHandler: Any?, javaSourceSet: SourceSet? ): List { - val androidExtension = project.extensions.getByName("android") as? BaseExtension ?: return emptyList() - val sourceSets = androidExtension.sourceSets + @Suppress("UNCHECKED_CAST") + androidProjectHandler as? AbstractAndroidProjectHandler ?: return emptyList() + val androidExtension = project.extensions.getByName("android") as? BaseExtension ?: return emptyList() val pluginOptions = arrayListOf() - val mainSourceSet = sourceSets.getByName("main") - val manifestFile = mainSourceSet.manifest.srcFile - val applicationPackage = getApplicationPackageFromManifest(manifestFile) ?: run { - project.logger.warn( - "Application package name is not present in the manifest file (${manifestFile.absolutePath})") - "" - } - pluginOptions += SubpluginOption("package", applicationPackage) + val mainSourceSet = androidExtension.sourceSets.getByName("main") + pluginOptions += SubpluginOption("package", getApplicationPackage(project, mainSourceSet)) - fun addVariant(sourceSet: AndroidSourceSet) { - pluginOptions += SubpluginOption("variant", sourceSet.name + ';' + - sourceSet.res.srcDirs.joinToString(";") { it.absolutePath }) + fun addVariant(name: String, resDirectories: List) { + pluginOptions += SubpluginOption("variant", buildString { + append(name) + append(';') + resDirectories.joinTo(this, separator = ";") { it.canonicalPath } + }) } - addVariant(mainSourceSet) + fun addSourceSetAsVariant(name: String) { + val sourceSet = androidExtension.sourceSets.findByName(name) ?: return + val srcDirs = sourceSet.res.srcDirs.toList() + if (srcDirs.isNotEmpty()) { + addVariant(sourceSet.name, srcDirs) + } + } - val flavorSourceSets = AndroidGradleWrapper.getProductFlavorsSourceSets(androidExtension).filterNotNull() - for (sourceSet in flavorSourceSets) { - addVariant(sourceSet) + val resDirectoriesForAllVariants = mutableListOf>() + + androidProjectHandler.forEachVariant(project) { variant -> + if (androidProjectHandler.getTestedVariantData(variant) != null) return@forEachVariant + resDirectoriesForAllVariants += androidProjectHandler.getResDirectories(variant) + } + + val commonResDirectories = getCommonResDirectories(resDirectoriesForAllVariants) + + addVariant("main", commonResDirectories.toList()) + + getVariantComponentNames(variantData)?.let { (variantName, flavorName, buildTypeName) -> + addSourceSetAsVariant(buildTypeName) + + if (flavorName.isNotEmpty()) { + addSourceSetAsVariant(flavorName) + } + + addSourceSetAsVariant(variantName) } return pluginOptions } + // Android25ProjectHandler.KaptVariant actually contains BaseVariant, not BaseVariantData + private fun getVariantComponentNames(flavorData: Any?): VariantComponentNames? = when(flavorData) { + is KaptVariantData<*> -> getVariantComponentNames(flavorData.variantData) + is TestVariantData -> getVariantComponentNames(flavorData.testedVariantData) + is TestVariant -> getVariantComponentNames(flavorData.testedVariant) + is BaseVariant -> VariantComponentNames(flavorData.name, flavorData.flavorName, flavorData.buildType.name) + is BaseVariantData<*> -> VariantComponentNames(flavorData.name, flavorData.variantConfiguration.flavorName, + flavorData.variantConfiguration.buildType.name) + else -> null + } + + private data class VariantComponentNames(val variantName: String, val flavorName: String, val buildTypeName: String) + + private fun getCommonResDirectories(resDirectories: List>): Set { + var common = resDirectories.firstOrNull()?.toSet() ?: return emptySet() + + for (resDirs in resDirectories.drop(1)) { + common = common.intersect(resDirs) + } + + return common + } + + private fun getApplicationPackage(project: Project, mainSourceSet: AndroidSourceSet): String { + val manifestFile = mainSourceSet.manifest.srcFile + val applicationPackage = getApplicationPackageFromManifest(manifestFile) + + if (applicationPackage == null) { + project.logger.warn("Application package name is not present in the manifest file " + + "(${manifestFile.absolutePath})") + + return "" + } else { + return applicationPackage + } + } + private fun getApplicationPackageFromManifest(manifestFile: File): String? { try { return manifestFile.parseXml().documentElement.getAttribute("package") @@ -101,7 +162,7 @@ class AndroidSubplugin : KotlinGradleSubplugin { override fun getArtifactName() = "kotlin-android-extensions" - fun File.parseXml(): Document { + private fun File.parseXml(): Document { val factory = DocumentBuilderFactory.newInstance() val builder = factory.newDocumentBuilder() return builder.parse(this) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt index a77e6c14f30..db6bada0d5f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt @@ -47,7 +47,8 @@ internal fun Project.initKapt( variantName: String, kotlinOptions: KotlinJvmOptionsImpl?, subpluginEnvironment: SubpluginEnvironment, - tasksProvider: KotlinTasksProvider + tasksProvider: KotlinTasksProvider, + androidProjectHandler: AbstractAndroidProjectHandler<*>? ): KotlinCompile? { val kaptExtension = extensions.getByType(KaptExtension::class.java) val kotlinAfterJavaTask: KotlinCompile? @@ -72,7 +73,7 @@ internal fun Project.initKapt( kotlinAfterJavaTask.source(kaptManager.generatedKotlinSourceDir) kotlinAfterJavaTask.source(kaptManager.aptOutputDir) - subpluginEnvironment.addSubpluginOptions(this, kotlinAfterJavaTask, javaTask, null, null) + subpluginEnvironment.addSubpluginOptions(this, kotlinAfterJavaTask, javaTask, null, androidProjectHandler, null) javaTask.doLast { moveGeneratedJavaFilesToCorrespondingDirectories(kaptManager.aptOutputDir) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt index 5697a382be0..2e4c85d3b87 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt @@ -125,6 +125,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { kotlinCompile: KotlinCompile, javaCompile: AbstractCompile, variantData: Any?, + androidProjectHandler: Any?, javaSourceSet: SourceSet? ): List { assert((variantData != null) xor (javaSourceSet != null)) 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 6a71813bf53..dc666d68449 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 @@ -29,7 +29,6 @@ import org.jetbrains.kotlin.com.intellij.util.ReflectionUtil import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl import org.jetbrains.kotlin.gradle.internal.* import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.getKaptClasssesDir -import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.utils.ParsedGradleVersion import org.jetbrains.kotlin.incremental.configureMultiProjectIncrementalCompilation @@ -135,7 +134,7 @@ internal class Kotlin2JvmSourceSetProcessor( val subpluginEnvironment = loadSubplugins(project) val appliedPlugins = subpluginEnvironment.addSubpluginOptions( - project, kotlinTask, javaTask as JavaCompile, null, sourceSet) + project, kotlinTask, javaTask as JavaCompile, null, null, sourceSet) var kotlinAfterJavaTask: KotlinCompile? = null @@ -148,7 +147,7 @@ internal class Kotlin2JvmSourceSetProcessor( aptConfiguration.resolve(), aptOutputDir, aptWorkingDir) kotlinAfterJavaTask = project.initKapt(kotlinTask, javaTask, kaptManager, - sourceSetName, null, subpluginEnvironment, tasksProvider) + sourceSetName, null, subpluginEnvironment, tasksProvider, null) } else { removeAnnotationProcessingPluginClasspathEntry(kotlinTask) } @@ -409,12 +408,13 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationT protected val logger = Logging.getLogger(this.javaClass) - protected abstract fun forEachVariant(project: Project, action: (V) -> Unit): Unit + abstract fun forEachVariant(project: Project, action: (V) -> Unit): Unit + abstract fun getTestedVariantData(variantData: V): V? + abstract fun getResDirectories(variantData: V): List protected abstract fun getSourceProviders(variantData: V): Iterable protected abstract fun getAllJavaSources(variantData: V): Iterable protected abstract fun getVariantName(variant: V): String - protected abstract fun getTestedVariantData(variantData: V): V? protected abstract fun getJavaTask(variantData: V): AbstractCompile? protected abstract fun addJavaSourceDirectoryToVariantModel(variantData: V, javaSourceDirectory: File): Unit @@ -541,7 +541,7 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationT aptFiles.toSet(), aptOutputDir, aptWorkingDir, variantData) kotlinAfterJavaTask = project.initKapt(kotlinTask, javaTask, kaptManager, - variantDataName, rootKotlinOptions, subpluginEnvironment, tasksProvider) + variantDataName, rootKotlinOptions, subpluginEnvironment, tasksProvider, this) } for (task in listOfNotNull(kotlinTask, kotlinAfterJavaTask)) { @@ -554,7 +554,7 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationT configureMultiProjectIc(project, variantData, javaTask, kotlinTask, kotlinAfterJavaTask) val appliedPlugins = subpluginEnvironment.addSubpluginOptions( - project, kotlinTask, javaTask, wrapVariantDataForKapt(variantData), null) + project, kotlinTask, javaTask, wrapVariantDataForKapt(variantData), this, null) appliedPlugins.flatMap { it.getSubpluginKotlinTasks(project, kotlinTask) } .forEach { configureSources(it, variantData) } @@ -700,6 +700,7 @@ internal class SubpluginEnvironment( kotlinTask: KotlinCompile, javaTask: AbstractCompile, variantData: Any?, + androidProjectHandler: AbstractAndroidProjectHandler?, javaSourceSet: SourceSet? ): List> { val pluginOptions = kotlinTask.pluginOptions @@ -715,7 +716,7 @@ internal class SubpluginEnvironment( val subpluginClasspath = subpluginClasspaths[subplugin] ?: continue subpluginClasspath.forEach { pluginOptions.addClasspathEntry(it) } - for (option in subplugin.apply(project, kotlinTask, javaTask, variantData, javaSourceSet)) { + for (option in subplugin.apply(project, kotlinTask, javaTask, variantData, androidProjectHandler, javaSourceSet)) { pluginOptions.addPluginArgument(subplugin.getCompilerPluginId(), option.key, option.value) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/LegacyAndroidAndroidProjectHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/LegacyAndroidAndroidProjectHandler.kt index 40d15400108..30578247f77 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/LegacyAndroidAndroidProjectHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/LegacyAndroidAndroidProjectHandler.kt @@ -91,6 +91,10 @@ internal class LegacyAndroidAndroidProjectHandler(kotlinConfigurationTools: Kotl override fun getTestedVariantData(variantData: BaseVariantData<*>): BaseVariantData<*>? = ((variantData as? TestVariantData)?.testedVariantData as? BaseVariantData<*>) + override fun getResDirectories(variantData: BaseVariantData): List { + return variantData.mergeResourcesTask?.rawInputFolders?.toList() ?: emptyList() + } + private fun Project.tryGetSingleArtifact(variantData: BaseVariantData<*>): File? { val log = logger log.kotlinDebug { "Trying to determine single artifact for project $path" } diff --git a/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt b/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt index 483f8774848..1478ef15494 100644 --- a/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt +++ b/libraries/tools/kotlin-noarg/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/NoArgSubplugin.kt @@ -81,6 +81,7 @@ class NoArgKotlinGradleSubplugin : KotlinGradleSubplugin { kotlinCompile: AbstractCompile, javaCompile: AbstractCompile, variantData: Any?, + androidProjectHandler: Any?, javaSourceSet: SourceSet? ): List { if (!NoArgGradleSubplugin.isEnabled(project)) return emptyList() diff --git a/libraries/tools/kotlin-sam-with-receiver/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/SamWithReceiverSubplugin.kt b/libraries/tools/kotlin-sam-with-receiver/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/SamWithReceiverSubplugin.kt index 901e35b4eb8..0e5585548d1 100644 --- a/libraries/tools/kotlin-sam-with-receiver/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/SamWithReceiverSubplugin.kt +++ b/libraries/tools/kotlin-sam-with-receiver/src/main/kotlin/org/jetbrains/kotlin/noarg/gradle/SamWithReceiverSubplugin.kt @@ -80,6 +80,7 @@ class SamWithReceiverKotlinGradleSubplugin : KotlinGradleSubplugin { if (!SamWithReceiverGradleSubplugin.isEnabled(project)) return emptyList() diff --git a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/res/IDEAndroidLayoutXmlFileManager.kt b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/res/IDEAndroidLayoutXmlFileManager.kt index 2716626887f..369a5f47c21 100644 --- a/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/res/IDEAndroidLayoutXmlFileManager.kt +++ b/plugins/android-extensions/android-extensions-idea/src/org/jetbrains/kotlin/android/synthetic/idea/res/IDEAndroidLayoutXmlFileManager.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.android.synthetic.idea.res import com.android.builder.model.SourceProvider import com.android.tools.idea.gradle.AndroidGradleModel import com.intellij.openapi.module.Module +import com.intellij.openapi.roots.ProjectRootModificationTracker import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.impl.PsiTreeChangePreprocessor @@ -47,7 +48,9 @@ class IDEAndroidLayoutXmlFileManager(val module: Module) : AndroidLayoutXmlFileM else { if (_moduleData == null) { _moduleData = cachedValue(project) { - CachedValueProvider.Result.create(super.getModuleData(), getPsiTreeChangePreprocessor()) + CachedValueProvider.Result.create( + super.getModuleData(), + getPsiTreeChangePreprocessor(), ProjectRootModificationTracker.getInstance(project)) } } } @@ -103,31 +106,33 @@ class IDEAndroidLayoutXmlFileManager(val module: Module) : AndroidLayoutXmlFileM return listOf() } + private fun SourceProvider.toVariant() = AndroidVariant(name, resDirectories.map { it.canonicalPath }) + private val Module.androidFacet: AndroidFacet? get() = AndroidFacet.getInstance(this) - private fun SourceProvider.toVariant() = AndroidVariant(name, resDirectories.map { it.absolutePath }) - private fun AndroidFacet.toAndroidModuleInfo(): AndroidModule? { - val applicationPackage = manifest?.`package`?.toString() + val applicationPackage = manifest?.`package`?.toString() ?: return null - if (applicationPackage != null) { - val mainVariant = mainSourceProvider.toVariant() + val allResDirectories = getAppResources(true)?.resourceDirs.orEmpty().mapNotNull { it.canonicalPath } - val method = try { this::class.java.getMethod("getFlavorSourceProviders") } catch (e: NoSuchMethodException) { null } - val variants: List? = if (method != null) { - val sourceProviders = method.invoke(this) as List? - sourceProviders?.map { it.toVariant() } ?: listOf() - } - else { - val model = AndroidGradleModel.get(module) - model?.flavorSourceProviders?.map { it.toVariant() } ?: listOf(this.mainSourceProvider.toVariant()) - } + val resDirectoriesForMainVariant = run { + val resDirsFromSourceProviders = AndroidGradleModel.get(module)?.allSourceProviders.orEmpty() + .filter { it.name != "main" } + .flatMap { it.resDirectories } + .map { it.canonicalPath } - if (variants != null) { - return AndroidModule(applicationPackage, listOf(mainVariant) + variants) + allResDirectories - resDirsFromSourceProviders + } + + val variants = mutableListOf(AndroidVariant("main", resDirectoriesForMainVariant)) + + AndroidGradleModel.get(module)?.let { androidGradleModel -> + androidGradleModel.activeSourceProviders.filter { it.name != "main" }.forEach { sourceProvider -> + variants += sourceProvider.toVariant() } } - return null + + return AndroidModule(applicationPackage, variants) } } \ No newline at end of file