diff --git a/.idea/artifacts/KotlinPlugin.xml b/.idea/artifacts/KotlinPlugin.xml
index 1c420dbd6a4..89b5c746b88 100644
--- a/.idea/artifacts/KotlinPlugin.xml
+++ b/.idea/artifacts/KotlinPlugin.xml
@@ -109,6 +109,9 @@
+
+
+
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 520fa2e16e7..1e6d1ac1a68 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -78,6 +78,7 @@
+
diff --git a/idea/kotlin-gradle-tooling/src/KotlinGradleModelBuilder.kt b/idea/kotlin-gradle-tooling/src/KotlinGradleModelBuilder.kt
index 3e90366eca1..102ac18ceed 100644
--- a/idea/kotlin-gradle-tooling/src/KotlinGradleModelBuilder.kt
+++ b/idea/kotlin-gradle-tooling/src/KotlinGradleModelBuilder.kt
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.gradle
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.ProjectDependency
+import org.gradle.tooling.ModelBuilder
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
import java.io.File
@@ -60,7 +61,7 @@ class KotlinGradleModelImpl(
override val transitiveCommonDependencies: Set
) : KotlinGradleModel
-class KotlinGradleModelBuilder : ModelBuilderService {
+abstract class AbstractKotlinGradleModelBuilder : ModelBuilderService {
companion object {
val kotlinCompileTaskClasses = listOf("org.jetbrains.kotlin.gradle.tasks.KotlinCompile_Decorated",
"org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile_Decorated")
@@ -70,10 +71,20 @@ class KotlinGradleModelBuilder : ModelBuilderService {
"kotlin2js" to "kotlin-platform-js"
)
val kotlinPluginIds = listOf("kotlin", "kotlin2js", "kotlin-android")
- private val kotlinPlatformCommonPluginId = "kotlin-platform-common"
- private val ABSTRACT_KOTLIN_COMPILE_CLASS = "org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile"
- }
+ val kotlinPlatformCommonPluginId = "kotlin-platform-common"
+ val ABSTRACT_KOTLIN_COMPILE_CLASS = "org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile"
+ fun Task.getSourceSetName(): String {
+ return try {
+ javaClass.methods.firstOrNull { it.name.startsWith("getSourceSetName") && it.parameterTypes.isEmpty() }?.invoke(this) as? String
+ } catch (e : InvocationTargetException) {
+ null // can be thrown if property is not initialized yet
+ } ?: "main"
+ }
+ }
+}
+
+class KotlinGradleModelBuilder : AbstractKotlinGradleModelBuilder() {
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
return ErrorMessageBuilder.create(project, e, "Gradle import errors").withDescription("Unable to build Kotlin project configuration")
}
@@ -168,14 +179,6 @@ class KotlinGradleModelBuilder : ModelBuilderService {
}
}
- private fun Task.getSourceSetName(): String {
- return try {
- javaClass.methods.firstOrNull { it.name.startsWith("getSourceSetName") && it.parameterTypes.isEmpty() }?.invoke(this) as? String
- } catch (e : InvocationTargetException) {
- null // can be thrown if property is not initialized yet
- } ?: "main"
- }
-
override fun buildAll(modelName: String?, project: Project): KotlinGradleModelImpl {
val kotlinPluginId = kotlinPluginIds.singleOrNull { project.plugins.findPlugin(it) != null }
val platformPluginId = platformPluginIds.singleOrNull { project.plugins.findPlugin(it) != null }
diff --git a/idea/src/META-INF/gradle.xml b/idea/src/META-INF/gradle.xml
index f5fdce48bcb..efff1b2c218 100644
--- a/idea/src/META-INF/gradle.xml
+++ b/idea/src/META-INF/gradle.xml
@@ -7,6 +7,7 @@
+
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 f7e4d793808..93f4578bda9 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
@@ -53,7 +53,7 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
}
if (Kapt3GradleSubplugin.isEnabled(project)) {
// Add Kapt3 output as well, since there's no SyncOutputTask with the new API
- val kaptClasssesDir = Kapt3KotlinGradleSubplugin.getKaptClasssesDir(project, getVariantName(variantData))
+ val kaptClasssesDir = Kapt3GradleSubplugin.getKaptGeneratedClassesDir(project, getVariantName(variantData))
add(kaptClasssesDir)
}
}
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 9b77cb56e0e..56c2805b765 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
@@ -34,11 +34,26 @@ import java.io.ByteArrayOutputStream
import java.io.File
import java.io.ObjectOutputStream
import javax.xml.bind.DatatypeConverter.printBase64Binary
+import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedSourcesDir
+import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedClassesDir
+import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedKotlinSourcesDir
// apply plugin: 'kotlin-kapt'
class Kapt3GradleSubplugin : Plugin {
companion object {
fun isEnabled(project: Project) = project.plugins.findPlugin(Kapt3GradleSubplugin::class.java) != null
+
+ @JvmStatic
+ fun getKaptGeneratedClassesDir(project: Project, sourceSetName: String) =
+ File(project.project.buildDir, "tmp/kapt3/classes/$sourceSetName")
+
+ @JvmStatic
+ fun getKaptGeneratedSourcesDir(project: Project, sourceSetName: String) =
+ File(project.project.buildDir, "generated/source/kapt/$sourceSetName")
+
+ @JvmStatic
+ fun getKaptGeneratedKotlinSourcesDir(project: Project, sourceSetName: String) =
+ File(project.project.buildDir, "generated/source/kaptKotlin/$sourceSetName")
}
override fun apply(project: Project) {}
@@ -77,23 +92,12 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin {
}
fun findMainKaptConfiguration(project: Project) = project.findKaptConfiguration(MAIN_KAPT_CONFIGURATION_NAME)
-
- fun getKaptClasssesDir(project: Project, sourceSetName: String): File =
- File(project.project.buildDir, "tmp/kapt3/classes/$sourceSetName")
}
private val kotlinToKaptGenerateStubsTasksMap = mutableMapOf()
override fun isApplicable(project: Project, task: AbstractCompile) = task is KotlinCompile && Kapt3GradleSubplugin.isEnabled(project)
- fun getKaptGeneratedDir(project: Project, sourceSetName: String): File {
- return File(project.project.buildDir, "generated/source/kapt/$sourceSetName")
- }
-
- fun getKaptGeneratedDirForKotlin(project: Project, sourceSetName: String): File {
- return File(project.project.buildDir, "generated/source/kaptKotlin/$sourceSetName")
- }
-
private fun Kapt3SubpluginContext.getKaptStubsDir() = createAndReturnTemporaryKaptDirectory("stubs")
private fun Kapt3SubpluginContext.getKaptIncrementalDataDir() = createAndReturnTemporaryKaptDirectory("incrementalData")
@@ -113,9 +117,9 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin {
val javaSourceSet: SourceSet?,
val kaptExtension: KaptExtension,
val kaptClasspath: MutableList) {
- val sourcesOutputDir = getKaptGeneratedDir(project, sourceSetName)
- val kotlinSourcesOutputDir = getKaptGeneratedDirForKotlin(project, sourceSetName)
- val classesOutputDir = getKaptClasssesDir(project, sourceSetName)
+ val sourcesOutputDir = getKaptGeneratedSourcesDir(project, sourceSetName)
+ val kotlinSourcesOutputDir = getKaptGeneratedKotlinSourcesDir(project, sourceSetName)
+ val classesOutputDir = getKaptGeneratedClassesDir(project, sourceSetName)
val kaptClasspathArtifacts = project
.resolveSubpluginArtifacts(listOf(this@Kapt3KotlinGradleSubplugin))
@@ -193,7 +197,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin {
private fun Kapt3SubpluginContext.buildOptions(aptMode: String): List {
val pluginOptions = mutableListOf()
- val generatedFilesDir = getKaptGeneratedDir(project, sourceSetName)
+ val generatedFilesDir = getKaptGeneratedSourcesDir(project, sourceSetName)
kaptVariantData?.addJavaSourceFoldersToModel(generatedFilesDir)
pluginOptions += SubpluginOption("aptMode", aptMode)
@@ -207,7 +211,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin {
javaCompile.source(generatedFilesDir)
pluginOptions += SubpluginOption("sources", generatedFilesDir.canonicalPath)
- pluginOptions += SubpluginOption("classes", getKaptClasssesDir(project, sourceSetName).canonicalPath)
+ pluginOptions += SubpluginOption("classes", getKaptGeneratedClassesDir(project, sourceSetName).canonicalPath)
pluginOptions += SubpluginOption("incrementalData", getKaptIncrementalDataDir().canonicalPath)
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 9b9fa3c2c11..d12a08e7ab7 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
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.com.intellij.openapi.util.text.StringUtil.compareVer
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.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedClassesDir
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.utils.ParsedGradleVersion
import org.jetbrains.kotlin.gradle.utils.checkedReflection
@@ -679,7 +679,7 @@ internal fun createSyncOutputTask(
syncTask.kotlinTask = kotlinCompile
kotlinTask.javaOutputDir = javaDir
kotlinAfterJavaTask?.javaOutputDir = javaDir
- syncTask.kaptClassesDir = getKaptClasssesDir(project, variantName)
+ syncTask.kaptClassesDir = getKaptGeneratedClassesDir(project, variantName)
// copying should be executed after a latter task
val previousTask = kotlinAfterJavaTask ?: javaTask
diff --git a/plugins/kapt3-idea/kapt3-idea.iml b/plugins/kapt3-idea/kapt3-idea.iml
new file mode 100644
index 00000000000..0b3bb9d456d
--- /dev/null
+++ b/plugins/kapt3-idea/kapt3-idea.iml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/kapt3-idea/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService b/plugins/kapt3-idea/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService
new file mode 100644
index 00000000000..310ea0a40cf
--- /dev/null
+++ b/plugins/kapt3-idea/src/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService
@@ -0,0 +1 @@
+org.jetbrains.kotlin.kapt.idea.KaptModelBuilderService
\ No newline at end of file
diff --git a/plugins/kapt3-idea/src/org/jetbrains/kotlin/kapt/idea/KaptProjectResolverExtension.kt b/plugins/kapt3-idea/src/org/jetbrains/kotlin/kapt/idea/KaptProjectResolverExtension.kt
new file mode 100644
index 00000000000..f35eef9deb5
--- /dev/null
+++ b/plugins/kapt3-idea/src/org/jetbrains/kotlin/kapt/idea/KaptProjectResolverExtension.kt
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2010-2017 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.kapt.idea
+
+import com.android.tools.idea.gradle.project.model.AndroidModuleModel
+import com.intellij.openapi.externalSystem.model.DataNode
+import com.intellij.openapi.externalSystem.model.ProjectKeys
+import com.intellij.openapi.externalSystem.model.project.*
+import org.gradle.api.Project
+import org.gradle.tooling.model.idea.IdeaModule
+import org.jetbrains.kotlin.gradle.AbstractKotlinGradleModelBuilder
+import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
+import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
+import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
+import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
+import java.io.File
+import java.io.Serializable
+import java.lang.Exception
+import java.lang.reflect.Modifier
+
+interface KaptSourceSetModel : Serializable {
+ val sourceSetName: String
+ val isTest: Boolean
+ val generatedSourcesDir: String
+ val generatedClassesDir: String
+ val generatedKotlinSourcesDir: String
+
+ val generatedSourcesDirFile get() = generatedSourcesDir.takeIf { it.isNotEmpty() }?.let(::File)
+ val generatedClassesDirFile get() = generatedClassesDir.takeIf { it.isNotEmpty() }?.let(::File)
+ val generatedKotlinSourcesDirFile get() = generatedKotlinSourcesDir.takeIf { it.isNotEmpty() }?.let(::File)
+}
+
+class KaptSourceSetModelImpl(
+ override val sourceSetName: String,
+ override val isTest: Boolean,
+ override val generatedSourcesDir: String,
+ override val generatedClassesDir: String,
+ override val generatedKotlinSourcesDir: String
+) : KaptSourceSetModel
+
+interface KaptGradleModel : Serializable {
+ val isEnabled: Boolean
+ val buildDirectory: File
+ val sourceSets: List
+}
+
+class KaptGradleModelImpl(
+ override val isEnabled: Boolean,
+ override val buildDirectory: File,
+ override val sourceSets: List
+) : KaptGradleModel
+
+@Suppress("unused")
+class KaptProjectResolverExtension : AbstractProjectResolverExtension() {
+ override fun getExtraProjectModelClasses() = setOf(KaptGradleModel::class.java)
+ override fun getToolingExtensionsClasses() = setOf(KaptModelBuilderService::class.java)
+
+ override fun populateModuleExtraModels(gradleModule: IdeaModule, ideModule: DataNode) {
+ val kaptModel = resolverCtx.getExtraProject(gradleModule, KaptGradleModel::class.java) ?: return
+
+ if (kaptModel.isEnabled) {
+ for (sourceSet in kaptModel.sourceSets) {
+ populateAndroidModuleModelIfNeeded(ideModule, sourceSet)
+
+ val sourceSetDataNode = ideModule.findGradleSourceSet(sourceSet.sourceSetName) ?: continue
+
+ fun addSourceSet(path: String, type: ExternalSystemSourceType) {
+ val contentRootData = ContentRootData(GRADLE_SYSTEM_ID, path)
+ contentRootData.storePath(type, path)
+ val child = sourceSetDataNode.createChild(ProjectKeys.CONTENT_ROOT, contentRootData)
+ sourceSetDataNode.addChild(child)
+ }
+
+ val sourceType = if (sourceSet.isTest) ExternalSystemSourceType.TEST_GENERATED else ExternalSystemSourceType.SOURCE_GENERATED
+ sourceSet.generatedSourcesDirFile?.let { addSourceSet(it.absolutePath, sourceType) }
+ sourceSet.generatedKotlinSourcesDirFile?.let { addSourceSet(it.absolutePath, sourceType) }
+
+ sourceSet.generatedClassesDirFile?.let { generatedClassesDir ->
+ val libraryData = LibraryData(GRADLE_SYSTEM_ID, "Kapt generated classes")
+ libraryData.addPath(LibraryPathType.BINARY, generatedClassesDir.absolutePath)
+ val libraryDependencyData = LibraryDependencyData(ideModule.data, libraryData, LibraryLevel.MODULE)
+ val child = sourceSetDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData)
+ sourceSetDataNode.addChild(child)
+ }
+ }
+ }
+
+ super.populateModuleExtraModels(gradleModule, ideModule)
+ }
+
+ private fun populateAndroidModuleModelIfNeeded(ideModule: DataNode, sourceSet: KaptSourceSetModel) {
+ if (true) return
+
+ ideModule.findAndroidModuleModel()?.let { androidModelAny ->
+ // We can cast to AndroidModuleModel cause we already checked in findAndroidModuleModel() that the class exists
+
+ val androidModel = androidModelAny.data as? AndroidModuleModel
+ val generatedKotlinSources = sourceSet.generatedKotlinSourcesDirFile
+
+ if (androidModel != null && generatedKotlinSources != null) {
+ // Looks like we can't add generated class root as a library dependency
+ androidModel.registerExtraGeneratedSourceFolder(generatedKotlinSources)
+ }
+ }
+ }
+
+ private fun DataNode.findAndroidModuleModel(): DataNode<*>? {
+ val modelClassName = "com.android.tools.idea.gradle.project.model.AndroidModuleModel"
+ val node = children.firstOrNull { it.key.dataType == modelClassName } ?: return null
+ return if (!hasClassInClasspath(modelClassName)) null else node
+ }
+
+ private fun hasClassInClasspath(name: String): Boolean {
+ return try {
+ Class.forName(name) != null
+ } catch (thr: Throwable) {
+ false
+ }
+ }
+
+ private fun DataNode.findGradleSourceSet(sourceSetName: String): DataNode? {
+ val moduleName = data.id
+ for (child in children) {
+ val gradleSourceSetData = child.data as? GradleSourceSetData ?: continue
+ if (gradleSourceSetData.id == "$moduleName:$sourceSetName") {
+ @Suppress("UNCHECKED_CAST")
+ return child as DataNode?
+ }
+ }
+
+ return null
+ }
+}
+
+class KaptModelBuilderService : AbstractKotlinGradleModelBuilder() {
+ override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
+ return ErrorMessageBuilder.create(project, e, "Gradle import errors")
+ .withDescription("Unable to build kotlin-kapt plugin configuration")
+ }
+
+ override fun canBuild(modelName: String?): Boolean = modelName == KaptGradleModel::class.java.name
+
+ override fun buildAll(modelName: String?, project: Project): Any {
+ val kaptPlugin = project.plugins.findPlugin("kotlin-kapt")
+ val kaptIsEnabled = kaptPlugin != null
+
+ val sourceSets = mutableListOf()
+
+ if (kaptIsEnabled) {
+ project.getAllTasks(false)[project]?.forEach { compileTask ->
+ if (compileTask.javaClass.name !in kotlinCompileTaskClasses) return@forEach
+
+ val sourceSetName = compileTask.getSourceSetName()
+ val isTest = sourceSetName.toLowerCase().endsWith("test")
+
+ val kaptGeneratedSourcesDir = getKaptDirectory("getKaptGeneratedSourcesDir", project, sourceSetName)
+ val kaptGeneratedClassesDir = getKaptDirectory("getKaptGeneratedClassesDir", project, sourceSetName)
+ val kaptGeneratedKotlinSourcesDir = getKaptDirectory("getKaptGeneratedKotlinSourcesDir", project, sourceSetName)
+ sourceSets += KaptSourceSetModelImpl(
+ sourceSetName, isTest, kaptGeneratedSourcesDir, kaptGeneratedClassesDir, kaptGeneratedKotlinSourcesDir)
+ }
+ }
+
+ return KaptGradleModelImpl(kaptIsEnabled, project.buildDir, sourceSets)
+ }
+
+ private fun getKaptDirectory(funName: String, project: Project, sourceSetName: String): String {
+ val kotlinKaptPlugin = project.plugins.findPlugin("kotlin-kapt") ?: return ""
+
+ val targetMethod = kotlinKaptPlugin::class.java.methods.firstOrNull {
+ Modifier.isStatic(it.modifiers) && it.name == funName && it.parameterCount == 2
+ } ?: return ""
+
+ return (targetMethod(null, project, sourceSetName) as? File)?.absolutePath ?: ""
+ }
+}
\ No newline at end of file