as32: Update to AS 3.2 C10

This commit is contained in:
Vyacheslav Gerasimov
2018-04-12 15:19:46 +03:00
parent 6fab21f916
commit 4299455dc1
98 changed files with 9321 additions and 7 deletions
+127
View File
@@ -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()
+74
View File
@@ -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 {}
@@ -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)
}
}
@@ -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;
@@ -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) }
}
}
@@ -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)
}
}
@@ -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) }
}
}
}
@@ -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
}
}
@@ -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()
}
}
}
+67
View File
@@ -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()
@@ -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)
}
@@ -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"
)
}
}
}
@@ -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);
}
}
@@ -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) }
}
}
}
+62
View File
@@ -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
}
@@ -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"
)
}
}
}
+5
View File
@@ -0,0 +1,5 @@
<idea-plugin>
<extensions defaultExtensionNs="com.intellij">
<externalAnnotator language="kotlin" implementationClass="org.jetbrains.android.inspections.lint.AndroidLintExternalAnnotator"/>
</extensions>
</idea-plugin>
+120
View File
@@ -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>
+2 -1
View File
@@ -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
}
}
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
View File
@@ -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
}