Kotlin Facet: Configure facet automatically on Gradle project import

This commit is contained in:
Alexey Sedunov
2016-11-10 15:43:02 +03:00
parent e59754e86c
commit 075a0bc7f1
6 changed files with 92 additions and 26 deletions

View File

@@ -35,6 +35,7 @@ import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.facet.configureFacet
import org.jetbrains.kotlin.idea.facet.getOrCreateFacet
import org.jetbrains.kotlin.idea.facet.initializeIfNeeded
import org.jetbrains.kotlin.idea.facet.mavenLibraryId
@@ -90,22 +91,9 @@ class KotlinMavenImporter : MavenImporter(KotlinPluginGroupId, KotlinPluginArtif
}
private fun configureFacet(mavenProject: MavenProject, modifiableModelsProvider: IdeModifiableModelsProvider, module: Module) {
val compilerVersion = mavenProject.findPlugin(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID)?.version ?: return
val artifacts = mavenProject.dependencyArtifactIndex.data[KotlinPluginGroupId]?.values?.flatMap { it.filter { it.isResolved } }
val expectedLibraryIds = TargetPlatformKind.ALL_PLATFORMS.map { it.mavenLibraryId }
val stdlibArtifact = artifacts?.firstOrNull { it.artifactId in expectedLibraryIds }
val facet = module.getOrCreateFacet(modifiableModelsProvider)
with(facet.configuration.settings.versionInfo) {
targetPlatformKind = null
apiLevel = null
facet.configuration.settings.initializeIfNeeded(module, modifiableModelsProvider.getModifiableRootModel(module))
languageLevel = LanguageVersion.fromFullVersionString(compilerVersion)
// Both apiLevel and languageLevel should be initialized in the lines above
if (apiLevel!! > languageLevel!!) {
apiLevel = languageLevel
}
}
val compilerVersion = mavenProject.findPlugin(KotlinMavenConfigurator.GROUP_ID, KotlinMavenConfigurator.MAVEN_PLUGIN_ID)?.version
?: return
module.getOrCreateFacet(modifiableModelsProvider).configureFacet(compilerVersion, modifiableModelsProvider)
}
// TODO in theory it should work like this but it doesn't as it couldn't unmark source roots that are not roots anymore.

View File

@@ -9,6 +9,8 @@
<pluginDescriptions implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradlePluginDescription"/>
</extensions>
<extensions defaultExtensionNs="com.intellij">
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
<localInspection
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DifferentKotlinGradleVersionInspection"
displayName="Kotlin Gradle and IDE plugins versions are different"

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2010-2016 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.idea.configuration
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
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.project.Project
import org.jetbrains.kotlin.idea.facet.configureFacet
import org.jetbrains.kotlin.idea.facet.getOrCreateFacet
import org.jetbrains.kotlin.idea.inspections.gradle.findAll
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
class KotlinGradleProjectDataService : AbstractProjectDataService<GradleSourceSetData, Void>() {
override fun getTargetDataKey() = GradleSourceSetData.KEY
override fun postProcess(
toImport: Collection<DataNode<GradleSourceSetData>>,
projectData: ProjectData?,
project: Project,
modelsProvider: IdeModifiableModelsProvider
) {
for (sourceSetNode in toImport) {
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
ideModule.getOrCreateFacet(modelsProvider).configureFacet(compilerVersion, modelsProvider)
}
}
}

View File

@@ -146,3 +146,19 @@ fun Module.getOrCreateFacet(modelsProvider: IdeModifiableModelsProvider): Kotlin
facetModel.addFacet(facet)
return facet
}
fun KotlinFacet.configureFacet(compilerVersion: String, modelsProvider: IdeModifiableModelsProvider) {
val module = module
with(configuration.settings) {
versionInfo.targetPlatformKind = null
versionInfo.apiLevel = null
initializeIfNeeded(module, modelsProvider.getModifiableRootModel(module))
with(versionInfo) {
languageLevel = LanguageVersion.fromFullVersionString(compilerVersion) ?: LanguageVersion.LATEST
// Both apiLevel and languageLevel should be initialized in the lines above
if (apiLevel!! > languageLevel!!) {
apiLevel = languageLevel
}
}
}
}

View File

@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.inspections.gradle
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.psi.PsiFile
@@ -50,7 +51,7 @@ class DifferentStdlibGradleVersionInspection : GradleBaseInspection() {
if (dependenciesCall.parent !is PsiFile) return
val stdlibStatement = findLibraryStatement(closure, "org.jetbrains.kotlin", libraryId) ?: return
val stdlibVersion = getResolvedKotlinStdlibVersion(closure.containingFile, "org.jetbrains.kotlin:$libraryId:") ?: return
val stdlibVersion = getResolvedKotlinStdlibVersion(closure.containingFile, libraryId) ?: return
onFound(stdlibVersion, stdlibStatement)
}
@@ -99,21 +100,27 @@ class DifferentStdlibGradleVersionInspection : GradleBaseInspection() {
return null
}
private fun getResolvedKotlinStdlibVersion(file: PsiFile, libraryNameMarker: String): String? {
private fun getResolvedKotlinStdlibVersion(file: PsiFile, libraryId: String): String? {
val projectStructureNode = findGradleProjectStructure(file) ?: return null
val module = ProjectRootManager.getInstance(file.project).fileIndex.getModuleForFile(file.virtualFile) ?: return null
for (moduleData in projectStructureNode.findAll(ProjectKeys.MODULE).filter { it.data.internalName == module.name }) {
for (sourceSetData in moduleData.node.findAll(GradleSourceSetData.KEY).filter { it.data.internalName.endsWith("main") }) {
for (libraryDependencyData in sourceSetData.node.findAll(ProjectKeys.LIBRARY_DEPENDENCY)) {
if (libraryDependencyData.data.externalName.startsWith(libraryNameMarker)) {
return libraryDependencyData.data.externalName.substringAfter(libraryNameMarker)
}
}
}
moduleData.node.getResolvedKotlinStdlibVersionByModuleData(libraryId)?.let { return it }
}
return null
}
}
}
internal fun DataNode<*>.getResolvedKotlinStdlibVersionByModuleData(libraryId: String): String? {
val libraryNameMarker = "org.jetbrains.kotlin:$libraryId:"
for (sourceSetData in findAll(GradleSourceSetData.KEY).filter { it.data.internalName.endsWith("main") }) {
for (libraryDependencyData in sourceSetData.node.findAll(ProjectKeys.LIBRARY_DEPENDENCY)) {
if (libraryDependencyData.data.externalName.startsWith(libraryNameMarker)) {
return libraryDependencyData.data.externalName.substringAfter(libraryNameMarker)
}
}
}
return null
}

View File

@@ -72,7 +72,7 @@ fun getResolvedKotlinGradleVersion(module: Module): String? {
return null
}
private fun findKotlinPluginVersion(classpathData: BuildScriptClasspathData): String? {
internal fun findKotlinPluginVersion(classpathData: BuildScriptClasspathData): String? {
for (classPathEntry in classpathData.classpathEntries) {
for (path in classPathEntry.classesFile) {
val uniformedPath = path.replace('\\', '/')