as32: Update to AS 3.2 C10
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testRuntime(intellijDep())
|
||||
|
||||
compile(project(":kotlin-stdlib"))
|
||||
compileOnly(project(":kotlin-reflect-api"))
|
||||
compile(project(":core:descriptors"))
|
||||
compile(project(":core:descriptors.jvm"))
|
||||
compile(project(":compiler:backend"))
|
||||
compile(project(":compiler:cli-common"))
|
||||
compile(project(":compiler:frontend"))
|
||||
compile(project(":compiler:frontend.java"))
|
||||
compile(project(":compiler:frontend.script"))
|
||||
compile(project(":js:js.frontend"))
|
||||
compile(project(":js:js.serializer"))
|
||||
compile(project(":compiler:light-classes"))
|
||||
compile(project(":compiler:util"))
|
||||
compile(project(":kotlin-build-common"))
|
||||
compile(project(":compiler:daemon-common"))
|
||||
compile(projectRuntimeJar(":kotlin-daemon-client"))
|
||||
compile(project(":kotlin-compiler-runner")) { isTransitive = false }
|
||||
compile(project(":compiler:plugin-api"))
|
||||
compile(project(":eval4j"))
|
||||
compile(project(":j2k"))
|
||||
compile(project(":idea:formatter"))
|
||||
compile(project(":idea:idea-core"))
|
||||
compile(project(":idea:ide-common"))
|
||||
compile(project(":idea:idea-jps-common"))
|
||||
compile(project(":idea:kotlin-gradle-tooling"))
|
||||
compile(project(":plugins:uast-kotlin"))
|
||||
compile(project(":plugins:uast-kotlin-idea"))
|
||||
compile(project(":kotlin-script-util")) { isTransitive = false }
|
||||
|
||||
compile(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false }
|
||||
compile(commonDep("org.jetbrains", "markdown"))
|
||||
|
||||
compileOnly(project(":kotlin-daemon-client"))
|
||||
|
||||
compileOnly(intellijDep())
|
||||
compileOnly(commonDep("com.google.code.findbugs", "jsr305"))
|
||||
compileOnly(intellijPluginDep("IntelliLang"))
|
||||
compileOnly(intellijPluginDep("copyright"))
|
||||
compileOnly(intellijPluginDep("properties"))
|
||||
compileOnly(intellijPluginDep("java-i18n"))
|
||||
|
||||
testCompile(project(":kotlin-test:kotlin-test-junit"))
|
||||
testCompile(projectTests(":compiler:tests-common"))
|
||||
testCompile(projectTests(":idea:idea-test-framework")) { isTransitive = false }
|
||||
testCompile(project(":idea:idea-jvm")) { isTransitive = false }
|
||||
testCompile(project(":idea:idea-gradle")) { isTransitive = false }
|
||||
testCompile(project(":idea:idea-maven")) { isTransitive = false }
|
||||
testCompile(commonDep("junit:junit"))
|
||||
|
||||
testRuntime(project(":plugins:kapt3-idea")) { isTransitive = false }
|
||||
testRuntime(projectDist(":kotlin-reflect"))
|
||||
testRuntime(projectDist(":kotlin-preloader"))
|
||||
|
||||
testCompile(project(":kotlin-sam-with-receiver-compiler-plugin")) { isTransitive = false }
|
||||
|
||||
testRuntime(project(":plugins:android-extensions-compiler"))
|
||||
testRuntime(project(":plugins:android-extensions-ide")) { isTransitive = false }
|
||||
testRuntime(project(":allopen-ide-plugin")) { isTransitive = false }
|
||||
testRuntime(project(":kotlin-allopen-compiler-plugin"))
|
||||
testRuntime(project(":noarg-ide-plugin")) { isTransitive = false }
|
||||
testRuntime(project(":kotlin-noarg-compiler-plugin"))
|
||||
testRuntime(project(":plugins:annotation-based-compiler-plugins-ide-support")) { isTransitive = false }
|
||||
testRuntime(project(":sam-with-receiver-ide-plugin")) { isTransitive = false }
|
||||
testRuntime(project(":idea:idea-android")) { isTransitive = false }
|
||||
testRuntime(project(":plugins:lint")) { isTransitive = false }
|
||||
testRuntime(project(":plugins:uast-kotlin"))
|
||||
|
||||
(rootProject.extra["compilerModules"] as Array<String>).forEach {
|
||||
testRuntime(project(it))
|
||||
}
|
||||
|
||||
testCompile(intellijPluginDep("IntelliLang"))
|
||||
testCompile(intellijPluginDep("copyright"))
|
||||
testCompile(intellijPluginDep("properties"))
|
||||
testCompile(intellijPluginDep("java-i18n"))
|
||||
testCompileOnly(intellijDep())
|
||||
testCompileOnly(commonDep("com.google.code.findbugs", "jsr305"))
|
||||
testCompileOnly(intellijPluginDep("gradle"))
|
||||
testCompileOnly(intellijPluginDep("Groovy"))
|
||||
//testCompileOnly(intellijPluginDep("maven"))
|
||||
|
||||
testRuntime(intellijPluginDep("junit"))
|
||||
testRuntime(intellijPluginDep("gradle"))
|
||||
testRuntime(intellijPluginDep("Groovy"))
|
||||
testRuntime(intellijPluginDep("coverage"))
|
||||
//testRuntime(intellijPluginDep("maven"))
|
||||
testRuntime(intellijPluginDep("android"))
|
||||
testRuntime(intellijPluginDep("smali"))
|
||||
testRuntime(intellijPluginDep("testng"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" {
|
||||
projectDefault()
|
||||
java.srcDirs("idea-completion/src",
|
||||
"idea-live-templates/src",
|
||||
"idea-repl/src")
|
||||
resources.srcDirs("idea-repl/src").apply { include("META-INF/**") }
|
||||
}
|
||||
"test" {
|
||||
projectDefault()
|
||||
java.srcDirs(
|
||||
"idea-completion/tests",
|
||||
"idea-live-templates/tests")
|
||||
}
|
||||
}
|
||||
|
||||
projectTest {
|
||||
dependsOn(":dist")
|
||||
workingDir = rootDir
|
||||
}
|
||||
|
||||
testsJar {}
|
||||
|
||||
classesDirsArtifact()
|
||||
configureInstrumentation()
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testRuntime(intellijDep())
|
||||
|
||||
compileOnly(project(":kotlin-reflect-api"))
|
||||
compile(project(":compiler:util"))
|
||||
compile(project(":compiler:light-classes"))
|
||||
compile(project(":compiler:frontend"))
|
||||
compile(project(":compiler:frontend.java"))
|
||||
compile(project(":idea"))
|
||||
compile(project(":idea:idea-jvm"))
|
||||
compile(project(":idea:idea-core"))
|
||||
compile(project(":idea:ide-common"))
|
||||
compile(project(":idea:idea-gradle"))
|
||||
|
||||
compile(androidDxJar())
|
||||
|
||||
compileOnly(project(":kotlin-android-extensions-runtime"))
|
||||
compileOnly(intellijDep())
|
||||
compileOnly(intellijPluginDep("android"))
|
||||
|
||||
testCompile(projectDist(":kotlin-test:kotlin-test-jvm"))
|
||||
testCompile(projectTests(":idea:idea-test-framework")) { isTransitive = false }
|
||||
testCompile(project(":plugins:lint")) { isTransitive = false }
|
||||
testCompile(project(":idea:idea-jvm"))
|
||||
testCompile(projectTests(":compiler:tests-common"))
|
||||
testCompile(projectTests(":idea"))
|
||||
testCompile(projectTests(":idea:idea-gradle"))
|
||||
testCompile(commonDep("junit:junit"))
|
||||
|
||||
testCompile(intellijDep())
|
||||
testCompile(intellijPluginDep("properties"))
|
||||
testCompileOnly(intellijPluginDep("android"))
|
||||
|
||||
testRuntime(projectDist(":kotlin-reflect"))
|
||||
testRuntime(project(":plugins:android-extensions-ide"))
|
||||
testRuntime(project(":plugins:kapt3-idea"))
|
||||
testRuntime(project(":sam-with-receiver-ide-plugin"))
|
||||
testRuntime(project(":noarg-ide-plugin"))
|
||||
testRuntime(project(":allopen-ide-plugin"))
|
||||
|
||||
testRuntime(intellijPluginDep("android"))
|
||||
testRuntime(intellijPluginDep("smali"))
|
||||
testRuntime(intellijPluginDep("copyright"))
|
||||
testRuntime(intellijPluginDep("coverage"))
|
||||
testRuntime(intellijPluginDep("gradle"))
|
||||
testRuntime(intellijPluginDep("Groovy"))
|
||||
testRuntime(intellijPluginDep("IntelliLang"))
|
||||
testRuntime(intellijPluginDep("java-decompiler"))
|
||||
testRuntime(intellijPluginDep("java-i18n"))
|
||||
testRuntime(intellijPluginDep("junit"))
|
||||
//testRuntime(intellijPluginDep("maven"))
|
||||
testRuntime(intellijPluginDep("testng"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
projectTest {
|
||||
workingDir = rootDir
|
||||
useAndroidSdk()
|
||||
}
|
||||
|
||||
testsJar {}
|
||||
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.android
|
||||
|
||||
import com.android.tools.idea.npw.template.ConvertJavaToKotlinProvider
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiJavaFile
|
||||
import org.jetbrains.kotlin.android.configure.KotlinAndroidGradleModuleConfigurator
|
||||
import org.jetbrains.kotlin.idea.actions.JavaToKotlinAction
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator
|
||||
import org.jetbrains.kotlin.idea.configuration.getCanBeConfiguredModules
|
||||
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
|
||||
|
||||
class ConvertJavaToKotlinProviderImpl : ConvertJavaToKotlinProvider {
|
||||
override fun configureKotlin(project: Project) {
|
||||
val configurator = KotlinProjectConfigurator.EP_NAME.findExtension(KotlinAndroidGradleModuleConfigurator::class.java)
|
||||
val nonConfiguredModules = getCanBeConfiguredModules(project, configurator)
|
||||
configurator.configureSilently(project, nonConfiguredModules, bundledRuntimeVersion())
|
||||
}
|
||||
|
||||
override fun getKotlinVersion(): String {
|
||||
return bundledRuntimeVersion()
|
||||
}
|
||||
|
||||
override fun convertToKotlin(project: Project, files: List<PsiJavaFile>): List<PsiFile> {
|
||||
return JavaToKotlinAction.convertFiles(files, project, askExternalCodeProcessing = false)
|
||||
}
|
||||
}
|
||||
-1
@@ -25,7 +25,6 @@ import com.android.resources.ResourceType;
|
||||
import com.android.tools.idea.configurations.Configuration;
|
||||
import com.android.tools.idea.configurations.ConfigurationManager;
|
||||
import com.android.tools.idea.res.AppResourceRepository;
|
||||
import com.android.tools.idea.res.LocalResourceRepository;
|
||||
import com.android.tools.idea.res.ResourceHelper;
|
||||
import com.android.tools.idea.ui.resourcechooser.ColorPicker;
|
||||
import com.android.utils.XmlUtils;
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.android.configure
|
||||
|
||||
import com.android.tools.idea.gradle.project.model.JavaModuleModel
|
||||
import com.android.tools.idea.gradle.project.sync.idea.data.service.AndroidProjectKeys
|
||||
import com.android.tools.idea.io.FilePaths
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||
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.project.Project
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.roots.impl.libraries.LibraryEx
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import org.jetbrains.kotlin.idea.configuration.detectPlatformByPlugin
|
||||
import org.jetbrains.kotlin.idea.framework.detectLibraryKind
|
||||
import org.jetbrains.kotlin.idea.framework.libraryKind
|
||||
import java.io.File
|
||||
|
||||
class KotlinAndroidGradleLibraryDataService : AbstractProjectDataService<JavaModuleModel, Void>() {
|
||||
override fun getTargetDataKey() = AndroidProjectKeys.JAVA_MODULE_MODEL
|
||||
|
||||
override fun postProcess(
|
||||
toImport: MutableCollection<DataNode<JavaModuleModel>>,
|
||||
projectData: ProjectData?,
|
||||
project: Project,
|
||||
modelsProvider: IdeModifiableModelsProvider
|
||||
) {
|
||||
for (dataNode in toImport) {
|
||||
val targetLibraryKind = detectPlatformByPlugin(dataNode.parent as DataNode<ModuleData>)?.libraryKind
|
||||
if (targetLibraryKind != null) {
|
||||
for (dep in dataNode.data.jarLibraryDependencies) {
|
||||
val library = modelsProvider.findLibraryByBinaryPath(dep.binaryPath) as LibraryEx? ?: continue
|
||||
if (library.kind == null) {
|
||||
val model = modelsProvider.getModifiableLibraryModel(library) as LibraryEx.ModifiableModelEx
|
||||
detectLibraryKind(model.getFiles(OrderRootType.CLASSES))?.let { model.kind = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IdeModifiableModelsProvider.findLibraryByBinaryPath(path: File?): Library? {
|
||||
if (path == null) return null
|
||||
val url = FilePaths.pathToIdeaUrl(path)
|
||||
return allLibraries.firstOrNull { url in getModifiableLibraryModel(it).getUrls(OrderRootType.CLASSES) }
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.android.configure
|
||||
|
||||
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
|
||||
import com.android.tools.idea.gradle.project.sync.setup.post.ModuleSetupStep
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.progress.ProgressIndicator
|
||||
import org.jetbrains.android.facet.AndroidFacet
|
||||
import org.jetbrains.kotlin.idea.configuration.compilerArgumentsBySourceSet
|
||||
import org.jetbrains.kotlin.idea.configuration.configureFacetByCompilerArguments
|
||||
import org.jetbrains.kotlin.idea.configuration.sourceSetName
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||
|
||||
class KotlinAndroidModuleSetupStep : ModuleSetupStep() {
|
||||
override fun setUpModule(module: Module, progressIndicator: ProgressIndicator?) {
|
||||
val facet = AndroidFacet.getInstance(module) ?: return
|
||||
val androidModel = AndroidModuleModel.get(facet) ?: return
|
||||
val sourceSetName = androidModel.selectedVariant.name
|
||||
if (module.sourceSetName == sourceSetName) return
|
||||
val argsInfo = module.compilerArgumentsBySourceSet?.get(sourceSetName) ?: return
|
||||
val kotlinFacet = KotlinFacet.get(module) ?: return
|
||||
module.sourceSetName = sourceSetName
|
||||
configureFacetByCompilerArguments(kotlinFacet, argsInfo, null)
|
||||
}
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.android.configure
|
||||
|
||||
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.Key
|
||||
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.configuration.GradleProjectImportHandler
|
||||
import org.jetbrains.kotlin.idea.configuration.configureFacetByGradleModule
|
||||
|
||||
class KotlinGradleAndroidModuleModelProjectDataService : AbstractProjectDataService<AndroidModuleModel, Void>() {
|
||||
companion object {
|
||||
val KEY = Key<AndroidModuleModel>(AndroidModuleModel::class.qualifiedName!!, 0)
|
||||
}
|
||||
|
||||
override fun getTargetDataKey() = KEY
|
||||
|
||||
override fun postProcess(
|
||||
toImport: MutableCollection<DataNode<AndroidModuleModel>>,
|
||||
projectData: ProjectData?,
|
||||
project: Project,
|
||||
modelsProvider: IdeModifiableModelsProvider
|
||||
) {
|
||||
super.postProcess(toImport, projectData, project, modelsProvider)
|
||||
for (moduleModelNode in toImport) {
|
||||
val moduleNode = ExternalSystemApiUtil.findParent(moduleModelNode, ProjectKeys.MODULE) ?: continue
|
||||
val moduleData = moduleNode.data
|
||||
val ideModule = modelsProvider.findIdeModule(moduleData) ?: continue
|
||||
val sourceSetName = moduleModelNode.data.selectedVariant.name
|
||||
val kotlinFacet = configureFacetByGradleModule(moduleNode, sourceSetName, ideModule, modelsProvider) ?: continue
|
||||
GradleProjectImportHandler.getInstances(project).forEach { it.importByModule(kotlinFacet, moduleNode) }
|
||||
}
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.android.navigation
|
||||
|
||||
import org.jetbrains.android.util.AndroidResourceUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.android.facet.AndroidFacet
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.PsiClass
|
||||
import org.jetbrains.android.util.AndroidUtils
|
||||
import com.android.SdkConstants
|
||||
import org.jetbrains.android.augment.AndroidPsiElementFinder
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
fun getReferenceExpression(element: PsiElement?): KtSimpleNameExpression? {
|
||||
return PsiTreeUtil.getParentOfType<KtSimpleNameExpression>(element, KtSimpleNameExpression::class.java)
|
||||
}
|
||||
|
||||
// given 'R.a.b' returns info for all three parts of the expression 'a', 'b', 'R'
|
||||
fun getInfo(
|
||||
referenceExpression: KtSimpleNameExpression,
|
||||
facet: AndroidFacet
|
||||
): AndroidResourceUtil.MyReferredResourceFieldInfo? {
|
||||
val info = getReferredInfo(referenceExpression, facet)
|
||||
if (info != null) return info
|
||||
|
||||
val topMostQualified = referenceExpression.getParentQualified().getParentQualified() ?: return null
|
||||
val selectorCandidate = topMostQualified.selectorExpression as? KtSimpleNameExpression ?: return null
|
||||
return getReferredInfo(selectorCandidate, facet)
|
||||
}
|
||||
|
||||
private fun KtExpression?.getParentQualified(): KtDotQualifiedExpression? {
|
||||
return this?.parent as? KtDotQualifiedExpression
|
||||
}
|
||||
|
||||
// returns info if passed expression is 'b' in 'R.a.b'
|
||||
private fun getReferredInfo(
|
||||
lastPart: KtSimpleNameExpression,
|
||||
facet: AndroidFacet
|
||||
): AndroidResourceUtil.MyReferredResourceFieldInfo? {
|
||||
val resFieldName = lastPart.getReferencedName()
|
||||
if (resFieldName.isEmpty()) return null
|
||||
|
||||
val middlePart = getReceiverAsSimpleNameExpression(lastPart) ?: return null
|
||||
|
||||
val resClassName = middlePart.getReferencedName()
|
||||
if (resClassName.isEmpty()) return null
|
||||
|
||||
val firstPart = getReceiverAsSimpleNameExpression(middlePart) ?: return null
|
||||
|
||||
val resolvedClass = firstPart.mainReference.resolve() as? PsiClass ?: return null
|
||||
|
||||
//the following code is copied from
|
||||
// org.jetbrains.android.util.AndroidResourceUtil.getReferredResourceOrManifestField
|
||||
// (org.jetbrains.android.facet.AndroidFacet, com.intellij.psi.PsiReferenceExpression, java.lang.String, boolean)
|
||||
val classShortName = resolvedClass.name
|
||||
|
||||
val fromManifest = AndroidUtils.MANIFEST_CLASS_NAME == classShortName
|
||||
|
||||
if (!fromManifest && AndroidUtils.R_CLASS_NAME != classShortName) {
|
||||
return null
|
||||
}
|
||||
val qName = resolvedClass.qualifiedName
|
||||
|
||||
if (SdkConstants.CLASS_R == qName || AndroidPsiElementFinder.INTERNAL_R_CLASS_QNAME == qName) {
|
||||
return AndroidResourceUtil.MyReferredResourceFieldInfo(resClassName, resFieldName, facet.module, true, false)
|
||||
}
|
||||
val containingFile = resolvedClass.containingFile ?: return null
|
||||
|
||||
val isFromCorrectFile =
|
||||
if (fromManifest) AndroidResourceUtil.isManifestJavaFile(facet, containingFile)
|
||||
else AndroidResourceUtil.isRJavaFile(facet, containingFile)
|
||||
|
||||
if (!isFromCorrectFile) {
|
||||
return null
|
||||
}
|
||||
|
||||
return AndroidResourceUtil.MyReferredResourceFieldInfo(resClassName, resFieldName, facet.module, false, fromManifest)
|
||||
}
|
||||
|
||||
private fun getReceiverAsSimpleNameExpression(exp: KtSimpleNameExpression): KtSimpleNameExpression? {
|
||||
val receiver = exp.getReceiverExpression()
|
||||
return when (receiver) {
|
||||
is KtSimpleNameExpression -> {
|
||||
receiver
|
||||
}
|
||||
is KtDotQualifiedExpression -> {
|
||||
receiver.selectorExpression as? KtSimpleNameExpression
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.android.quickfix
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.android.inspections.lint.AndroidLintQuickFix
|
||||
import org.jetbrains.android.inspections.lint.AndroidQuickfixContexts
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.codeInsight.surroundWith.statement.KotlinIfSurrounder
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.inspections.findExistingEditor
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
|
||||
class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix {
|
||||
|
||||
override fun apply(startElement: PsiElement, endElement: PsiElement, context: AndroidQuickfixContexts.Context) {
|
||||
val targetExpression = getTargetExpression(startElement)
|
||||
val project = targetExpression?.project ?: return
|
||||
val editor = targetExpression.findExistingEditor() ?: return
|
||||
|
||||
val file = targetExpression.containingFile
|
||||
val documentManager = PsiDocumentManager.getInstance(project)
|
||||
val document = documentManager.getDocument(file) ?: return
|
||||
|
||||
if (!FileModificationService.getInstance().prepareFileForWrite(file)) {
|
||||
return
|
||||
}
|
||||
|
||||
val surrounder = getSurrounder(targetExpression, "\"VERSION.SDK_INT < ${getVersionField(api, false)}\"")
|
||||
val conditionRange = surrounder.surroundElements(project, editor, arrayOf(targetExpression)) ?: return
|
||||
val conditionText = "android.os.Build.VERSION.SDK_INT >= ${getVersionField(api, true)}"
|
||||
document.replaceString(conditionRange.startOffset, conditionRange.endOffset, conditionText)
|
||||
documentManager.commitDocument(document)
|
||||
|
||||
ShortenReferences.DEFAULT.process(documentManager.getPsiFile(document) as KtFile,
|
||||
conditionRange.startOffset,
|
||||
conditionRange.startOffset + conditionText.length)
|
||||
}
|
||||
|
||||
override fun isApplicable(startElement: PsiElement, endElement: PsiElement, contextType: AndroidQuickfixContexts.ContextType): Boolean =
|
||||
getTargetExpression(startElement) != null
|
||||
|
||||
override fun getName(): String = "Surround with if (VERSION.SDK_INT >= VERSION_CODES.${getVersionField(api, false)}) { ... }"
|
||||
|
||||
private fun getTargetExpression(element: PsiElement): KtElement? {
|
||||
var current = PsiTreeUtil.getParentOfType(element, KtExpression::class.java)
|
||||
while (current != null) {
|
||||
if (current.parent is KtBlockExpression ||
|
||||
current.parent is KtContainerNode ||
|
||||
current.parent is KtWhenEntry ||
|
||||
current.parent is KtFunction ||
|
||||
current.parent is KtPropertyAccessor ||
|
||||
current.parent is KtProperty ||
|
||||
current.parent is KtReturnExpression ||
|
||||
current.parent is KtDestructuringDeclaration) {
|
||||
break
|
||||
}
|
||||
current = PsiTreeUtil.getParentOfType(current, KtExpression::class.java, true)
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
private fun getSurrounder(element: KtElement, todoText: String?): KotlinIfSurrounder {
|
||||
val used = element.analyze(BodyResolveMode.PARTIAL_WITH_CFA)[BindingContext.USED_AS_EXPRESSION, element] ?: false
|
||||
return if (used) {
|
||||
object : KotlinIfSurrounder() {
|
||||
override fun getCodeTemplate(): String = "if (a) { \n} else {\nTODO(${todoText ?: ""})\n}"
|
||||
}
|
||||
} else {
|
||||
KotlinIfSurrounder()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testRuntime(intellijDep())
|
||||
|
||||
compileOnly(project(":idea"))
|
||||
compileOnly(project(":idea:idea-jvm"))
|
||||
compile(project(":idea:kotlin-gradle-tooling"))
|
||||
|
||||
compile(project(":compiler:frontend"))
|
||||
compile(project(":compiler:frontend.java"))
|
||||
compile(project(":compiler:frontend.script"))
|
||||
|
||||
compile(project(":js:js.frontend"))
|
||||
|
||||
compileOnly(intellijDep())
|
||||
compileOnly(intellijPluginDep("gradle"))
|
||||
compileOnly(intellijPluginDep("Groovy"))
|
||||
compileOnly(intellijPluginDep("junit"))
|
||||
|
||||
testCompile(projectTests(":idea"))
|
||||
testCompile(projectTests(":idea:idea-test-framework"))
|
||||
|
||||
testCompile(intellijPluginDep("gradle"))
|
||||
testCompileOnly(intellijPluginDep("Groovy"))
|
||||
testCompileOnly(intellijDep())
|
||||
|
||||
testRuntime(projectDist(":kotlin-reflect"))
|
||||
testRuntime(project(":idea:idea-jvm"))
|
||||
testRuntime(project(":idea:idea-android"))
|
||||
testRuntime(project(":plugins:kapt3-idea"))
|
||||
testRuntime(project(":plugins:android-extensions-ide"))
|
||||
testRuntime(project(":plugins:lint"))
|
||||
testRuntime(project(":sam-with-receiver-ide-plugin"))
|
||||
testRuntime(project(":allopen-ide-plugin"))
|
||||
testRuntime(project(":noarg-ide-plugin"))
|
||||
// TODO: the order of the plugins matters here, consider avoiding order-dependency
|
||||
testRuntime(intellijPluginDep("junit"))
|
||||
testRuntime(intellijPluginDep("testng"))
|
||||
testRuntime(intellijPluginDep("properties"))
|
||||
testRuntime(intellijPluginDep("gradle"))
|
||||
testRuntime(intellijPluginDep("Groovy"))
|
||||
testRuntime(intellijPluginDep("coverage"))
|
||||
//testRuntime(intellijPluginDep("maven"))
|
||||
testRuntime(intellijPluginDep("android"))
|
||||
testRuntime(intellijPluginDep("smali"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" {
|
||||
projectDefault()
|
||||
resources.srcDir("res").apply { include("**") }
|
||||
}
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
testsJar()
|
||||
|
||||
projectTest {
|
||||
workingDir = rootDir
|
||||
useAndroidSdk()
|
||||
}
|
||||
|
||||
configureInstrumentation()
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* 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.idea.configuration
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||
import com.intellij.openapi.externalSystem.model.project.LibraryData
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||
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.module.isQualifiedModuleNamesEnabled
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.OrderRootType
|
||||
import com.intellij.openapi.roots.impl.libraries.LibraryEx
|
||||
import com.intellij.openapi.roots.impl.libraries.LibraryImpl
|
||||
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.util.PathUtil
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
|
||||
import org.jetbrains.kotlin.config.CoroutineSupport
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.TargetPlatformKind
|
||||
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
||||
import org.jetbrains.kotlin.gradle.ArgsInfo
|
||||
import org.jetbrains.kotlin.gradle.CompilerArgumentsBySourceSet
|
||||
import org.jetbrains.kotlin.idea.facet.*
|
||||
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
|
||||
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
|
||||
import org.jetbrains.kotlin.idea.framework.detectLibraryKind
|
||||
import org.jetbrains.kotlin.idea.inspections.gradle.findAll
|
||||
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
|
||||
import org.jetbrains.kotlin.idea.inspections.gradle.getResolvedKotlinStdlibVersionByModuleData
|
||||
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||
import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData
|
||||
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
var Module.compilerArgumentsBySourceSet
|
||||
by UserDataProperty(Key.create<CompilerArgumentsBySourceSet>("CURRENT_COMPILER_ARGUMENTS"))
|
||||
|
||||
var Module.sourceSetName
|
||||
by UserDataProperty(Key.create<String>("SOURCE_SET_NAME"))
|
||||
|
||||
interface GradleProjectImportHandler {
|
||||
companion object : ProjectExtensionDescriptor<GradleProjectImportHandler>(
|
||||
"org.jetbrains.kotlin.gradleProjectImportHandler",
|
||||
GradleProjectImportHandler::class.java
|
||||
)
|
||||
|
||||
fun importBySourceSet(facet: KotlinFacet, sourceSetNode: DataNode<GradleSourceSetData>)
|
||||
fun importByModule(facet: KotlinFacet, moduleNode: DataNode<ModuleData>)
|
||||
}
|
||||
|
||||
class KotlinGradleSourceSetDataService : 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) ?: continue
|
||||
val sourceSetName = sourceSetNode.data.id.let { it.substring(it.lastIndexOf(':') + 1) }
|
||||
val kotlinFacet = configureFacetByGradleModule(moduleNode, sourceSetName, 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, null, ideModule, modelsProvider) ?: continue
|
||||
GradleProjectImportHandler.getInstances(project).forEach { it.importByModule(kotlinFacet, moduleNode) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinGradleLibraryDataService : AbstractProjectDataService<LibraryData, Void>() {
|
||||
override fun getTargetDataKey() = ProjectKeys.LIBRARY
|
||||
|
||||
override fun postProcess(
|
||||
toImport: MutableCollection<DataNode<LibraryData>>,
|
||||
projectData: ProjectData?,
|
||||
project: Project,
|
||||
modelsProvider: IdeModifiableModelsProvider
|
||||
) {
|
||||
if (toImport.isEmpty()) return
|
||||
val projectDataNode = toImport.first().parent!!
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val moduleDataNodes = projectDataNode.children.filter { it.data is ModuleData } as List<DataNode<ModuleData>>
|
||||
val anyNonJvmModules = moduleDataNodes.any { detectPlatformByPlugin(it)?.takeIf { it !is TargetPlatformKind.Jvm } != null }
|
||||
for (libraryDataNode in toImport) {
|
||||
val ideLibrary = modelsProvider.findIdeLibrary(libraryDataNode.data) ?: continue
|
||||
|
||||
val modifiableModel = modelsProvider.getModifiableLibraryModel(ideLibrary) as LibraryEx.ModifiableModelEx
|
||||
if (anyNonJvmModules || ideLibrary.name?.looksAsNonJvmLibraryName() == true) {
|
||||
detectLibraryKind(modifiableModel.getFiles(OrderRootType.CLASSES))?.let { modifiableModel.kind = it }
|
||||
} else if (ideLibrary is LibraryImpl && (ideLibrary.kind === JSLibraryKind || ideLibrary.kind === CommonLibraryKind)) {
|
||||
resetLibraryKind(modifiableModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.looksAsNonJvmLibraryName() = nonJvmSuffixes.any { it in this }
|
||||
|
||||
private fun resetLibraryKind(modifiableModel: LibraryEx.ModifiableModelEx) {
|
||||
try {
|
||||
val cls = LibraryImpl::class.java
|
||||
// Don't use name-based lookup because field names are scrambled in IDEA Ultimate
|
||||
for (field in cls.declaredFields) {
|
||||
if (field.type == PersistentLibraryKind::class.java) {
|
||||
field.isAccessible = true
|
||||
field.set(modifiableModel, null)
|
||||
return
|
||||
}
|
||||
}
|
||||
LOG.info("Could not find field of type PersistentLibraryKind in LibraryImpl.class")
|
||||
} catch (e: Exception) {
|
||||
LOG.info("Failed to reset library kind", e)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOG = Logger.getInstance(KotlinGradleLibraryDataService::class.java)
|
||||
|
||||
val nonJvmSuffixes = listOf("-common", "-js", "-native", "-kjsm")
|
||||
}
|
||||
}
|
||||
|
||||
fun detectPlatformByPlugin(moduleNode: DataNode<ModuleData>): TargetPlatformKind<*>? {
|
||||
return when (moduleNode.platformPluginId) {
|
||||
"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<*>? {
|
||||
val detectedPlatforms =
|
||||
mavenLibraryIdToPlatform.entries
|
||||
.filter { moduleNode.getResolvedKotlinStdlibVersionByModuleData(listOf(it.key)) != null }
|
||||
.map { it.value }.distinct()
|
||||
return detectedPlatforms.singleOrNull() ?: detectedPlatforms.firstOrNull { it != TargetPlatformKind.Common }
|
||||
}
|
||||
|
||||
fun configureFacetByGradleModule(
|
||||
moduleNode: DataNode<ModuleData>,
|
||||
sourceSetName: String?,
|
||||
ideModule: Module,
|
||||
modelsProvider: IdeModifiableModelsProvider
|
||||
): KotlinFacet? {
|
||||
if (!moduleNode.isResolved) return null
|
||||
|
||||
if (!moduleNode.hasKotlinPlugin) {
|
||||
val facetModel = modelsProvider.getModifiableFacetModel(ideModule)
|
||||
val facet = facetModel.getFacetByType(KotlinFacetType.TYPE_ID)
|
||||
if (facet != null) {
|
||||
facetModel.removeFacet(facet)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
val compilerVersion = moduleNode.findAll(BuildScriptClasspathData.KEY).firstOrNull()?.data?.let(::findKotlinPluginVersion)
|
||||
?: return null
|
||||
val platformKind = detectPlatformByPlugin(moduleNode) ?: detectPlatformByLibrary(moduleNode)
|
||||
|
||||
val coroutinesProperty = CoroutineSupport.byCompilerArgument(
|
||||
moduleNode.coroutines ?: findKotlinCoroutinesProperty(ideModule.project)
|
||||
)
|
||||
|
||||
val kotlinFacet = ideModule.getOrCreateFacet(modelsProvider, false)
|
||||
kotlinFacet.configureFacet(compilerVersion, coroutinesProperty, platformKind, modelsProvider)
|
||||
|
||||
ideModule.compilerArgumentsBySourceSet = moduleNode.compilerArgumentsBySourceSet
|
||||
ideModule.sourceSetName = sourceSetName
|
||||
|
||||
val argsInfo = moduleNode.compilerArgumentsBySourceSet?.get(sourceSetName ?: "main")
|
||||
if (argsInfo != null) {
|
||||
configureFacetByCompilerArguments(kotlinFacet, argsInfo, modelsProvider)
|
||||
}
|
||||
|
||||
with(kotlinFacet.configuration.settings) {
|
||||
implementedModuleNames = getImplementedModuleNames(moduleNode, sourceSetName, ideModule.project)
|
||||
productionOutputPath = getExplicitOutputPath(moduleNode, platformKind, "main")
|
||||
testOutputPath = getExplicitOutputPath(moduleNode, platformKind, "test")
|
||||
}
|
||||
|
||||
kotlinFacet.noVersionAutoAdvance()
|
||||
|
||||
return kotlinFacet
|
||||
}
|
||||
|
||||
fun configureFacetByCompilerArguments(kotlinFacet: KotlinFacet, argsInfo: ArgsInfo, modelsProvider: IdeModifiableModelsProvider?) {
|
||||
val currentCompilerArguments = argsInfo.currentArguments
|
||||
val defaultCompilerArguments = argsInfo.defaultArguments
|
||||
val dependencyClasspath = argsInfo.dependencyClasspath.map { PathUtil.toSystemIndependentName(it) }
|
||||
if (currentCompilerArguments.isNotEmpty()) {
|
||||
parseCompilerArgumentsToFacet(currentCompilerArguments, defaultCompilerArguments, kotlinFacet, modelsProvider)
|
||||
}
|
||||
adjustClasspath(kotlinFacet, dependencyClasspath)
|
||||
}
|
||||
|
||||
private fun getImplementedModuleNames(moduleNode: DataNode<ModuleData>, sourceSetName: String?, project: Project): List<String> {
|
||||
val baseModuleNames = moduleNode.implementedModuleNames
|
||||
if (baseModuleNames.isEmpty() || sourceSetName == null) return baseModuleNames
|
||||
val delimiter = if(isQualifiedModuleNamesEnabled(project)) "." else "_"
|
||||
return baseModuleNames.map { "$it$delimiter$sourceSetName" }
|
||||
}
|
||||
|
||||
private fun getExplicitOutputPath(moduleNode: DataNode<ModuleData>, platformKind: TargetPlatformKind<*>?, sourceSet: String): String? {
|
||||
if (platformKind !== TargetPlatformKind.JavaScript) return null
|
||||
val k2jsArgumentList = moduleNode.compilerArgumentsBySourceSet?.get(sourceSet)?.currentArguments ?: return null
|
||||
return K2JSCompilerArguments().apply { parseCommandLineArguments(k2jsArgumentList, this) }.outputFile
|
||||
}
|
||||
|
||||
private fun adjustClasspath(kotlinFacet: KotlinFacet, dependencyClasspath: List<String>) {
|
||||
if (dependencyClasspath.isEmpty()) return
|
||||
val arguments = kotlinFacet.configuration.settings.compilerArguments as? K2JVMCompilerArguments ?: return
|
||||
val fullClasspath = arguments.classpath?.split(File.pathSeparator) ?: emptyList()
|
||||
if (fullClasspath.isEmpty()) return
|
||||
val newClasspath = fullClasspath - dependencyClasspath
|
||||
arguments.classpath = if (newClasspath.isNotEmpty()) newClasspath.joinToString(File.pathSeparator) else null
|
||||
}
|
||||
|
||||
private val gradlePropertyFiles = listOf("local.properties", "gradle.properties")
|
||||
|
||||
private fun findKotlinCoroutinesProperty(project: Project): String {
|
||||
for (propertyFileName in gradlePropertyFiles) {
|
||||
val propertyFile = project.baseDir.findChild(propertyFileName) ?: continue
|
||||
val properties = Properties()
|
||||
properties.load(propertyFile.inputStream)
|
||||
properties.getProperty("kotlin.coroutines")?.let { return it }
|
||||
}
|
||||
|
||||
return CoroutineSupport.getCompilerArgument(LanguageFeature.Coroutines.defaultState)
|
||||
}
|
||||
+375
@@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.configuration
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightUtilCore
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix
|
||||
import com.intellij.ide.actions.OpenFileAction
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.WritingAccessProvider
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.CoroutineSupport
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.idea.facet.getRuntimeLibraryVersion
|
||||
import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion
|
||||
import org.jetbrains.kotlin.idea.quickfix.ChangeCoroutineSupportFix
|
||||
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
|
||||
import org.jetbrains.kotlin.idea.versions.getStdlibArtifactId
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
|
||||
|
||||
override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus {
|
||||
val module = moduleSourceRootGroup.baseModule
|
||||
if (!isApplicable(module)) {
|
||||
return ConfigureKotlinStatus.NON_APPLICABLE
|
||||
}
|
||||
|
||||
if (moduleSourceRootGroup.sourceRootModules.all(::hasAnyKotlinRuntimeInScope)) {
|
||||
return ConfigureKotlinStatus.CONFIGURED
|
||||
}
|
||||
|
||||
val buildFiles = runReadAction {
|
||||
listOf(
|
||||
module.getBuildScriptPsiFile(),
|
||||
module.project.getTopLevelBuildScriptPsiFile()
|
||||
).filterNotNull()
|
||||
}
|
||||
|
||||
if (buildFiles.isEmpty()) {
|
||||
return ConfigureKotlinStatus.NON_APPLICABLE
|
||||
}
|
||||
|
||||
if (buildFiles.none { it.isConfiguredByAnyGradleConfigurator() }) {
|
||||
return ConfigureKotlinStatus.CAN_BE_CONFIGURED
|
||||
}
|
||||
|
||||
return ConfigureKotlinStatus.BROKEN
|
||||
}
|
||||
|
||||
private fun PsiFile.isConfiguredByAnyGradleConfigurator(): Boolean {
|
||||
return Extensions.getExtensions(KotlinProjectConfigurator.EP_NAME)
|
||||
.filterIsInstance<KotlinWithGradleConfigurator>()
|
||||
.any { it.isFileConfigured(this) }
|
||||
}
|
||||
|
||||
protected open fun isApplicable(module: Module): Boolean =
|
||||
module.getBuildSystemType() == Gradle
|
||||
|
||||
protected open fun getMinimumSupportedVersion() = "1.0.0"
|
||||
|
||||
private fun isFileConfigured(buildScript: PsiFile): Boolean = getManipulator(buildScript).isConfigured(kotlinPluginName)
|
||||
|
||||
@JvmSuppressWildcards
|
||||
override fun configure(project: Project, excludeModules: Collection<Module>) {
|
||||
val dialog = ConfigureDialogWithModulesAndVersion(project, this, excludeModules, getMinimumSupportedVersion())
|
||||
|
||||
dialog.show()
|
||||
if (!dialog.isOK) return
|
||||
|
||||
val collector = configureSilently(project, dialog.modulesToConfigure, dialog.kotlinVersion)
|
||||
collector.showNotification()
|
||||
}
|
||||
|
||||
fun configureSilently(project: Project, modules: List<Module>, version: String): NotificationMessageCollector {
|
||||
return project.executeCommand("Configure Kotlin") {
|
||||
val collector = createConfigureKotlinNotificationCollector(project)
|
||||
val changedFiles = configureWithVersion(project, modules, version, collector)
|
||||
|
||||
for (file in changedFiles) {
|
||||
OpenFileAction.openFile(file.virtualFile, project)
|
||||
}
|
||||
collector
|
||||
}
|
||||
}
|
||||
|
||||
fun configureWithVersion(
|
||||
project: Project,
|
||||
modulesToConfigure: List<Module>,
|
||||
kotlinVersion: String,
|
||||
collector: NotificationMessageCollector
|
||||
): HashSet<PsiFile> {
|
||||
val filesToOpen = HashSet<PsiFile>()
|
||||
val buildScript = project.getTopLevelBuildScriptPsiFile()
|
||||
if (buildScript != null && canConfigureFile(buildScript)) {
|
||||
val isModified = configureBuildScript(buildScript, true, kotlinVersion, collector)
|
||||
if (isModified) {
|
||||
filesToOpen.add(buildScript)
|
||||
}
|
||||
}
|
||||
|
||||
for (module in modulesToConfigure) {
|
||||
val file = module.getBuildScriptPsiFile()
|
||||
if (file != null && canConfigureFile(file)) {
|
||||
configureModule(module, file, false, kotlinVersion, collector, filesToOpen)
|
||||
} else {
|
||||
showErrorMessage(project, "Cannot find build.gradle file for module " + module.name)
|
||||
}
|
||||
}
|
||||
return filesToOpen
|
||||
}
|
||||
|
||||
open fun configureModule(
|
||||
module: Module,
|
||||
file: PsiFile,
|
||||
isTopLevelProjectFile: Boolean,
|
||||
version: String,
|
||||
collector: NotificationMessageCollector,
|
||||
filesToOpen: MutableCollection<PsiFile>
|
||||
) {
|
||||
val isModified = configureBuildScript(file, isTopLevelProjectFile, version, collector)
|
||||
if (isModified) {
|
||||
filesToOpen.add(file)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun configureModuleBuildScript(file: PsiFile, version: String): Boolean {
|
||||
val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk }
|
||||
val jvmTarget = getJvmTarget(sdk, version)
|
||||
return getManipulator(file).configureModuleBuildScript(
|
||||
kotlinPluginName,
|
||||
getStdlibArtifactName(sdk, version),
|
||||
version,
|
||||
jvmTarget
|
||||
)
|
||||
}
|
||||
|
||||
protected open fun getStdlibArtifactName(sdk: Sdk?, version: String) = getStdlibArtifactId(sdk, version)
|
||||
|
||||
protected open fun getJvmTarget(sdk: Sdk?, version: String): String? = null
|
||||
|
||||
protected abstract val kotlinPluginName: String
|
||||
|
||||
protected open fun addElementsToFile(
|
||||
file: PsiFile,
|
||||
isTopLevelProjectFile: Boolean,
|
||||
version: String
|
||||
): Boolean {
|
||||
if (!isTopLevelProjectFile) {
|
||||
var wasModified = configureProjectFile(file, version)
|
||||
wasModified = wasModified or configureModuleBuildScript(file, version)
|
||||
return wasModified
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun configureBuildScript(
|
||||
file: PsiFile,
|
||||
isTopLevelProjectFile: Boolean,
|
||||
version: String,
|
||||
collector: NotificationMessageCollector
|
||||
): Boolean {
|
||||
val isModified = file.project.executeWriteCommand("Configure ${file.name}", null) {
|
||||
val isModified = addElementsToFile(file, isTopLevelProjectFile, version)
|
||||
|
||||
CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(file)
|
||||
isModified
|
||||
}
|
||||
|
||||
val virtualFile = file.virtualFile
|
||||
if (virtualFile != null && isModified) {
|
||||
collector.addMessage(virtualFile.path + " was modified")
|
||||
}
|
||||
return isModified
|
||||
}
|
||||
|
||||
override fun updateLanguageVersion(
|
||||
module: Module,
|
||||
languageVersion: String?,
|
||||
apiVersion: String?,
|
||||
requiredStdlibVersion: ApiVersion,
|
||||
forTests: Boolean
|
||||
) {
|
||||
val runtimeUpdateRequired = getRuntimeLibraryVersion(module)?.let { ApiVersion.parse(it) }?.let { runtimeVersion ->
|
||||
runtimeVersion < requiredStdlibVersion
|
||||
} ?: false
|
||||
|
||||
if (runtimeUpdateRequired) {
|
||||
Messages.showErrorDialog(
|
||||
module.project,
|
||||
"This language feature requires version $requiredStdlibVersion or later of the Kotlin runtime library. " +
|
||||
"Please update the version in your build script.",
|
||||
"Update Language Version"
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val element = changeLanguageVersion(module, languageVersion, apiVersion, forTests)
|
||||
|
||||
element?.let {
|
||||
OpenFileDescriptor(module.project, it.containingFile.virtualFile, it.textRange.startOffset).navigate(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun changeCoroutineConfiguration(module: Module, state: LanguageFeature.State) {
|
||||
val runtimeUpdateRequired = state != LanguageFeature.State.DISABLED &&
|
||||
(getRuntimeLibraryVersion(module)?.startsWith("1.0") ?: false)
|
||||
|
||||
if (runtimeUpdateRequired) {
|
||||
Messages.showErrorDialog(
|
||||
module.project,
|
||||
"Coroutines support requires version 1.1 or later of the Kotlin runtime library. " +
|
||||
"Please update the version in your build script.",
|
||||
ChangeCoroutineSupportFix.getFixText(state)
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val element = changeCoroutineConfiguration(module, CoroutineSupport.getCompilerArgument(state))
|
||||
if (element != null) {
|
||||
OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addLibraryDependency(
|
||||
module: Module,
|
||||
element: PsiElement,
|
||||
library: ExternalLibraryDescriptor,
|
||||
libraryJarDescriptors: List<LibraryJarDescriptor>
|
||||
) {
|
||||
val scope = OrderEntryFix.suggestScopeByLocation(module, element)
|
||||
KotlinWithGradleConfigurator.addKotlinLibraryToModule(module, scope, library)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getManipulator(file: PsiFile): GradleBuildScriptManipulator = when (file) {
|
||||
is KtFile -> KotlinBuildScriptManipulator(file)
|
||||
is GroovyFile -> GroovyBuildScriptManipulator(file)
|
||||
else -> error("Unknown build script file type!")
|
||||
}
|
||||
|
||||
val GROUP_ID = "org.jetbrains.kotlin"
|
||||
val GRADLE_PLUGIN_ID = "kotlin-gradle-plugin"
|
||||
|
||||
val CLASSPATH = "classpath \"$GROUP_ID:$GRADLE_PLUGIN_ID:\$kotlin_version\""
|
||||
|
||||
private val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts"
|
||||
|
||||
fun getGroovyDependencySnippet(artifactName: String, scope: String) =
|
||||
"$scope \"org.jetbrains.kotlin:$artifactName:\$kotlin_version\""
|
||||
|
||||
fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'"
|
||||
|
||||
fun addKotlinLibraryToModule(module: Module, scope: DependencyScope, libraryDescriptor: ExternalLibraryDescriptor) {
|
||||
val buildScript = module.getBuildScriptPsiFile() ?: return
|
||||
if (!canConfigureFile(buildScript)) {
|
||||
return
|
||||
}
|
||||
|
||||
getManipulator(buildScript)
|
||||
.addKotlinLibraryToModuleBuildScript(scope, libraryDescriptor, module.getBuildSystemType() == AndroidGradle)
|
||||
|
||||
buildScript.virtualFile?.let {
|
||||
createConfigureKotlinNotificationCollector(buildScript.project)
|
||||
.addMessage(it.path + " was modified")
|
||||
.showNotification()
|
||||
}
|
||||
}
|
||||
|
||||
fun changeCoroutineConfiguration(module: Module, coroutineOption: String): PsiElement? = changeBuildGradle(module) {
|
||||
getManipulator(it).changeCoroutineConfiguration(coroutineOption)
|
||||
}
|
||||
|
||||
fun changeLanguageVersion(module: Module, languageVersion: String?, apiVersion: String?, forTests: Boolean) =
|
||||
changeBuildGradle(module) { buildScriptFile ->
|
||||
val manipulator = getManipulator(buildScriptFile)
|
||||
var result: PsiElement? = null
|
||||
if (languageVersion != null) {
|
||||
result = manipulator.changeLanguageVersion(languageVersion, forTests)
|
||||
}
|
||||
|
||||
if (apiVersion != null) {
|
||||
result = manipulator.changeApiVersion(apiVersion, forTests)
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
private fun changeBuildGradle(module: Module, body: (PsiFile) -> PsiElement?): PsiElement? {
|
||||
val buildScriptFile = module.getBuildScriptPsiFile()
|
||||
if (buildScriptFile != null && canConfigureFile(buildScriptFile)) {
|
||||
return buildScriptFile.project.executeWriteCommand("Change build.gradle configuration", null) {
|
||||
body(buildScriptFile)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun getKotlinStdlibVersion(module: Module): String? {
|
||||
return module.getBuildScriptPsiFile()?.let {
|
||||
getManipulator(it).getKotlinStdlibVersion()
|
||||
}
|
||||
}
|
||||
|
||||
fun configureProjectFile(file: PsiFile, version: String): Boolean = getManipulator(file).configureProjectBuildScript(version)
|
||||
|
||||
private fun canConfigureFile(file: PsiFile): Boolean = WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null)
|
||||
|
||||
private fun Module.getBuildScriptPsiFile() = getBuildScriptFile()?.getPsiFile(project)
|
||||
|
||||
private fun Project.getTopLevelBuildScriptPsiFile() = basePath?.let { findBuildGradleFile(it)?.getPsiFile(this) }
|
||||
|
||||
private fun Module.getBuildScriptFile(): File? {
|
||||
val moduleDir = File(moduleFilePath).parent
|
||||
findBuildGradleFile(moduleDir)?.let {
|
||||
return it
|
||||
}
|
||||
|
||||
ModuleRootManager.getInstance(this).contentRoots.forEach { root ->
|
||||
findBuildGradleFile(root.path)?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
||||
ExternalSystemApiUtil.getExternalProjectPath(this)?.let { externalProjectPath ->
|
||||
findBuildGradleFile(externalProjectPath)?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun findBuildGradleFile(path: String): File? =
|
||||
File(path + "/" + GradleConstants.DEFAULT_SCRIPT_NAME).takeIf { it.exists() }
|
||||
?: File(path + "/" + KOTLIN_BUILD_SCRIPT_NAME).takeIf { it.exists() }
|
||||
|
||||
private fun File.getPsiFile(project: Project) = VfsUtil.findFileByIoFile(this, true)?.let {
|
||||
PsiManager.getInstance(project).findFile(it)
|
||||
}
|
||||
|
||||
private fun showErrorMessage(project: Project, message: String?) {
|
||||
Messages.showErrorDialog(
|
||||
project,
|
||||
"<html>Couldn't configure kotlin-gradle plugin automatically.<br/>" +
|
||||
(if (message != null) message + "<br/>" else "") +
|
||||
"<br/>See manual installation instructions <a href=\"https://kotlinlang.org/docs/reference/using-gradle.html\">here</a>.</html>",
|
||||
"Configure Kotlin-Gradle Plugin"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1912
File diff suppressed because it is too large
Load Diff
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.framework;
|
||||
|
||||
import com.intellij.framework.library.LibraryVersionProperties;
|
||||
import com.intellij.openapi.roots.libraries.LibraryPresentationProvider;
|
||||
import com.intellij.openapi.roots.libraries.LibraryProperties;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.idea.KotlinIcons;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.List;
|
||||
|
||||
public class JavaRuntimePresentationProvider extends LibraryPresentationProvider<LibraryVersionProperties> {
|
||||
public static JavaRuntimePresentationProvider getInstance() {
|
||||
return LibraryPresentationProvider.EP_NAME.findExtension(JavaRuntimePresentationProvider.class);
|
||||
}
|
||||
|
||||
protected JavaRuntimePresentationProvider() {
|
||||
super(JavaRuntimeLibraryDescription.Companion.getKOTLIN_JAVA_RUNTIME_KIND());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Icon getIcon(@Nullable LibraryVersionProperties properties) {
|
||||
return KotlinIcons.SMALL_LOGO;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public LibraryVersionProperties detect(@NotNull List<VirtualFile> classesRoots) {
|
||||
String version = JavaRuntimeDetectionUtil.getJavaRuntimeVersion(classesRoots);
|
||||
return version == null ? null : new LibraryVersionProperties(version);
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
|
||||
import org.jetbrains.kotlin.idea.configuration.BuildSystemType
|
||||
import org.jetbrains.kotlin.idea.configuration.findApplicableConfigurator
|
||||
import org.jetbrains.kotlin.idea.configuration.getBuildSystemType
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
|
||||
sealed class ChangeCoroutineSupportFix(
|
||||
element: PsiElement,
|
||||
protected val coroutineSupport: LanguageFeature.State
|
||||
) : KotlinQuickFixAction<PsiElement>(element) {
|
||||
protected val coroutineSupportEnabled: Boolean
|
||||
get() = coroutineSupport == LanguageFeature.State.ENABLED || coroutineSupport == LanguageFeature.State.ENABLED_WITH_WARNING
|
||||
|
||||
class InModule(element: PsiElement, coroutineSupport: LanguageFeature.State) : ChangeCoroutineSupportFix(element, coroutineSupport) {
|
||||
override fun getText() = "${super.getText()} in the current module"
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(file) ?: return
|
||||
|
||||
findApplicableConfigurator(module).changeCoroutineConfiguration(module, coroutineSupport)
|
||||
}
|
||||
}
|
||||
|
||||
class InProject(element: PsiElement, coroutineSupport: LanguageFeature.State) : ChangeCoroutineSupportFix(element, coroutineSupport) {
|
||||
override fun getText() = "${super.getText()} in the project"
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
if (coroutineSupportEnabled) {
|
||||
if (!checkUpdateRuntime(project, LanguageFeature.Coroutines.sinceApiVersion)) return
|
||||
}
|
||||
|
||||
KotlinCommonCompilerArgumentsHolder.getInstance(project).update {
|
||||
coroutinesState = when (coroutineSupport) {
|
||||
LanguageFeature.State.ENABLED -> CommonCompilerArguments.ENABLE
|
||||
LanguageFeature.State.ENABLED_WITH_WARNING -> CommonCompilerArguments.WARN
|
||||
LanguageFeature.State.ENABLED_WITH_ERROR, LanguageFeature.State.DISABLED -> CommonCompilerArguments.ERROR
|
||||
}
|
||||
}
|
||||
ProjectRootManagerEx.getInstanceEx(project).makeRootsChange({}, false, true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun getFamilyName() = "Enable/Disable coroutine support"
|
||||
|
||||
override fun getText(): String {
|
||||
return getFixText(coroutineSupport)
|
||||
}
|
||||
|
||||
companion object : KotlinIntentionActionsFactory() {
|
||||
fun getFixText(state: LanguageFeature.State): String {
|
||||
return when (state) {
|
||||
LanguageFeature.State.ENABLED -> "Enable coroutine support"
|
||||
LanguageFeature.State.ENABLED_WITH_WARNING -> "Enable coroutine support (with warning)"
|
||||
LanguageFeature.State.ENABLED_WITH_ERROR, LanguageFeature.State.DISABLED -> "Disable coroutine support"
|
||||
}
|
||||
}
|
||||
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||
val newCoroutineSupports = when (diagnostic.factory) {
|
||||
Errors.EXPERIMENTAL_FEATURE_ERROR -> {
|
||||
if (Errors.EXPERIMENTAL_FEATURE_ERROR.cast(diagnostic).a.first != LanguageFeature.Coroutines) return emptyList()
|
||||
listOf(LanguageFeature.State.ENABLED_WITH_WARNING, LanguageFeature.State.ENABLED)
|
||||
}
|
||||
Errors.EXPERIMENTAL_FEATURE_WARNING -> {
|
||||
if (Errors.EXPERIMENTAL_FEATURE_WARNING.cast(diagnostic).a.first != LanguageFeature.Coroutines) return emptyList()
|
||||
listOf(LanguageFeature.State.ENABLED, LanguageFeature.State.ENABLED_WITH_ERROR)
|
||||
}
|
||||
else -> return emptyList()
|
||||
}
|
||||
val module = ModuleUtilCore.findModuleForPsiElement(diagnostic.psiElement) ?: return emptyList()
|
||||
val facetSettings = KotlinFacet.get(module)?.configuration?.settings
|
||||
|
||||
val configureInProject = (facetSettings == null || facetSettings.useProjectSettings) &&
|
||||
module.getBuildSystemType() == BuildSystemType.JPS
|
||||
val quickFixConstructor: (PsiElement, LanguageFeature.State) -> ChangeCoroutineSupportFix =
|
||||
if (configureInProject) ::InProject else ::InModule
|
||||
return newCoroutineSupports.map { quickFixConstructor(diagnostic.psiElement, it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(project(":core:util.runtime"))
|
||||
compile(project(":compiler:frontend"))
|
||||
compile(project(":compiler:frontend.java"))
|
||||
compile(project(":compiler:util"))
|
||||
compile(project(":compiler:cli-common"))
|
||||
compile(project(":kotlin-build-common"))
|
||||
|
||||
compile(project(":js:js.frontend"))
|
||||
|
||||
compile(project(":idea"))
|
||||
compile(project(":idea:idea-jvm"))
|
||||
compile(project(":idea:idea-jps-common"))
|
||||
|
||||
compileOnly(intellijDep())
|
||||
excludeInAndroidStudio(rootProject) { compileOnly(intellijPluginDep("maven")) }
|
||||
|
||||
testCompile(projectTests(":idea"))
|
||||
testCompile(projectTests(":compiler:tests-common"))
|
||||
testCompile(projectTests(":idea:idea-test-framework"))
|
||||
|
||||
testCompileOnly(intellijDep())
|
||||
//testCompileOnly(intellijPluginDep("maven"))
|
||||
|
||||
testRuntime(projectDist(":kotlin-reflect"))
|
||||
testRuntime(project(":idea:idea-jvm"))
|
||||
testRuntime(project(":idea:idea-android"))
|
||||
testRuntime(project(":plugins:android-extensions-ide"))
|
||||
testRuntime(project(":plugins:lint"))
|
||||
testRuntime(project(":sam-with-receiver-ide-plugin"))
|
||||
testRuntime(project(":allopen-ide-plugin"))
|
||||
testRuntime(project(":noarg-ide-plugin"))
|
||||
|
||||
testRuntime(intellijDep())
|
||||
// TODO: the order of the plugins matters here, consider avoiding order-dependency
|
||||
testRuntime(intellijPluginDep("junit"))
|
||||
testRuntime(intellijPluginDep("testng"))
|
||||
testRuntime(intellijPluginDep("properties"))
|
||||
testRuntime(intellijPluginDep("gradle"))
|
||||
testRuntime(intellijPluginDep("Groovy"))
|
||||
testRuntime(intellijPluginDep("coverage"))
|
||||
//testRuntime(intellijPluginDep("maven"))
|
||||
testRuntime(intellijPluginDep("android"))
|
||||
testRuntime(intellijPluginDep("smali"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { /*projectDefault()*/ }
|
||||
"test" { /*projectDefault()*/ }
|
||||
}
|
||||
|
||||
testsJar()
|
||||
|
||||
projectTest {
|
||||
workingDir = rootDir
|
||||
}
|
||||
+326
@@ -0,0 +1,326 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.maven.configuration
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightUtilCore
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix
|
||||
import com.intellij.ide.actions.OpenFileAction
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.openapi.command.WriteCommandAction
|
||||
import com.intellij.openapi.fileEditor.OpenFileDescriptor
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtilCore
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||
import com.intellij.openapi.roots.JavaProjectModelModificationService
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.vfs.WritingAccessProvider
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.search.FileTypeIndex
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.xml.XmlFile
|
||||
import org.jetbrains.idea.maven.dom.MavenDomUtil
|
||||
import org.jetbrains.idea.maven.dom.model.MavenDomPlugin
|
||||
import org.jetbrains.idea.maven.model.MavenId
|
||||
import org.jetbrains.idea.maven.project.MavenProjectsManager
|
||||
import org.jetbrains.idea.maven.utils.MavenArtifactScope
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.CoroutineSupport
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.idea.configuration.*
|
||||
import org.jetbrains.kotlin.idea.facet.getRuntimeLibraryVersion
|
||||
import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion
|
||||
import org.jetbrains.kotlin.idea.maven.*
|
||||
import org.jetbrains.kotlin.idea.quickfix.ChangeCoroutineSupportFix
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
|
||||
|
||||
abstract class KotlinMavenConfigurator
|
||||
protected constructor(
|
||||
private val testArtifactId: String?,
|
||||
private val addJunit: Boolean,
|
||||
override val name: String,
|
||||
override val presentableText: String
|
||||
) : KotlinProjectConfigurator {
|
||||
|
||||
override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus {
|
||||
val module = moduleSourceRootGroup.baseModule
|
||||
if (module.getBuildSystemType() != Maven)
|
||||
return ConfigureKotlinStatus.NON_APPLICABLE
|
||||
|
||||
val psi = runReadAction { findModulePomFile(module) }
|
||||
if (psi == null
|
||||
|| !psi.isValid
|
||||
|| psi !is XmlFile
|
||||
|| psi.virtualFile == null) {
|
||||
return ConfigureKotlinStatus.BROKEN
|
||||
}
|
||||
|
||||
if (isKotlinModule(module)) {
|
||||
return runReadAction { checkKotlinPlugin(module) }
|
||||
}
|
||||
return ConfigureKotlinStatus.CAN_BE_CONFIGURED
|
||||
}
|
||||
|
||||
private fun checkKotlinPlugin(module: Module): ConfigureKotlinStatus {
|
||||
val psi = findModulePomFile(module) as? XmlFile ?: return ConfigureKotlinStatus.BROKEN
|
||||
val pom = PomFile.forFileOrNull(psi) ?: return ConfigureKotlinStatus.NON_APPLICABLE
|
||||
|
||||
if (hasKotlinPlugin(pom)) {
|
||||
return ConfigureKotlinStatus.CONFIGURED
|
||||
}
|
||||
|
||||
val mavenProjectsManager = MavenProjectsManager.getInstance(module.project)
|
||||
val mavenProject = mavenProjectsManager.findProject(module) ?: return ConfigureKotlinStatus.BROKEN
|
||||
|
||||
val kotlinPluginId = kotlinPluginId(null)
|
||||
val kotlinPlugin = mavenProject.plugins.find { it.mavenId.equals(kotlinPluginId.groupId, kotlinPluginId.artifactId) }
|
||||
?: return ConfigureKotlinStatus.CAN_BE_CONFIGURED
|
||||
|
||||
if (kotlinPlugin.executions.any { it.goals.any(this::isRelevantGoal) }) {
|
||||
return ConfigureKotlinStatus.CONFIGURED
|
||||
}
|
||||
|
||||
return ConfigureKotlinStatus.CAN_BE_CONFIGURED
|
||||
}
|
||||
|
||||
private fun hasKotlinPlugin(pom: PomFile): Boolean {
|
||||
val plugin = pom.findPlugin(kotlinPluginId(null)) ?: return false
|
||||
|
||||
return plugin.executions.executions.any {
|
||||
it.goals.goals.any { isRelevantGoal(it.stringValue ?: "") }
|
||||
}
|
||||
}
|
||||
|
||||
override fun configure(project: Project, excludeModules: Collection<Module>) {
|
||||
val dialog = ConfigureDialogWithModulesAndVersion(project, this, excludeModules, getMinimumSupportedVersion())
|
||||
|
||||
dialog.show()
|
||||
if (!dialog.isOK) return
|
||||
|
||||
WriteCommandAction.runWriteCommandAction(project) {
|
||||
val collector = createConfigureKotlinNotificationCollector(project)
|
||||
for (module in excludeMavenChildrenModules(project, dialog.modulesToConfigure)) {
|
||||
val file = findModulePomFile(module)
|
||||
if (file != null && canConfigureFile(file)) {
|
||||
configureModule(module, file, dialog.kotlinVersion, collector)
|
||||
OpenFileAction.openFile(file.virtualFile, project)
|
||||
} else {
|
||||
showErrorMessage(project, "Cannot find pom.xml for module " + module.name)
|
||||
}
|
||||
}
|
||||
collector.showNotification()
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun getMinimumSupportedVersion() = "1.0.0"
|
||||
|
||||
protected abstract fun isKotlinModule(module: Module): Boolean
|
||||
protected abstract fun isRelevantGoal(goalName: String): Boolean
|
||||
|
||||
protected abstract fun createExecutions(pomFile: PomFile, kotlinPlugin: MavenDomPlugin, module: Module)
|
||||
protected abstract fun getStdlibArtifactId(module: Module, version: String): String
|
||||
|
||||
open fun configureModule(module: Module, file: PsiFile, version: String, collector: NotificationMessageCollector): Boolean =
|
||||
changePomFile(module, file, version, collector)
|
||||
|
||||
private fun changePomFile(
|
||||
module: Module,
|
||||
file: PsiFile,
|
||||
version: String,
|
||||
collector: NotificationMessageCollector
|
||||
): Boolean {
|
||||
val virtualFile = file.virtualFile ?: error("Virtual file should exists for psi file " + file.name)
|
||||
val domModel = MavenDomUtil.getMavenDomProjectModel(module.project, virtualFile)
|
||||
if (domModel == null) {
|
||||
showErrorMessage(module.project, null)
|
||||
return false
|
||||
}
|
||||
|
||||
val pom = PomFile.forFileOrNull(file as XmlFile) ?: return false
|
||||
pom.addProperty(KOTLIN_VERSION_PROPERTY, version)
|
||||
|
||||
pom.addDependency(
|
||||
MavenId(GROUP_ID, getStdlibArtifactId(module, version), "\${$KOTLIN_VERSION_PROPERTY}"),
|
||||
MavenArtifactScope.COMPILE,
|
||||
null,
|
||||
false,
|
||||
null
|
||||
)
|
||||
if (testArtifactId != null) {
|
||||
pom.addDependency(MavenId(GROUP_ID, testArtifactId, "\${$KOTLIN_VERSION_PROPERTY}"), MavenArtifactScope.TEST, null, false, null)
|
||||
}
|
||||
if (addJunit) {
|
||||
// TODO currently it is always disabled: junit version selection could be shown in the configurator dialog
|
||||
pom.addDependency(MavenId("junit", "junit", "4.12"), MavenArtifactScope.TEST, null, false, null)
|
||||
}
|
||||
|
||||
val repositoryDescription = getRepositoryForVersion(version)
|
||||
if (repositoryDescription != null) {
|
||||
pom.addLibraryRepository(repositoryDescription)
|
||||
pom.addPluginRepository(repositoryDescription)
|
||||
}
|
||||
|
||||
val plugin = pom.addPlugin(MavenId(GROUP_ID, MAVEN_PLUGIN_ID, "\${$KOTLIN_VERSION_PROPERTY}"))
|
||||
createExecutions(pom, plugin, module)
|
||||
|
||||
configurePlugin(pom, plugin, module, version)
|
||||
|
||||
CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement<PsiFile>(file)
|
||||
|
||||
collector.addMessage(virtualFile.path + " was modified")
|
||||
return true
|
||||
}
|
||||
|
||||
protected open fun configurePlugin(pom: PomFile, plugin: MavenDomPlugin, module: Module, version: String) {
|
||||
}
|
||||
|
||||
protected fun createExecution(
|
||||
pomFile: PomFile,
|
||||
kotlinPlugin: MavenDomPlugin,
|
||||
executionId: String,
|
||||
goalName: String,
|
||||
module: Module,
|
||||
isTest: Boolean
|
||||
) {
|
||||
pomFile.addKotlinExecution(module, kotlinPlugin, executionId, PomFile.getPhase(false, isTest), isTest, listOf(goalName))
|
||||
|
||||
if (hasJavaFiles(module)) {
|
||||
pomFile.addJavacExecutions(module, kotlinPlugin)
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateLanguageVersion(
|
||||
module: Module,
|
||||
languageVersion: String?,
|
||||
apiVersion: String?,
|
||||
requiredStdlibVersion: ApiVersion,
|
||||
forTests: Boolean
|
||||
) {
|
||||
fun doUpdateMavenLanguageVersion(): PsiElement? {
|
||||
val psi = KotlinMavenConfigurator.findModulePomFile(module) as? XmlFile ?: return null
|
||||
val pom = PomFile.forFileOrNull(psi) ?: return null
|
||||
return pom.changeLanguageVersion(
|
||||
languageVersion,
|
||||
apiVersion
|
||||
)
|
||||
}
|
||||
|
||||
val runtimeUpdateRequired = getRuntimeLibraryVersion(module)?.let { ApiVersion.parse(it) }?.let { runtimeVersion ->
|
||||
runtimeVersion < requiredStdlibVersion
|
||||
} ?: false
|
||||
|
||||
if (runtimeUpdateRequired) {
|
||||
Messages.showErrorDialog(
|
||||
module.project,
|
||||
"This language feature requires version $requiredStdlibVersion or later of the Kotlin runtime library. " +
|
||||
"Please update the version in your build script.",
|
||||
"Update Language Version"
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val element = doUpdateMavenLanguageVersion()
|
||||
if (element == null) {
|
||||
Messages.showErrorDialog(
|
||||
module.project,
|
||||
"Failed to update.pom.xml. Please update the file manually.",
|
||||
"Update Language Version"
|
||||
)
|
||||
} else {
|
||||
OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true)
|
||||
}
|
||||
}
|
||||
|
||||
override fun addLibraryDependency(
|
||||
module: Module,
|
||||
element: PsiElement,
|
||||
library: ExternalLibraryDescriptor,
|
||||
libraryJarDescriptors: List<LibraryJarDescriptor>
|
||||
) {
|
||||
val scope = OrderEntryFix.suggestScopeByLocation(module, element)
|
||||
JavaProjectModelModificationService.getInstance(module.project).addDependency(module, library, scope)
|
||||
}
|
||||
|
||||
override fun changeCoroutineConfiguration(module: Module, state: LanguageFeature.State) {
|
||||
val runtimeUpdateRequired = state != LanguageFeature.State.DISABLED &&
|
||||
(getRuntimeLibraryVersion(module)?.startsWith("1.0") ?: false)
|
||||
|
||||
val messageTitle = ChangeCoroutineSupportFix.getFixText(state)
|
||||
if (runtimeUpdateRequired) {
|
||||
Messages.showErrorDialog(
|
||||
module.project,
|
||||
"Coroutines support requires version 1.1 or later of the Kotlin runtime library. " +
|
||||
"Please update the version in your build script.",
|
||||
messageTitle
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val element = changeMavenCoroutineConfiguration(module, CoroutineSupport.getCompilerArgument(state), messageTitle)
|
||||
|
||||
if (element != null) {
|
||||
OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun changeMavenCoroutineConfiguration(module: Module, value: String, messageTitle: String): PsiElement? {
|
||||
fun doChangeMavenCoroutineConfiguration(): PsiElement? {
|
||||
val psi = KotlinMavenConfigurator.findModulePomFile(module) as? XmlFile ?: return null
|
||||
val pom = PomFile.forFileOrNull(psi) ?: return null
|
||||
return pom.changeCoroutineConfiguration(value)
|
||||
}
|
||||
|
||||
val element = doChangeMavenCoroutineConfiguration()
|
||||
if (element == null) {
|
||||
Messages.showErrorDialog(
|
||||
module.project,
|
||||
"Failed to update.pom.xml. Please update the file manually.",
|
||||
messageTitle
|
||||
)
|
||||
}
|
||||
return element
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val GROUP_ID = "org.jetbrains.kotlin"
|
||||
const val MAVEN_PLUGIN_ID = "kotlin-maven-plugin"
|
||||
private const val KOTLIN_VERSION_PROPERTY = "kotlin.version"
|
||||
|
||||
private fun hasJavaFiles(module: Module): Boolean {
|
||||
return !FileTypeIndex.getFiles(JavaFileType.INSTANCE, GlobalSearchScope.moduleScope(module)).isEmpty()
|
||||
}
|
||||
|
||||
private fun findModulePomFile(module: Module): PsiFile? {
|
||||
val files = MavenProjectsManager.getInstance(module.project).projectsFiles
|
||||
for (file in files) {
|
||||
val fileModule = ModuleUtilCore.findModuleForFile(file, module.project)
|
||||
if (module != fileModule) continue
|
||||
val psiFile = PsiManager.getInstance(module.project).findFile(file) ?: continue
|
||||
if (!MavenDomUtil.isProjectFile(psiFile)) continue
|
||||
return psiFile
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun canConfigureFile(file: PsiFile): Boolean {
|
||||
return WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null)
|
||||
}
|
||||
|
||||
private fun showErrorMessage(project: Project, message: String?) {
|
||||
Messages.showErrorDialog(
|
||||
project,
|
||||
"<html>Couldn't configure kotlin-maven plugin automatically.<br/>" +
|
||||
(if (message != null) "$message</br>" else "") +
|
||||
"See manual installation instructions <a href=\"http://confluence.jetbrains.com/display/Kotlin/Kotlin+Build+Tools#KotlinBuildTools-Maven\">here</a>.</html>",
|
||||
"Configure Kotlin-Maven Plugin"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<externalAnnotator language="kotlin" implementationClass="org.jetbrains.android.inspections.lint.AndroidLintExternalAnnotator"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -0,0 +1,120 @@
|
||||
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<xi:include href="android-lint.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.android.navigation.KotlinAndroidGotoDeclarationHandler"/>
|
||||
|
||||
<moduleService serviceInterface="org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager"
|
||||
serviceImplementation="org.jetbrains.kotlin.android.synthetic.idea.res.IDEAndroidLayoutXmlFileManager"/>
|
||||
<psi.treeChangePreprocessor implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidPsiTreeChangePreprocessor"/>
|
||||
<errorHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsReportSubmitter"/>
|
||||
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidGotoDeclarationHandler"/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.android.inspection.IllegalIdentifierInspection"
|
||||
displayName="Illegal Android Identifier"
|
||||
groupName="Kotlin Android"
|
||||
enabledByDefault="true"
|
||||
level="ERROR"/>
|
||||
|
||||
<localInspection implementationClass="org.jetbrains.kotlin.android.inspection.TypeParameterFindViewByIdInspection"
|
||||
displayName="Cast can be converted to findViewById with type parameter"
|
||||
groupName="Kotlin Android"
|
||||
enabledByDefault="true"
|
||||
cleanupTool="true"
|
||||
level="WEAK WARNING"
|
||||
language="kotlin" />
|
||||
|
||||
<codeInsight.lineMarkerProvider language="kotlin" implementationClass="org.jetbrains.kotlin.android.KotlinAndroidLineMarkerProvider"/>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.android.intention.KotlinAndroidAddStringResource</className>
|
||||
<category>Kotlin Android</category>
|
||||
</intentionAction>
|
||||
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinGradleAndroidModuleModelProjectDataService"/>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.android.intention.AddActivityToManifest</className>
|
||||
<category>Kotlin Android</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.android.intention.AddServiceToManifest</className>
|
||||
<category>Kotlin Android</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.android.intention.AddBroadcastReceiverToManifest</className>
|
||||
<category>Kotlin Android</category>
|
||||
</intentionAction>
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.android.intention.ImplementParcelableAction</className>
|
||||
<category>Kotlin Android</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.android.intention.RemoveParcelableAction</className>
|
||||
<category>Kotlin Android</category>
|
||||
</intentionAction>
|
||||
|
||||
<intentionAction>
|
||||
<className>org.jetbrains.kotlin.android.intention.RedoParcelableAction</className>
|
||||
<category>Kotlin Android</category>
|
||||
</intentionAction>
|
||||
|
||||
<codeInsight.unresolvedReferenceQuickFixProvider
|
||||
implementation="org.jetbrains.kotlin.android.inspection.KotlinAndroidResourceQuickFixProvider"/>
|
||||
|
||||
<lang.foldingBuilder language="kotlin" implementationClass="org.jetbrains.kotlin.android.folding.ResourceFoldingBuilder" />
|
||||
|
||||
<annotator language="kotlin" implementationClass="org.jetbrains.kotlin.android.AndroidResourceReferenceAnnotator" />
|
||||
|
||||
<referencesSearch implementation="org.jetbrains.kotlin.AndroidExtensionsReferenceSearchExecutor"/>
|
||||
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleLibraryDataService"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||
<projectResolve implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsProjectResolverExtension"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
<expressionCodegenExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.IDEAndroidExtensionsExpressionCodegenExtension"/>
|
||||
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.android.synthetic.AndroidExtensionPropertiesComponentContainerContributor"/>
|
||||
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.IDEAndroidOnDestroyClassBuilderInterceptorExtension"/>
|
||||
<packageFragmentProviderExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.res.IDEAndroidPackageFragmentProviderExtension"/>
|
||||
<simpleNameReferenceExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidSimpleNameReferenceExtension"/>
|
||||
<kotlinIndicesHelperExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidIndicesHelperExtension"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsGradleImportHandler"/>
|
||||
|
||||
<quickFixContributor implementation="org.jetbrains.kotlin.android.quickfix.AndroidQuickFixRegistrar"/>
|
||||
<projectConfigurator implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleModuleConfigurator"/>
|
||||
<gradleModelFacade implementation="org.jetbrains.kotlin.android.configure.AndroidGradleModelFacade"/>
|
||||
<completionInformationProvider implementation="org.jetbrains.kotlin.AndroidExtensionsCompletionInformationProvider" />
|
||||
|
||||
<expressionCodegenExtension implementation="org.jetbrains.kotlin.android.parcel.IDEParcelableCodegenExtension"/>
|
||||
<syntheticResolveExtension implementation="org.jetbrains.kotlin.android.parcel.IDEParcelableResolveExtension"/>
|
||||
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.codegen.ParcelableClinitClassBuilderInterceptorExtension"/>
|
||||
<quickFixContributor implementation="org.jetbrains.kotlin.android.parcel.quickfixes.ParcelableQuickFixContributor"/>
|
||||
|
||||
<androidDexer implementation="org.jetbrains.kotlin.android.debugger.AndroidDexerImpl"/>
|
||||
|
||||
<highlighterExtension implementation="org.jetbrains.kotlin.android.AndroidHighlighterExtension"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.android.tools.idea">
|
||||
<npw.template.convertJavaToKotlinProvider implementation="org.jetbrains.kotlin.android.ConvertJavaToKotlinProviderImpl"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.android">
|
||||
<androidLintQuickFixProvider implementation="org.jetbrains.kotlin.android.quickfix.KotlinAndroidQuickFixProvider" />
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.android.gradle.sync">
|
||||
<postSyncModuleSetupStep implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidModuleSetupStep"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin.android.model">
|
||||
<androidModuleInfoProvider implementation="org.jetbrains.kotlin.android.model.impl.AndroidModuleInfoProviderImpl"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -6,9 +6,10 @@
|
||||
<version>@snapshot@</version>
|
||||
<vendor url="http://www.jetbrains.com">JetBrains</vendor>
|
||||
|
||||
<idea-version since-build="173.4548.28" until-build="173.*"/>
|
||||
<idea-version since-build="181.1" until-build="181.*"/>
|
||||
|
||||
<depends>com.intellij.modules.platform</depends>
|
||||
<depends>com.intellij.modules.remoteServers</depends>
|
||||
|
||||
<!-- required for Kotlin/Native plugin -->
|
||||
<depends optional="true">org.jetbrains.kotlin.native.platform.deps</depends>
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.actions
|
||||
|
||||
import com.intellij.codeInsight.navigation.NavigationUtil
|
||||
import com.intellij.ide.scratch.ScratchFileService
|
||||
import com.intellij.ide.scratch.ScratchRootType
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||
import com.intellij.openapi.command.CommandProcessor
|
||||
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.ui.ex.MessagesEx
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileVisitor
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiErrorElement
|
||||
import com.intellij.psi.PsiJavaFile
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
|
||||
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
|
||||
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.j2k.ConverterSettings
|
||||
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
class JavaToKotlinAction : AnAction() {
|
||||
companion object {
|
||||
private fun uniqueKotlinFileName(javaFile: VirtualFile): String {
|
||||
val ioFile = File(javaFile.path.replace('/', File.separatorChar))
|
||||
|
||||
var i = 0
|
||||
while (true) {
|
||||
val fileName = javaFile.nameWithoutExtension + (if (i > 0) i else "") + ".kt"
|
||||
if (!ioFile.resolveSibling(fileName).exists()) return fileName
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
val title = "Convert Java to Kotlin"
|
||||
|
||||
private fun saveResults(javaFiles: List<PsiJavaFile>, convertedTexts: List<String>): List<VirtualFile> {
|
||||
val result = ArrayList<VirtualFile>()
|
||||
for ((psiFile, text) in javaFiles.zip(convertedTexts)) {
|
||||
try {
|
||||
val document = PsiDocumentManager.getInstance(psiFile.project).getDocument(psiFile)
|
||||
if (document == null) {
|
||||
MessagesEx.error(psiFile.project, "Failed to save conversion result: couldn't find document for " + psiFile.name).showLater()
|
||||
continue
|
||||
}
|
||||
document.replaceString(0, document.textLength, text)
|
||||
FileDocumentManager.getInstance().saveDocument(document)
|
||||
|
||||
val virtualFile = psiFile.virtualFile
|
||||
if (ScratchRootType.getInstance().containsFile(virtualFile)) {
|
||||
val mapping = ScratchFileService.getInstance().scratchesMapping
|
||||
mapping.setMapping(virtualFile, KotlinFileType.INSTANCE.language)
|
||||
}
|
||||
else {
|
||||
val fileName = uniqueKotlinFileName(virtualFile)
|
||||
virtualFile.rename(this, fileName)
|
||||
}
|
||||
}
|
||||
catch (e: IOException) {
|
||||
MessagesEx.error(psiFile.project, e.message ?: "").showLater()
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun convertFiles(javaFiles: List<PsiJavaFile>, project: Project,
|
||||
enableExternalCodeProcessing: Boolean = true,
|
||||
askExternalCodeProcessing: Boolean = true): List<KtFile> {
|
||||
var converterResult: JavaToKotlinConverter.FilesResult? = null
|
||||
fun convert() {
|
||||
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
|
||||
converterResult = converter.filesToKotlin(javaFiles, J2kPostProcessor(formatCode = true), ProgressManager.getInstance().progressIndicator!!)
|
||||
}
|
||||
|
||||
|
||||
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
||||
::convert,
|
||||
title,
|
||||
true,
|
||||
project)) return emptyList()
|
||||
|
||||
|
||||
var externalCodeUpdate: (() -> Unit)? = null
|
||||
|
||||
if (enableExternalCodeProcessing && converterResult!!.externalCodeProcessing != null) {
|
||||
val question = "Some code in the rest of your project may require corrections after performing this conversion. Do you want to find such code and correct it too?"
|
||||
if (!askExternalCodeProcessing || (Messages.showOkCancelDialog(project, question, title, Messages.getQuestionIcon()) == Messages.OK)) {
|
||||
ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
||||
{
|
||||
runReadAction {
|
||||
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(ProgressManager.getInstance().progressIndicator!!)
|
||||
}
|
||||
},
|
||||
title,
|
||||
true,
|
||||
project)
|
||||
}
|
||||
}
|
||||
|
||||
return project.executeWriteCommand("Convert files from Java to Kotlin", null) {
|
||||
CommandProcessor.getInstance().markCurrentCommandAsGlobal(project)
|
||||
|
||||
val newFiles = saveResults(javaFiles, converterResult!!.results)
|
||||
|
||||
externalCodeUpdate?.invoke()
|
||||
|
||||
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||
|
||||
newFiles.singleOrNull()?.let {
|
||||
FileEditorManager.getInstance(project).openFile(it, true)
|
||||
}
|
||||
|
||||
newFiles.map { it.toPsiFile(project) as KtFile }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun actionPerformed(e: AnActionEvent) {
|
||||
val javaFiles = selectedJavaFiles(e).filter { it.isWritable }.toList()
|
||||
val project = CommonDataKeys.PROJECT.getData(e.dataContext)!!
|
||||
|
||||
val firstSyntaxError = javaFiles.asSequence().map { PsiTreeUtil.findChildOfType(it, PsiErrorElement::class.java) }.firstOrNull()
|
||||
|
||||
if (firstSyntaxError != null) {
|
||||
val count = javaFiles.filter { PsiTreeUtil.hasErrorElements(it) }.count()
|
||||
val question = firstSyntaxError.containingFile.name +
|
||||
(if (count > 1) " and ${count - 1} more Java files" else " file") +
|
||||
" contain syntax errors, the conversion result may be incorrect"
|
||||
|
||||
val okText = "Investigate Errors"
|
||||
val cancelText = "Proceed with Conversion"
|
||||
if (Messages.showOkCancelDialog(
|
||||
project,
|
||||
question,
|
||||
title,
|
||||
okText,
|
||||
cancelText,
|
||||
Messages.getWarningIcon()
|
||||
) == Messages.OK) {
|
||||
NavigationUtil.activateFileWithPsiElement(firstSyntaxError.navigationElement)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
convertFiles(javaFiles, project)
|
||||
}
|
||||
|
||||
override fun update(e: AnActionEvent) {
|
||||
val virtualFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return
|
||||
val project = e.project ?: return
|
||||
|
||||
e.presentation.isEnabled = isAnyJavaFileSelected(project, virtualFiles)
|
||||
}
|
||||
|
||||
private fun isAnyJavaFileSelected(project: Project, files: Array<VirtualFile>): Boolean {
|
||||
val manager = PsiManager.getInstance(project)
|
||||
|
||||
if (files.any { manager.findFile(it) is PsiJavaFile && it.isWritable }) return true
|
||||
return files.any { it.isDirectory && isAnyJavaFileSelected(project, it.children) }
|
||||
}
|
||||
|
||||
private fun selectedJavaFiles(e: AnActionEvent): Sequence<PsiJavaFile> {
|
||||
val virtualFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return sequenceOf()
|
||||
val project = e.project ?: return sequenceOf()
|
||||
return allJavaFiles(virtualFiles, project)
|
||||
}
|
||||
|
||||
private fun allJavaFiles(filesOrDirs: Array<VirtualFile>, project: Project): Sequence<PsiJavaFile> {
|
||||
val manager = PsiManager.getInstance(project)
|
||||
return allFiles(filesOrDirs)
|
||||
.asSequence()
|
||||
.mapNotNull { manager.findFile(it) as? PsiJavaFile }
|
||||
}
|
||||
|
||||
private fun allFiles(filesOrDirs: Array<VirtualFile>): Collection<VirtualFile> {
|
||||
val result = ArrayList<VirtualFile>()
|
||||
for (file in filesOrDirs) {
|
||||
VfsUtilCore.visitChildrenRecursively(file, object : VirtualFileVisitor<Unit>() {
|
||||
override fun visitFile(file: VirtualFile): Boolean {
|
||||
result.add(file)
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* 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.idea.facet
|
||||
|
||||
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
|
||||
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.JavaSdk
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersion
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.roots.ModuleRootModel
|
||||
import com.intellij.openapi.roots.ProjectRootModificationTracker
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
|
||||
import org.jetbrains.kotlin.cli.common.arguments.*
|
||||
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.project.*
|
||||
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JsCompilerArgumentsHolder
|
||||
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JvmCompilerArgumentsHolder
|
||||
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
|
||||
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
|
||||
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.idea.versions.*
|
||||
import kotlin.reflect.KProperty1
|
||||
|
||||
private fun getDefaultTargetPlatform(module: Module, rootModel: ModuleRootModel?): TargetPlatformKind<*> {
|
||||
for (platform in TargetPlatformKind.ALL_PLATFORMS) {
|
||||
if (getRuntimeLibraryVersions(module, rootModel, platform).isNotEmpty()) {
|
||||
return platform
|
||||
}
|
||||
}
|
||||
|
||||
val sdk = ((rootModel ?: ModuleRootManager.getInstance(module))).sdk
|
||||
val sdkVersion = (sdk?.sdkType as? JavaSdk)?.getVersion(sdk!!)
|
||||
return when {
|
||||
sdkVersion == null || sdkVersion >= JavaSdkVersion.JDK_1_8 -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_8]
|
||||
else -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]
|
||||
}
|
||||
}
|
||||
|
||||
fun KotlinFacetSettings.initializeIfNeeded(
|
||||
module: Module,
|
||||
rootModel: ModuleRootModel?,
|
||||
platformKind: TargetPlatformKind<*>? = null, // if null, detect by module dependencies
|
||||
languageVersion: String? = null
|
||||
) {
|
||||
val project = module.project
|
||||
|
||||
val shouldInferLanguageLevel = languageLevel == null
|
||||
val shouldInferAPILevel = apiLevel == null
|
||||
|
||||
if (compilerSettings == null) {
|
||||
compilerSettings = KotlinCompilerSettings.getInstance(project).settings
|
||||
}
|
||||
|
||||
val commonArguments = KotlinCommonCompilerArgumentsHolder.getInstance(module.project).settings
|
||||
|
||||
if (compilerArguments == null) {
|
||||
val targetPlatformKind = platformKind ?: getDefaultTargetPlatform(module, rootModel)
|
||||
compilerArguments = targetPlatformKind.createCompilerArguments {
|
||||
targetPlatformKind.getPlatformCompilerArgumentsByProject(module.project)?.let { mergeBeans(it, this) }
|
||||
mergeBeans(commonArguments, this)
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldInferLanguageLevel) {
|
||||
languageLevel = (if (useProjectSettings) LanguageVersion.fromVersionString(commonArguments.languageVersion) else null)
|
||||
?: getDefaultLanguageLevel(module, languageVersion)
|
||||
}
|
||||
|
||||
if (shouldInferAPILevel) {
|
||||
apiLevel = if (useProjectSettings) {
|
||||
LanguageVersion.fromVersionString(commonArguments.apiVersion) ?: languageLevel
|
||||
}
|
||||
else {
|
||||
languageLevel!!.coerceAtMost(getLibraryLanguageLevel(module, rootModel, targetPlatformKind))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun TargetPlatformKind<*>.getPlatformCompilerArgumentsByProject(project: Project): CommonCompilerArguments? {
|
||||
return when (this) {
|
||||
is TargetPlatformKind.Jvm -> Kotlin2JvmCompilerArgumentsHolder.getInstance(project).settings
|
||||
is TargetPlatformKind.JavaScript -> Kotlin2JsCompilerArgumentsHolder.getInstance(project).settings
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
val TargetPlatformKind<*>.mavenLibraryIds: List<String>
|
||||
get() = when (this) {
|
||||
is TargetPlatformKind.Jvm -> listOf(MAVEN_STDLIB_ID, MAVEN_STDLIB_ID_JRE7, MAVEN_STDLIB_ID_JDK7, MAVEN_STDLIB_ID_JRE8, MAVEN_STDLIB_ID_JDK8)
|
||||
is TargetPlatformKind.JavaScript -> listOf(MAVEN_JS_STDLIB_ID, MAVEN_OLD_JS_STDLIB_ID)
|
||||
is TargetPlatformKind.Common -> listOf(MAVEN_COMMON_STDLIB_ID)
|
||||
}
|
||||
|
||||
val mavenLibraryIdToPlatform: Map<String, TargetPlatformKind<*>> by lazy {
|
||||
TargetPlatformKind.ALL_PLATFORMS
|
||||
.flatMap { platform -> platform.mavenLibraryIds.map { it to platform } }
|
||||
.sortedByDescending { it.first.length }
|
||||
.toMap()
|
||||
}
|
||||
|
||||
fun Module.getOrCreateFacet(modelsProvider: IdeModifiableModelsProvider,
|
||||
useProjectSettings: Boolean,
|
||||
commitModel: Boolean = false): KotlinFacet {
|
||||
val facetModel = modelsProvider.getModifiableFacetModel(this)
|
||||
|
||||
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
|
||||
if (commitModel) {
|
||||
runWriteAction {
|
||||
facetModel.commit()
|
||||
}
|
||||
}
|
||||
return facet
|
||||
}
|
||||
|
||||
fun KotlinFacet.configureFacet(
|
||||
compilerVersion: String,
|
||||
coroutineSupport: LanguageFeature.State,
|
||||
platformKind: TargetPlatformKind<*>?, // if null, detect by module dependencies
|
||||
modelsProvider: IdeModifiableModelsProvider
|
||||
) {
|
||||
val module = module
|
||||
with(configuration.settings) {
|
||||
compilerArguments = null
|
||||
compilerSettings = null
|
||||
initializeIfNeeded(
|
||||
module,
|
||||
modelsProvider.getModifiableRootModel(module),
|
||||
platformKind,
|
||||
compilerVersion
|
||||
)
|
||||
val apiLevel = apiLevel
|
||||
val languageLevel = languageLevel
|
||||
if (languageLevel != null && apiLevel != null && apiLevel > languageLevel) {
|
||||
this.apiLevel = languageLevel
|
||||
}
|
||||
this.coroutineSupport = coroutineSupport
|
||||
}
|
||||
}
|
||||
|
||||
fun KotlinFacet.noVersionAutoAdvance() {
|
||||
configuration.settings.compilerArguments?.let {
|
||||
it.autoAdvanceLanguageVersion = false
|
||||
it.autoAdvanceApiVersion = false
|
||||
}
|
||||
}
|
||||
|
||||
// "Primary" fields are written to argument beans directly and thus not presented in the "additional arguments" string
|
||||
// Update these lists when facet/project settings UI changes
|
||||
val commonUIExposedFields = listOf(CommonCompilerArguments::languageVersion.name,
|
||||
CommonCompilerArguments::apiVersion.name,
|
||||
CommonCompilerArguments::suppressWarnings.name,
|
||||
CommonCompilerArguments::coroutinesState.name)
|
||||
private val commonUIHiddenFields = listOf(CommonCompilerArguments::pluginClasspaths.name,
|
||||
CommonCompilerArguments::pluginOptions.name)
|
||||
private val commonPrimaryFields = commonUIExposedFields + commonUIHiddenFields
|
||||
|
||||
private val jvmSpecificUIExposedFields = listOf(K2JVMCompilerArguments::jvmTarget.name,
|
||||
K2JVMCompilerArguments::destination.name,
|
||||
K2JVMCompilerArguments::classpath.name)
|
||||
val jvmUIExposedFields = commonUIExposedFields + jvmSpecificUIExposedFields
|
||||
private val jvmPrimaryFields = commonPrimaryFields + jvmSpecificUIExposedFields
|
||||
|
||||
private val jsSpecificUIExposedFields = listOf(K2JSCompilerArguments::sourceMap.name,
|
||||
K2JSCompilerArguments::sourceMapPrefix.name,
|
||||
K2JSCompilerArguments::sourceMapEmbedSources.name,
|
||||
K2JSCompilerArguments::outputPrefix.name,
|
||||
K2JSCompilerArguments::outputPostfix.name,
|
||||
K2JSCompilerArguments::moduleKind.name)
|
||||
val jsUIExposedFields = commonUIExposedFields + jsSpecificUIExposedFields
|
||||
private val jsPrimaryFields = commonPrimaryFields + jsSpecificUIExposedFields
|
||||
|
||||
private val metadataSpecificUIExposedFields = listOf(K2MetadataCompilerArguments::destination.name,
|
||||
K2MetadataCompilerArguments::classpath.name)
|
||||
val metadataUIExposedFields = commonUIExposedFields + metadataSpecificUIExposedFields
|
||||
private val metadataPrimaryFields = commonPrimaryFields + metadataSpecificUIExposedFields
|
||||
|
||||
private val CommonCompilerArguments.primaryFields: List<String>
|
||||
get() = when (this) {
|
||||
is K2JVMCompilerArguments -> jvmPrimaryFields
|
||||
is K2JSCompilerArguments -> jsPrimaryFields
|
||||
is K2MetadataCompilerArguments -> metadataPrimaryFields
|
||||
else -> commonPrimaryFields
|
||||
}
|
||||
|
||||
private val CommonCompilerArguments.ignoredFields: List<String>
|
||||
get() = when (this) {
|
||||
is K2JVMCompilerArguments -> listOf(K2JVMCompilerArguments::noJdk.name, K2JVMCompilerArguments::jdkHome.name)
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
private fun Module.configureSdkIfPossible(compilerArguments: CommonCompilerArguments, modelsProvider: IdeModifiableModelsProvider) {
|
||||
val allSdks = ProjectJdkTable.getInstance().allJdks
|
||||
val sdk = if (compilerArguments is K2JVMCompilerArguments) {
|
||||
val jdkHome = compilerArguments.jdkHome ?: return
|
||||
allSdks.firstOrNull { it.sdkType is JavaSdk && FileUtil.comparePaths(it.homePath, jdkHome) == 0 } ?: return
|
||||
} else {
|
||||
allSdks.firstOrNull { it.sdkType is KotlinSdkType } ?: KotlinSdkType.INSTANCE.createSdkWithUniqueName(allSdks.toList())
|
||||
}
|
||||
|
||||
modelsProvider.getModifiableRootModel(this).sdk = sdk
|
||||
}
|
||||
|
||||
fun parseCompilerArgumentsToFacet(
|
||||
arguments: List<String>,
|
||||
defaultArguments: List<String>,
|
||||
kotlinFacet: KotlinFacet,
|
||||
modelsProvider: IdeModifiableModelsProvider?
|
||||
) {
|
||||
with(kotlinFacet.configuration.settings) {
|
||||
val compilerArguments = this.compilerArguments ?: return
|
||||
|
||||
val defaultCompilerArguments = compilerArguments::class.java.newInstance()
|
||||
parseCommandLineArguments(defaultArguments, defaultCompilerArguments)
|
||||
defaultCompilerArguments.convertPathsToSystemIndependent()
|
||||
|
||||
parseCommandLineArguments(arguments, compilerArguments)
|
||||
|
||||
compilerArguments.convertPathsToSystemIndependent()
|
||||
|
||||
// Retain only fields exposed (and not explicitly ignored) in facet configuration editor.
|
||||
// The rest is combined into string and stored in CompilerSettings.additionalArguments
|
||||
|
||||
if (modelsProvider != null)
|
||||
kotlinFacet.module.configureSdkIfPossible(compilerArguments, modelsProvider)
|
||||
|
||||
val primaryFields = compilerArguments.primaryFields
|
||||
val ignoredFields = compilerArguments.ignoredFields
|
||||
|
||||
fun exposeAsAdditionalArgument(property: KProperty1<CommonCompilerArguments, Any?>) =
|
||||
property.name !in primaryFields && property.get(compilerArguments) != property.get(defaultCompilerArguments)
|
||||
|
||||
val additionalArgumentsString = with(compilerArguments::class.java.newInstance()) {
|
||||
copyFieldsSatisfying(compilerArguments, this) { exposeAsAdditionalArgument(it) && it.name !in ignoredFields }
|
||||
ArgumentUtils.convertArgumentsToStringList(this).joinToString(separator = " ") {
|
||||
if (StringUtil.containsWhitespaces(it) || it.startsWith('"')) {
|
||||
StringUtil.wrapWithDoubleQuote(StringUtil.escapeQuotes(it))
|
||||
} else it
|
||||
}
|
||||
}
|
||||
compilerSettings?.additionalArguments =
|
||||
if (additionalArgumentsString.isNotEmpty()) additionalArgumentsString else CompilerSettings.DEFAULT_ADDITIONAL_ARGUMENTS
|
||||
|
||||
with(compilerArguments::class.java.newInstance()) {
|
||||
copyFieldsSatisfying(this, compilerArguments) { exposeAsAdditionalArgument(it) || it.name in ignoredFields }
|
||||
}
|
||||
|
||||
val languageLevel = languageLevel
|
||||
val apiLevel = apiLevel
|
||||
if (languageLevel != null && apiLevel != null && apiLevel > languageLevel) {
|
||||
this.apiLevel = languageLevel
|
||||
}
|
||||
|
||||
updateMergedArguments()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.reporter
|
||||
|
||||
import com.intellij.diagnostic.ITNReporter
|
||||
import com.intellij.openapi.diagnostic.IdeaLoggingEvent
|
||||
import com.intellij.openapi.diagnostic.SubmittedReportInfo
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.util.Consumer
|
||||
import org.jetbrains.kotlin.idea.KotlinPluginUpdater
|
||||
import org.jetbrains.kotlin.idea.KotlinPluginUtil
|
||||
import org.jetbrains.kotlin.idea.PluginUpdateStatus
|
||||
import org.jetbrains.kotlin.idea.actions.internal.KotlinInternalMode
|
||||
import java.awt.Component
|
||||
|
||||
/**
|
||||
* We need to wrap ITNReporter for force showing or errors from kotlin plugin even from released version of IDEA.
|
||||
*/
|
||||
class KotlinReportSubmitter : ITNReporter() {
|
||||
private var hasUpdate = false
|
||||
private var hasLatestVersion = false
|
||||
|
||||
override fun showErrorInRelease(event: IdeaLoggingEvent): Boolean {
|
||||
val notificationEnabled = "disabled" != System.getProperty("kotlin.fatal.error.notification", "enabled")
|
||||
return notificationEnabled && (!hasUpdate || KotlinInternalMode.enabled)
|
||||
}
|
||||
|
||||
override fun submit(events: Array<IdeaLoggingEvent>, additionalInfo: String?, parentComponent: Component?, consumer: Consumer<SubmittedReportInfo>): Boolean {
|
||||
if (hasUpdate) {
|
||||
if (KotlinInternalMode.enabled) {
|
||||
return super.submit(events, additionalInfo, parentComponent, consumer)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
if (hasLatestVersion) {
|
||||
return super.submit(events, additionalInfo, parentComponent, consumer)
|
||||
}
|
||||
|
||||
KotlinPluginUpdater.getInstance().runUpdateCheck { status ->
|
||||
if (status is PluginUpdateStatus.Update) {
|
||||
hasUpdate = true
|
||||
if (parentComponent != null) {
|
||||
|
||||
if (KotlinInternalMode.enabled) {
|
||||
super.submit(events, additionalInfo, parentComponent, consumer)
|
||||
}
|
||||
|
||||
val rc = Messages.showDialog(parentComponent,
|
||||
"You're running Kotlin plugin version ${KotlinPluginUtil.getPluginVersion()}, " +
|
||||
"while the latest version is ${status.pluginDescriptor.version}",
|
||||
"Update Kotlin Plugin",
|
||||
arrayOf("Update", "Ignore"),
|
||||
0, Messages.getInformationIcon())
|
||||
if (rc == 0) {
|
||||
KotlinPluginUpdater.getInstance().installPluginUpdate(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
hasLatestVersion = true
|
||||
super.submit(events, additionalInfo, parentComponent, consumer)
|
||||
}
|
||||
false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "class org.jetbrains.kotlin.idea.quickfix.AddArrayOfTypeFix" "false"
|
||||
// ACTION: Add 'value =' to argument
|
||||
// ACTION: Create test
|
||||
// ACTION: Do not show hints for current method
|
||||
// ACTION: Make internal
|
||||
// ACTION: Make private
|
||||
// ACTION: To raw string literal
|
||||
// ACTION: Do not show hints for current method
|
||||
|
||||
@ArrAnn(<caret>"123") class My
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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
|
||||
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
||||
import com.intellij.psi.codeStyle.PackageEntry
|
||||
import com.intellij.testFramework.LightProjectDescriptor
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
||||
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractImportsTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||
override fun getTestDataPath() = KotlinTestUtils.getHomeDirectory()
|
||||
override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||
|
||||
protected fun doTest(testPath: String) {
|
||||
val settingManager = CodeStyleSettingsManager.getInstance(project)
|
||||
val tempSettings = settingManager.currentSettings.clone()
|
||||
settingManager.setTemporarySettings(tempSettings)
|
||||
|
||||
val codeStyleSettings = KotlinCodeStyleSettings.getInstance(project)
|
||||
|
||||
try {
|
||||
val fixture = myFixture
|
||||
val dependencySuffixes = listOf(".dependency.kt", ".dependency.java", ".dependency1.kt", ".dependency2.kt")
|
||||
for (suffix in dependencySuffixes) {
|
||||
val dependencyPath = testPath.replace(".kt", suffix)
|
||||
if (File(dependencyPath).exists()) {
|
||||
fixture.configureByFile(dependencyPath)
|
||||
}
|
||||
}
|
||||
|
||||
fixture.configureByFile(testPath)
|
||||
|
||||
val file = fixture.file as KtFile
|
||||
|
||||
val fileText = file.text
|
||||
|
||||
codeStyleSettings.NAME_COUNT_TO_USE_STAR_IMPORT = InTextDirectivesUtils.getPrefixedInt(fileText, "// NAME_COUNT_TO_USE_STAR_IMPORT:") ?: nameCountToUseStarImportDefault
|
||||
codeStyleSettings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS = InTextDirectivesUtils.getPrefixedInt(fileText, "// NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS:") ?: nameCountToUseStarImportForMembersDefault
|
||||
codeStyleSettings.IMPORT_NESTED_CLASSES = InTextDirectivesUtils.getPrefixedBoolean(fileText, "// IMPORT_NESTED_CLASSES:") ?: false
|
||||
|
||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGE_TO_USE_STAR_IMPORTS:").forEach {
|
||||
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(PackageEntry(false, it.trim(), false))
|
||||
}
|
||||
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGES_TO_USE_STAR_IMPORTS:").forEach {
|
||||
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(PackageEntry(false, it.trim(), true))
|
||||
}
|
||||
|
||||
val log = project.executeWriteCommand<String?>("") { doTest(file) }
|
||||
|
||||
KotlinTestUtils.assertEqualsToFile(File(testPath + ".after"), myFixture.file.text)
|
||||
if (log != null) {
|
||||
val logFile = File(testPath + ".log")
|
||||
if (log.isNotEmpty()) {
|
||||
KotlinTestUtils.assertEqualsToFile(logFile, log)
|
||||
}
|
||||
else {
|
||||
TestCase.assertFalse(logFile.exists())
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
settingManager.dropTemporarySettings()
|
||||
}
|
||||
}
|
||||
|
||||
// returns test log
|
||||
protected abstract fun doTest(file: KtFile): String?
|
||||
|
||||
protected open val nameCountToUseStarImportDefault: Int
|
||||
get() = 1
|
||||
|
||||
protected open val nameCountToUseStarImportForMembersDefault: Int
|
||||
get() = 3
|
||||
}
|
||||
Reference in New Issue
Block a user