Kotlin Facet: Fix Gradle import without "module per source set" option

#KT-15812 Fixed
This commit is contained in:
Alexey Sedunov
2017-01-25 17:57:15 +03:00
parent 34b0e175ca
commit be3e33051e
4 changed files with 84 additions and 40 deletions
+1
View File
@@ -12,6 +12,7 @@
</extensionPoints>
<extensions defaultExtensionNs="com.intellij">
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
<localInspection
@@ -23,6 +23,7 @@ import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.config.CoroutineSupport
import org.jetbrains.kotlin.config.JvmTarget
@@ -43,29 +44,13 @@ interface GradleProjectImportHandler {
GradleProjectImportHandler::class.java
)
operator fun invoke(facet: KotlinFacet, sourceSetNode: DataNode<GradleSourceSetData>)
fun importBySourceSet(facet: KotlinFacet, sourceSetNode: DataNode<GradleSourceSetData>)
fun importByModule(facet: KotlinFacet, moduleNode: DataNode<ModuleData>)
}
class KotlinGradleProjectDataService : AbstractProjectDataService<GradleSourceSetData, Void>() {
class KotlinGradleSourceSetDataService : AbstractProjectDataService<GradleSourceSetData, Void>() {
override fun getTargetDataKey() = GradleSourceSetData.KEY
private fun detectPlatformByPlugin(moduleNode: DataNode<ModuleData>): TargetPlatformKind<*>? {
val projectNode = ExternalSystemApiUtil.findParent(moduleNode, ProjectKeys.PROJECT)
val externalProjectNode = ExternalSystemApiUtil.find(projectNode as DataNode<*>, ExternalProjectDataService.KEY)
return externalProjectNode?.let {
when (it.data.plugins.values.map { it.id }.firstOrNull { it.startsWith("kotlin-platform-") }) {
"kotlin-platform-jvm" -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]
"kotlin-platform-js" -> TargetPlatformKind.JavaScript
"kotlin-platform-common" -> TargetPlatformKind.Common
else -> null
}
}
}
private fun detectPlatformByLibrary(moduleNode: DataNode<ModuleData>): TargetPlatformKind<*>? {
return TargetPlatformKind.ALL_PLATFORMS.firstOrNull { moduleNode.getResolvedKotlinStdlibVersionByModuleData(it.mavenLibraryId) != null }
}
override fun postProcess(
toImport: Collection<DataNode<GradleSourceSetData>>,
projectData: ProjectData?,
@@ -76,21 +61,70 @@ class KotlinGradleProjectDataService : AbstractProjectDataService<GradleSourceSe
val sourceSetData = sourceSetNode.data
val ideModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
val moduleNode = ExternalSystemApiUtil.findParent(sourceSetNode, ProjectKeys.MODULE)
val compilerVersion = moduleNode?.findAll(BuildScriptClasspathData.KEY)?.firstOrNull()?.data?.let(::findKotlinPluginVersion)
?: continue
val platformKind = detectPlatformByPlugin(moduleNode) ?: detectPlatformByLibrary(moduleNode)
val coroutinesProperty = findKotlinCoroutinesProperty(project)
val kotlinFacet = ideModule.getOrCreateFacet(modelsProvider, false)
kotlinFacet.configureFacet(compilerVersion, coroutinesProperty, platformKind, modelsProvider)
moduleNode.serializedCompilerArguments?.let { parseCompilerArgumentsToFacet(it, kotlinFacet) }
GradleProjectImportHandler.getInstances(project).forEach { it(kotlinFacet, sourceSetNode) }
val moduleNode = ExternalSystemApiUtil.findParent(sourceSetNode, ProjectKeys.MODULE) ?: continue
val kotlinFacet = configureFacetByGradleModule(moduleNode, ideModule, modelsProvider) ?: continue
GradleProjectImportHandler.getInstances(project).forEach { it.importBySourceSet(kotlinFacet, sourceSetNode) }
}
}
}
class KotlinGradleProjectDataService : AbstractProjectDataService<ModuleData, Void>() {
override fun getTargetDataKey() = ProjectKeys.MODULE
override fun postProcess(
toImport: MutableCollection<DataNode<ModuleData>>,
projectData: ProjectData?,
project: Project,
modelsProvider: IdeModifiableModelsProvider
) {
for (moduleNode in toImport) {
// If source sets are present, configure facets in the their modules
if (ExternalSystemApiUtil.getChildren(moduleNode, GradleSourceSetData.KEY).isNotEmpty()) continue
val moduleData = moduleNode.data
val ideModule = modelsProvider.findIdeModule(moduleData) ?: continue
val kotlinFacet = configureFacetByGradleModule(moduleNode, ideModule, modelsProvider) ?: continue
GradleProjectImportHandler.getInstances(project).forEach { it.importByModule(kotlinFacet, moduleNode) }
}
}
}
private fun detectPlatformByPlugin(moduleNode: DataNode<ModuleData>): TargetPlatformKind<*>? {
val projectNode = ExternalSystemApiUtil.findParent(moduleNode, ProjectKeys.PROJECT)
val externalProjectNode = ExternalSystemApiUtil.find(projectNode as DataNode<*>, ExternalProjectDataService.KEY)
return externalProjectNode?.let {
when (it.data.plugins.values.map { it.id }.firstOrNull { it.startsWith("kotlin-platform-") }) {
"kotlin-platform-jvm" -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]
"kotlin-platform-js" -> TargetPlatformKind.JavaScript
"kotlin-platform-common" -> TargetPlatformKind.Common
else -> null
}
}
}
private fun detectPlatformByLibrary(moduleNode: DataNode<ModuleData>): TargetPlatformKind<*>? {
return TargetPlatformKind.ALL_PLATFORMS.firstOrNull { moduleNode.getResolvedKotlinStdlibVersionByModuleData(it.mavenLibraryId) != null }
}
private fun configureFacetByGradleModule(
moduleNode: DataNode<ModuleData>,
ideModule: Module,
modelsProvider: IdeModifiableModelsProvider
): KotlinFacet? {
val compilerVersion = moduleNode.findAll(BuildScriptClasspathData.KEY).firstOrNull()?.data?.let(::findKotlinPluginVersion)
?: return null
val platformKind = detectPlatformByPlugin(moduleNode) ?: detectPlatformByLibrary(moduleNode)
val coroutinesProperty = findKotlinCoroutinesProperty(ideModule.project)
val kotlinFacet = ideModule.getOrCreateFacet(modelsProvider, false)
kotlinFacet.configureFacet(compilerVersion, coroutinesProperty, platformKind, modelsProvider)
moduleNode.serializedCompilerArguments?.let { parseCompilerArgumentsToFacet(it, kotlinFacet) }
return kotlinFacet
}
private val gradlePropertyFiles = listOf("local.properties", "gradle.properties")
private fun findKotlinCoroutinesProperty(project: Project): CoroutineSupport {
@@ -155,10 +155,9 @@ val TargetPlatformKind<*>.mavenLibraryId: String
fun Module.getOrCreateFacet(modelsProvider: IdeModifiableModelsProvider, useProjectSettings: Boolean): KotlinFacet {
val facetModel = modelsProvider.getModifiableFacetModel(this)
facetModel.findFacet(KotlinFacetType.TYPE_ID, KotlinFacetType.INSTANCE.defaultFacetName)?.let { return it }
val facet = with(KotlinFacetType.INSTANCE) { createFacet(this@getOrCreateFacet, defaultFacetName, createDefaultConfiguration(), null) }
facetModel.addFacet(facet)
val facet = facetModel.findFacet(KotlinFacetType.TYPE_ID, KotlinFacetType.INSTANCE.defaultFacetName)
?: with(KotlinFacetType.INSTANCE) { createFacet(this@getOrCreateFacet, defaultFacetName, createDefaultConfiguration(), null) }
.apply { facetModel.addFacet(this) }
facet.configuration.settings.useProjectSettings = useProjectSettings
return facet
}
@@ -17,8 +17,10 @@
package org.jetbrains.kotlin.annotation.plugin.ide
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.ModuleData
import com.intellij.openapi.externalSystem.model.task.TaskData
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import org.jetbrains.kotlin.idea.configuration.GradleProjectImportHandler
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
@@ -35,18 +37,23 @@ abstract class AbstractGradleImportHandler : GradleProjectImportHandler {
abstract val dataStorageTaskName: String
abstract val pluginJarFileFromIdea: File
override fun invoke(facet: KotlinFacet, sourceSetNode: DataNode<GradleSourceSetData>) {
modifyCompilerArgumentsForPlugin(facet, getPluginSetup(sourceSetNode),
override fun importBySourceSet(facet: KotlinFacet, sourceSetNode: DataNode<GradleSourceSetData>) {
modifyCompilerArgumentsForPlugin(facet, getPluginSetupBySourceSet(sourceSetNode),
compilerPluginId = compilerPluginId,
pluginName = pluginName,
annotationOptionName = annotationOptionName)
}
private fun getPluginSetup(
sourceSetNode: DataNode<GradleSourceSetData>
override fun importByModule(facet: KotlinFacet, moduleNode: DataNode<ModuleData>) {
modifyCompilerArgumentsForPlugin(facet, getPluginSetupByModule(moduleNode),
compilerPluginId = compilerPluginId,
pluginName = pluginName,
annotationOptionName = annotationOptionName)
}
private fun getPluginSetupByModule(
moduleNode: DataNode<ModuleData>
): AnnotationBasedCompilerPluginSetup? {
val moduleNode = sourceSetNode.parent ?: return null
if (moduleNode.data !is ModuleData) return null
val dataStorageTaskData = moduleNode.children.firstOrNull {
val data = it.data as? TaskData ?: return@firstOrNull false
data.name == dataStorageTaskName
@@ -63,4 +70,7 @@ abstract class AbstractGradleImportHandler : GradleProjectImportHandler {
return AnnotationBasedCompilerPluginSetup(annotationFqNames, classpath)
}
private fun getPluginSetupBySourceSet(sourceSetNode: DataNode<GradleSourceSetData>) =
ExternalSystemApiUtil.findParent(sourceSetNode, ProjectKeys.MODULE)?.let { getPluginSetupByModule(it) }
}