as32: Update to AS 3.2 C10
This commit is contained in:
@@ -0,0 +1,144 @@
|
|||||||
|
<project name="Kotlin CI Steps" default="none">
|
||||||
|
<import file="common.xml" optional="false"/>
|
||||||
|
<property name="kotlin-home" value="${output}/kotlinc"/>
|
||||||
|
|
||||||
|
<property name="build.number" value="snapshot"/>
|
||||||
|
<property name="fail.on.plugin.verifier.error" value="true"/>
|
||||||
|
|
||||||
|
<property name="version_substitute_dir" value="${basedir}/versions_temp/"/>
|
||||||
|
|
||||||
|
<property name="artifact.output.path" value="${basedir}/dist/artifacts/ideaPlugin"/>
|
||||||
|
<property name="plugin.xml" value="idea/src/META-INF/plugin.xml"/>
|
||||||
|
<property name="plugin.xml.bk" value="${version_substitute_dir}/plugin.xml.bk"/>
|
||||||
|
<property name="plugin.xml.versioned" value="${plugin.xml}.versioned"/>
|
||||||
|
<property name="plugin.xml.version.number" value="${build.number}"/>
|
||||||
|
|
||||||
|
<property name="compiler.version.java" value="core/util.runtime/src/org/jetbrains/kotlin/config/KotlinCompilerVersion.java"/>
|
||||||
|
<property name="compiler.version.java.bk" value="${version_substitute_dir}/KotlinCompilerVersion.java.bk"/>
|
||||||
|
<property name="compiler.version.java.versioned" value="${compiler.version.java}.versioned"/>
|
||||||
|
<property name="compiler.version.number" value="${build.number}"/>
|
||||||
|
<property name="compiler.ant.fork.jvmargs" value="-Xmx1024m"/>
|
||||||
|
|
||||||
|
<property name="plugin.zip" value="${artifact.output.path}/kotlin-plugin-${build.number}.zip"/>
|
||||||
|
<property name="pluginArtifactDir" value="Kotlin" />
|
||||||
|
|
||||||
|
<macrodef name="echoprop">
|
||||||
|
<attribute name="prop"/>
|
||||||
|
<sequential>
|
||||||
|
<echo>@{prop}=${@{prop}}</echo>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
<echoprop prop="os.name"/>
|
||||||
|
<echoprop prop="os.version"/>
|
||||||
|
<echoprop prop="os.arch"/>
|
||||||
|
<echoprop prop="java.home"/>
|
||||||
|
<echoprop prop="java.vendor"/>
|
||||||
|
<echoprop prop="java.version"/>
|
||||||
|
<echoprop prop="user.name"/>
|
||||||
|
<echoprop prop="user.home"/>
|
||||||
|
<echoprop prop="user.dir"/>
|
||||||
|
|
||||||
|
<macrodef name="run-gradle">
|
||||||
|
<attribute name="tasks" />
|
||||||
|
<attribute name="args" default="" />
|
||||||
|
<sequential>
|
||||||
|
<java classname="org.gradle.wrapper.GradleWrapperMain"
|
||||||
|
fork="true"
|
||||||
|
dir="${basedir}"
|
||||||
|
failonerror="true"
|
||||||
|
timeout="4000000"
|
||||||
|
maxmemory="400m"
|
||||||
|
taskname="gradle">
|
||||||
|
<classpath>
|
||||||
|
<pathelement location="${basedir}/gradle/wrapper/gradle-wrapper.jar"/>
|
||||||
|
</classpath>
|
||||||
|
<arg line="--no-daemon" />
|
||||||
|
<arg line="@{tasks}" />
|
||||||
|
<arg line="@{args}" />
|
||||||
|
</java>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
<target name="cleanupArtifacts">
|
||||||
|
<run-gradle tasks="cleanupArtifacts" />
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="zip-compiler">
|
||||||
|
<run-gradle tasks="zipCompiler" args="-PdeployVersion=${build.number}" />
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="zip-test-data">
|
||||||
|
<run-gradle tasks="zipTestData" />
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="writeCompilerVersionToTemplateFile">
|
||||||
|
<!-- empty, version is written in gradle build -->
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="writePluginVersionToTemplateFile">
|
||||||
|
<run-gradle tasks="writePluginVersion" args="-PpluginVersion=${plugin.xml.version.number}" />
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="zipArtifacts">
|
||||||
|
<run-gradle tasks="zipPlugin" args="-PpluginArtifactDir=${pluginArtifactDir} -PpluginZipPath=${plugin.zip}"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<macrodef name="print-statistic">
|
||||||
|
<attribute name="key"/>
|
||||||
|
<attribute name="value"/>
|
||||||
|
|
||||||
|
<sequential>
|
||||||
|
<echo message="##teamcity[buildStatisticValue key='@{key}' value='@{value}']"/>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
<macrodef name="print-file-size-statistic">
|
||||||
|
<attribute name="path"/>
|
||||||
|
<attribute name="file-name"/>
|
||||||
|
|
||||||
|
<sequential>
|
||||||
|
<local name="file.size"/>
|
||||||
|
<length file="@{path}/@{file-name}" property="file.size"/>
|
||||||
|
<print-statistic key="@{file-name} size" value="${file.size}"/>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
<target name="printStatistics">
|
||||||
|
<print-file-size-statistic path="${kotlin-home}/lib" file-name="kotlin-stdlib.jar"/>
|
||||||
|
<print-file-size-statistic path="${kotlin-home}/lib" file-name="kotlin-reflect.jar"/>
|
||||||
|
|
||||||
|
<print-file-size-statistic path="${kotlin-home}/lib" file-name="kotlin-stdlib-js.jar"/>
|
||||||
|
<print-file-size-statistic path="${js.stdlib.output.dir}" file-name="kotlin.js"/>
|
||||||
|
<print-file-size-statistic path="${js.stdlib.output.dir}" file-name="kotlin-test.js"/>
|
||||||
|
<print-file-size-statistic path="${basedir}/libraries/stdlib/js/build/classes/main" file-name="kotlin.meta.js"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="none">
|
||||||
|
<fail message="Either specify pre_build or post_build"/>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<macrodef name="patch_plugin_xml">
|
||||||
|
<attribute name="plugin.xml" />
|
||||||
|
<sequential>
|
||||||
|
<replace file="@{plugin.xml}" token="<!-- DEPENDS-ON-AS-PLACEHOLDER -->" value="<depends>com.intellij.modules.androidstudio</depends>"/>
|
||||||
|
</sequential>
|
||||||
|
</macrodef>
|
||||||
|
|
||||||
|
<target name="patchXmlForAndroidStudio">
|
||||||
|
<unzip src="${artifact.output.path}/Kotlin/lib/kotlin-plugin.jar" dest="tmpAndroidStudio">
|
||||||
|
<patternset>
|
||||||
|
<include name="META-INF/plugin.xml"/>
|
||||||
|
</patternset>
|
||||||
|
</unzip>
|
||||||
|
|
||||||
|
<patch_plugin_xml plugin.xml="tmpAndroidStudio/META-INF/plugin.xml"/>
|
||||||
|
|
||||||
|
<jar destfile="${artifact.output.path}/Kotlin/lib/kotlin-plugin.jar" update="true">
|
||||||
|
<fileset dir="tmpAndroidStudio"/>
|
||||||
|
<file file="META-INF/plugin.xml"/>
|
||||||
|
</jar>
|
||||||
|
|
||||||
|
<delete file="tmpAndroidStudio"/>
|
||||||
|
</target>
|
||||||
|
</project>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
org.gradle.daemon=true
|
||||||
|
org.gradle.parallel=false
|
||||||
|
org.gradle.configureondemand=false
|
||||||
|
org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx1600m
|
||||||
|
|
||||||
|
#buildSrc.kotlin.repo=https://jcenter.bintray.com
|
||||||
|
#buildSrc.kotlin.version=1.1.50
|
||||||
|
|
||||||
|
intellijUltimateEnabled=false
|
||||||
+335
@@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
* 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.cli.jvm.compiler
|
||||||
|
|
||||||
|
import com.intellij.openapi.vfs.StandardFileSystems
|
||||||
|
import com.intellij.openapi.vfs.VfsUtilCore
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.psi.PsiJavaModule
|
||||||
|
import com.intellij.openapi.vfs.VirtualFileManager
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.psi.impl.light.LightJavaModule
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.MessageUtil
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.config.JavaSourceRoot
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.config.JvmContentRoot
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.modules.JavaModuleGraph
|
||||||
|
import org.jetbrains.kotlin.config.ContentRoot
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.isValidJavaFqName
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.modules.KOTLIN_STDLIB_MODULE_NAME
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.jar.Attributes
|
||||||
|
import java.util.jar.Manifest
|
||||||
|
import kotlin.LazyThreadSafetyMode.NONE
|
||||||
|
|
||||||
|
class ClasspathRootsResolver(
|
||||||
|
private val psiManager: PsiManager,
|
||||||
|
private val messageCollector: MessageCollector?,
|
||||||
|
private val additionalModules: List<String>,
|
||||||
|
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?,
|
||||||
|
private val javaModuleFinder: CliJavaModuleFinder,
|
||||||
|
private val requireStdlibModule: Boolean,
|
||||||
|
private val outputDirectory: VirtualFile?
|
||||||
|
) {
|
||||||
|
val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
|
||||||
|
|
||||||
|
data class RootsAndModules(val roots: List<JavaRoot>, val modules: List<JavaModule>)
|
||||||
|
|
||||||
|
private data class RootWithPrefix(val root: VirtualFile, val packagePrefix: String?)
|
||||||
|
|
||||||
|
fun convertClasspathRoots(contentRoots: List<ContentRoot>): RootsAndModules {
|
||||||
|
val javaSourceRoots = mutableListOf<RootWithPrefix>()
|
||||||
|
val jvmClasspathRoots = mutableListOf<VirtualFile>()
|
||||||
|
val jvmModulePathRoots = mutableListOf<VirtualFile>()
|
||||||
|
|
||||||
|
for (contentRoot in contentRoots) {
|
||||||
|
if (contentRoot !is JvmContentRoot) continue
|
||||||
|
val root = contentRootToVirtualFile(contentRoot) ?: continue
|
||||||
|
when (contentRoot) {
|
||||||
|
is JavaSourceRoot -> javaSourceRoots += RootWithPrefix(root, contentRoot.packagePrefix)
|
||||||
|
is JvmClasspathRoot -> jvmClasspathRoots += root
|
||||||
|
is JvmModulePathRoot -> jvmModulePathRoots += root
|
||||||
|
else -> error("Unknown root type: $contentRoot")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return computeRoots(javaSourceRoots, jvmClasspathRoots, jvmModulePathRoots)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun computeRoots(
|
||||||
|
javaSourceRoots: List<RootWithPrefix>,
|
||||||
|
jvmClasspathRoots: List<VirtualFile>,
|
||||||
|
jvmModulePathRoots: List<VirtualFile>
|
||||||
|
): RootsAndModules {
|
||||||
|
val result = mutableListOf<JavaRoot>()
|
||||||
|
val modules = mutableListOf<JavaModule>()
|
||||||
|
|
||||||
|
val hasOutputDirectoryInClasspath = outputDirectory in jvmClasspathRoots || outputDirectory in jvmModulePathRoots
|
||||||
|
|
||||||
|
for ((root, packagePrefix) in javaSourceRoots) {
|
||||||
|
val modularRoot = modularSourceRoot(root, hasOutputDirectoryInClasspath)
|
||||||
|
if (modularRoot != null) {
|
||||||
|
modules += modularRoot
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += JavaRoot(root, JavaRoot.RootType.SOURCE, packagePrefix?.let { prefix ->
|
||||||
|
if (isValidJavaFqName(prefix)) FqName(prefix)
|
||||||
|
else null.also {
|
||||||
|
report(STRONG_WARNING, "Invalid package prefix name is ignored: $prefix")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (root in jvmClasspathRoots) {
|
||||||
|
result += JavaRoot(root, JavaRoot.RootType.BINARY)
|
||||||
|
}
|
||||||
|
|
||||||
|
val outputDirectoryAddedAsPartOfModule = modules.any { module -> module.moduleRoots.any { it.file == outputDirectory } }
|
||||||
|
|
||||||
|
for (root in jvmModulePathRoots) {
|
||||||
|
// Do not add output directory as a separate module if we're compiling an explicit named module.
|
||||||
|
// It's going to be included as a root of our module in modularSourceRoot.
|
||||||
|
if (outputDirectoryAddedAsPartOfModule && root == outputDirectory) continue
|
||||||
|
|
||||||
|
val module = modularBinaryRoot(root)
|
||||||
|
if (module != null) {
|
||||||
|
modules += module
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addModularRoots(modules, result)
|
||||||
|
|
||||||
|
return RootsAndModules(result, modules)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
private fun findSourceModuleInfo(root: VirtualFile): Pair<VirtualFile, PsiJavaModule>? {
|
||||||
|
val moduleInfoFile =
|
||||||
|
when {
|
||||||
|
root.isDirectory -> root.findChild(PsiJavaModule.MODULE_INFO_FILE)
|
||||||
|
root.name == PsiJavaModule.MODULE_INFO_FILE -> root
|
||||||
|
else -> null
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
val psiFile = psiManager.findFile(moduleInfoFile) ?: return null
|
||||||
|
val psiJavaModule = psiFile.children.singleOrNull { it is PsiJavaModule } as? PsiJavaModule ?: return null
|
||||||
|
|
||||||
|
return moduleInfoFile to psiJavaModule
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
private fun modularSourceRoot(root: VirtualFile, hasOutputDirectoryInClasspath: Boolean): JavaModule.Explicit? {
|
||||||
|
/*
|
||||||
|
val (moduleInfoFile, psiJavaModule) = findSourceModuleInfo(root) ?: return null
|
||||||
|
val sourceRoot = JavaModule.Root(root, isBinary = false)
|
||||||
|
val roots =
|
||||||
|
if (hasOutputDirectoryInClasspath)
|
||||||
|
listOf(sourceRoot, JavaModule.Root(outputDirectory!!, isBinary = true))
|
||||||
|
else listOf(sourceRoot)
|
||||||
|
return JavaModule.Explicit(JavaModuleInfo.create(psiJavaModule), roots, moduleInfoFile)
|
||||||
|
*/
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun modularBinaryRoot(root: VirtualFile): JavaModule? {
|
||||||
|
val isJar = root.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL
|
||||||
|
val manifest: Attributes? by lazy(NONE) { readManifestAttributes(root) }
|
||||||
|
|
||||||
|
/*
|
||||||
|
val moduleInfoFile =
|
||||||
|
root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE)
|
||||||
|
?: root.takeIf { isJar }?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)?.takeIf {
|
||||||
|
manifest?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true) == true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleInfoFile != null) {
|
||||||
|
val moduleInfo = JavaModuleInfo.read(moduleInfoFile) ?: return null
|
||||||
|
return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(root, isBinary = true)), moduleInfoFile)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Only .jar files can be automatic modules
|
||||||
|
if (isJar) {
|
||||||
|
val moduleRoot = listOf(JavaModule.Root(root, isBinary = true))
|
||||||
|
|
||||||
|
val automaticModuleName = manifest?.getValue(AUTOMATIC_MODULE_NAME)
|
||||||
|
if (automaticModuleName != null) {
|
||||||
|
return JavaModule.Automatic(automaticModuleName, moduleRoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
val originalFile = VfsUtilCore.virtualToIoFile(root)
|
||||||
|
val moduleName = LightJavaModule.moduleName(originalFile.nameWithoutExtension)
|
||||||
|
if (moduleName.isEmpty()) {
|
||||||
|
report(ERROR, "Cannot infer automatic module name for the file", VfsUtilCore.getVirtualFileForJar(root) ?: root)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return JavaModule.Automatic(moduleName, moduleRoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun readManifestAttributes(jarRoot: VirtualFile): Attributes? {
|
||||||
|
val manifestFile = jarRoot.findChild("META-INF")?.findChild("MANIFEST.MF")
|
||||||
|
return try {
|
||||||
|
manifestFile?.inputStream?.let(::Manifest)?.mainAttributes
|
||||||
|
}
|
||||||
|
catch (e: IOException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addModularRoots(modules: List<JavaModule>, result: MutableList<JavaRoot>) {
|
||||||
|
// In current implementation, at most one source module is supported. This can be relaxed in the future if we support another
|
||||||
|
// compilation mode, similar to java's --module-source-path
|
||||||
|
val sourceModules = modules.filterIsInstance<JavaModule.Explicit>().filter(JavaModule::isSourceModule)
|
||||||
|
if (sourceModules.size > 1) {
|
||||||
|
for (module in sourceModules) {
|
||||||
|
report(ERROR, "Too many source module declarations found", module.moduleInfoFile)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (module in modules) {
|
||||||
|
val existing = javaModuleFinder.findModule(module.name)
|
||||||
|
if (existing == null) {
|
||||||
|
javaModuleFinder.addUserModule(module)
|
||||||
|
}
|
||||||
|
else if (module.moduleRoots != existing.moduleRoots) {
|
||||||
|
fun JavaModule.getRootFile() =
|
||||||
|
moduleRoots.firstOrNull()?.file?.let { VfsUtilCore.getVirtualFileForJar(it) ?: it }
|
||||||
|
|
||||||
|
val thisFile = module.getRootFile()
|
||||||
|
val existingFile = existing.getRootFile()
|
||||||
|
val atExistingPath = if (existingFile == null) "" else " at: ${existingFile.path}"
|
||||||
|
report(STRONG_WARNING, "The root is ignored because a module with the same name '${module.name}' " +
|
||||||
|
"has been found earlier on the module path$atExistingPath", thisFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (javaModuleFinder.allObservableModules.none()) return
|
||||||
|
|
||||||
|
val sourceModule = sourceModules.singleOrNull()
|
||||||
|
val addAllModulePathToRoots = "ALL-MODULE-PATH" in additionalModules
|
||||||
|
if (addAllModulePathToRoots && sourceModule != null) {
|
||||||
|
report(ERROR, "-Xadd-modules=ALL-MODULE-PATH can only be used when compiling the unnamed module")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val rootModules = when {
|
||||||
|
sourceModule != null -> listOf(sourceModule.name) + additionalModules
|
||||||
|
addAllModulePathToRoots -> modules.map(JavaModule::name)
|
||||||
|
else -> computeDefaultRootModules() + additionalModules
|
||||||
|
}
|
||||||
|
|
||||||
|
val allDependencies = javaModuleGraph.getAllDependencies(rootModules)
|
||||||
|
if (allDependencies.any { moduleName -> javaModuleFinder.findModule(moduleName) is JavaModule.Automatic }) {
|
||||||
|
// According to java.lang.module javadoc, if at least one automatic module is added to the module graph,
|
||||||
|
// all observable automatic modules should be added.
|
||||||
|
// There are no automatic modules in the JDK, so we select all automatic modules out of user modules
|
||||||
|
for (module in modules) {
|
||||||
|
if (module is JavaModule.Automatic) {
|
||||||
|
allDependencies += module.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
report(LOGGING, "Loading modules: $allDependencies")
|
||||||
|
|
||||||
|
for (moduleName in allDependencies) {
|
||||||
|
val module = javaModuleFinder.findModule(moduleName)
|
||||||
|
if (module == null) {
|
||||||
|
report(ERROR, "Module $moduleName cannot be found in the module graph")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for ((root, isBinary) in module.moduleRoots) {
|
||||||
|
result.add(JavaRoot(root, if (isBinary) JavaRoot.RootType.BINARY else JavaRoot.RootType.SOURCE))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requireStdlibModule && sourceModule != null && !javaModuleGraph.reads(sourceModule.name, KOTLIN_STDLIB_MODULE_NAME)) {
|
||||||
|
report(
|
||||||
|
ERROR,
|
||||||
|
"The Kotlin standard library is not found in the module graph. " +
|
||||||
|
"Please ensure you have the 'requires $KOTLIN_STDLIB_MODULE_NAME' clause in your module definition",
|
||||||
|
sourceModule.moduleInfoFile
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See http://openjdk.java.net/jeps/261
|
||||||
|
private fun computeDefaultRootModules(): List<String> {
|
||||||
|
val result = arrayListOf<String>()
|
||||||
|
|
||||||
|
val systemModules = javaModuleFinder.systemModules.associateBy(JavaModule::name)
|
||||||
|
val javaSeExists = "java.se" in systemModules
|
||||||
|
if (javaSeExists) {
|
||||||
|
// The java.se module is a root, if it exists.
|
||||||
|
result.add("java.se")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun JavaModule.Explicit.exportsAtLeastOnePackageUnqualified(): Boolean = moduleInfo.exports.any { it.toModules.isEmpty() }
|
||||||
|
|
||||||
|
if (!javaSeExists) {
|
||||||
|
// If it does not exist then every java.* module on the upgrade module path or among the system modules
|
||||||
|
// that exports at least one package, without qualification, is a root.
|
||||||
|
for ((name, module) in systemModules) {
|
||||||
|
if (name.startsWith("java.") && module.exportsAtLeastOnePackageUnqualified()) {
|
||||||
|
result.add(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((name, module) in systemModules) {
|
||||||
|
// Every non-java.* module on the upgrade module path or among the system modules that exports at least one package,
|
||||||
|
// without qualification, is also a root.
|
||||||
|
if (!name.startsWith("java.") && module.exportsAtLeastOnePackageUnqualified()) {
|
||||||
|
result.add(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun report(severity: CompilerMessageSeverity, message: String, file: VirtualFile? = null) {
|
||||||
|
if (messageCollector == null) {
|
||||||
|
throw IllegalStateException("${if (file != null) file.path + ":" else ""}$severity: $message (no MessageCollector configured)")
|
||||||
|
}
|
||||||
|
messageCollector.report(
|
||||||
|
severity, message,
|
||||||
|
if (file == null) null else CompilerMessageLocation.create(MessageUtil.virtualFileToPath(file))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val MULTI_RELEASE_MODULE_INFO_CLS_FILE = "META-INF/versions/9/${PsiJavaModule.MODULE_INFO_CLS_FILE}"
|
||||||
|
const val AUTOMATIC_MODULE_NAME = "Automatic-Module-Name"
|
||||||
|
const val IS_MULTI_RELEASE = "Multi-Release"
|
||||||
|
}
|
||||||
|
}
|
||||||
+302
@@ -0,0 +1,302 @@
|
|||||||
|
/*
|
||||||
|
* 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.cli.jvm.compiler
|
||||||
|
|
||||||
|
import com.intellij.core.CoreJavaFileManager
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.psi.*
|
||||||
|
import com.intellij.psi.impl.file.PsiPackageImpl
|
||||||
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
|
import gnu.trove.THashMap
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.index.SingleJavaFileRootsIndex
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryClassSignatureParser
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.ClassifierResolutionContext
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.isNotTopLevelClass
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager
|
||||||
|
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
// TODO: do not inherit from CoreJavaFileManager to avoid accidental usage of its methods which do not use caches/indices
|
||||||
|
// Currently, the only relevant usage of this class as CoreJavaFileManager is at CoreJavaDirectoryService.getPackage,
|
||||||
|
// which is indirectly invoked from PsiPackage.getSubPackages
|
||||||
|
class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJavaFileManager(myPsiManager), KotlinCliJavaFileManager {
|
||||||
|
private val perfCounter = PerformanceCounter.create("Find Java class")
|
||||||
|
private lateinit var index: JvmDependenciesIndex
|
||||||
|
private lateinit var singleJavaFileRootsIndex: SingleJavaFileRootsIndex
|
||||||
|
private lateinit var packagePartProviders: List<JvmPackagePartProvider>
|
||||||
|
private val topLevelClassesCache: MutableMap<FqName, VirtualFile?> = THashMap()
|
||||||
|
private val allScope = GlobalSearchScope.allScope(myPsiManager.project)
|
||||||
|
private var useFastClassFilesReading = false
|
||||||
|
|
||||||
|
fun initialize(
|
||||||
|
index: JvmDependenciesIndex,
|
||||||
|
packagePartProviders: List<JvmPackagePartProvider>,
|
||||||
|
singleJavaFileRootsIndex: SingleJavaFileRootsIndex,
|
||||||
|
useFastClassFilesReading: Boolean
|
||||||
|
) {
|
||||||
|
this.index = index
|
||||||
|
this.packagePartProviders = packagePartProviders
|
||||||
|
this.singleJavaFileRootsIndex = singleJavaFileRootsIndex
|
||||||
|
this.useFastClassFilesReading = useFastClassFilesReading
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findPsiClass(classId: ClassId, searchScope: GlobalSearchScope): PsiClass? = perfCounter.time {
|
||||||
|
findVirtualFileForTopLevelClass(classId, searchScope)?.findPsiClassInVirtualFile(classId.relativeClassName.asString())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findVirtualFileForTopLevelClass(classId: ClassId, searchScope: GlobalSearchScope): VirtualFile? {
|
||||||
|
val relativeClassName = classId.relativeClassName.asString()
|
||||||
|
return topLevelClassesCache.getOrPut(classId.packageFqName.child(classId.relativeClassName.pathSegments().first())) {
|
||||||
|
index.findClass(classId) { dir, type ->
|
||||||
|
findVirtualFileGivenPackage(dir, relativeClassName, type)
|
||||||
|
}
|
||||||
|
?: singleJavaFileRootsIndex.findJavaSourceClass(classId)
|
||||||
|
}?.takeIf { it in searchScope }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap()
|
||||||
|
private val signatureParsingComponent =
|
||||||
|
BinaryClassSignatureParser()
|
||||||
|
|
||||||
|
override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? {
|
||||||
|
val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null
|
||||||
|
|
||||||
|
if (useFastClassFilesReading && virtualFile.extension == "class") {
|
||||||
|
// We return all class files' names in the directory in knownClassNamesInPackage method, so one may request an inner class
|
||||||
|
return binaryCache.getOrPut(classId) {
|
||||||
|
// Note that currently we implicitly suppose that searchScope for binary classes is constant and we do not use it
|
||||||
|
// as a key in cache
|
||||||
|
// This is a true assumption by now since there are two search scopes in compiler: one for sources and another one for binary
|
||||||
|
// When it become wrong because we introduce the modules into CLI, it's worth to consider
|
||||||
|
// having different KotlinCliJavaFileManagerImpl's for different modules
|
||||||
|
val classContent = virtualFile.contentsToByteArray()
|
||||||
|
if (virtualFile.nameWithoutExtension.contains("$") && isNotTopLevelClass(classContent)) return@getOrPut null
|
||||||
|
classId.outerClassId?.let { outerClassId ->
|
||||||
|
val outerClass = findClass(outerClassId, searchScope)
|
||||||
|
return@getOrPut outerClass?.findInnerClass(classId.shortClassName)
|
||||||
|
}
|
||||||
|
|
||||||
|
val resolver = ClassifierResolutionContext { findClass(it, allScope) }
|
||||||
|
|
||||||
|
BinaryJavaClass(
|
||||||
|
virtualFile,
|
||||||
|
classId.asSingleFqName(),
|
||||||
|
resolver,
|
||||||
|
signatureParsingComponent,
|
||||||
|
outerClass = null,
|
||||||
|
classContent = classContent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return virtualFile.findPsiClassInVirtualFile(classId.relativeClassName.asString())?.let(::JavaClassImpl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// this method is called from IDEA to resolve dependencies in Java code
|
||||||
|
// which supposedly shouldn't have errors so the dependencies exist in general
|
||||||
|
override fun findClass(qName: String, scope: GlobalSearchScope): PsiClass? {
|
||||||
|
// String cannot be reliably converted to ClassId because we don't know where the package name ends and class names begin.
|
||||||
|
// For example, if qName is "a.b.c.d.e", we should either look for a top level class "e" in the package "a.b.c.d",
|
||||||
|
// or, for example, for a nested class with the relative qualified name "c.d.e" in the package "a.b".
|
||||||
|
// Below, we start by looking for the top level class "e" in the package "a.b.c.d" first, then for the class "d.e" in the package
|
||||||
|
// "a.b.c", and so on, until we find something. Most classes are top level, so most of the times the search ends quickly
|
||||||
|
|
||||||
|
forEachClassId(qName) { classId ->
|
||||||
|
findPsiClass(classId, scope)?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun forEachClassId(fqName: String, block: (ClassId) -> Unit) {
|
||||||
|
var classId = fqName.toSafeTopLevelClassId() ?: return
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
block(classId)
|
||||||
|
|
||||||
|
val packageFqName = classId.packageFqName
|
||||||
|
if (packageFqName.isRoot) break
|
||||||
|
|
||||||
|
classId = ClassId(
|
||||||
|
packageFqName.parent(),
|
||||||
|
FqName(packageFqName.shortName().asString() + "." + classId.relativeClassName.asString()),
|
||||||
|
false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findClasses(qName: String, scope: GlobalSearchScope): Array<PsiClass> = perfCounter.time {
|
||||||
|
val result = ArrayList<PsiClass>(1)
|
||||||
|
forEachClassId(qName) { classId ->
|
||||||
|
val relativeClassName = classId.relativeClassName.asString()
|
||||||
|
index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType ->
|
||||||
|
val psiClass =
|
||||||
|
findVirtualFileGivenPackage(dir, relativeClassName, rootType)
|
||||||
|
?.takeIf { it in scope }
|
||||||
|
?.findPsiClassInVirtualFile(relativeClassName)
|
||||||
|
if (psiClass != null) {
|
||||||
|
result.add(psiClass)
|
||||||
|
}
|
||||||
|
// traverse all
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
result.addIfNotNull(
|
||||||
|
singleJavaFileRootsIndex.findJavaSourceClass(classId)
|
||||||
|
?.takeIf { it in scope }
|
||||||
|
?.findPsiClassInVirtualFile(relativeClassName)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (result.isNotEmpty()) {
|
||||||
|
return@time result.toTypedArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PsiClass.EMPTY_ARRAY
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findPackage(packageName: String): PsiPackage? {
|
||||||
|
var found = false
|
||||||
|
val packageFqName = packageName.toSafeFqName() ?: return null
|
||||||
|
index.traverseDirectoriesInPackage(packageFqName) { _, _ ->
|
||||||
|
found = true
|
||||||
|
//abort on first found
|
||||||
|
false
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
found = packagePartProviders.any { it.findPackageParts(packageName).isNotEmpty() }
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
found = singleJavaFileRootsIndex.findJavaSourceClasses(packageFqName).isNotEmpty()
|
||||||
|
}
|
||||||
|
return if (found) PsiPackageImpl(myPsiManager, packageName) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findVirtualFileGivenPackage(
|
||||||
|
packageDir: VirtualFile,
|
||||||
|
classNameWithInnerClasses: String,
|
||||||
|
rootType: JavaRoot.RootType
|
||||||
|
): VirtualFile? {
|
||||||
|
val topLevelClassName = classNameWithInnerClasses.substringBefore('.')
|
||||||
|
|
||||||
|
val vFile = when (rootType) {
|
||||||
|
JavaRoot.RootType.BINARY -> packageDir.findChild("$topLevelClassName.class")
|
||||||
|
JavaRoot.RootType.SOURCE -> packageDir.findChild("$topLevelClassName.java")
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
if (!vFile.isValid) {
|
||||||
|
LOG.error("Invalid child of valid parent: ${vFile.path}; ${packageDir.isValid} path=${packageDir.path}")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return vFile
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun VirtualFile.findPsiClassInVirtualFile(
|
||||||
|
classNameWithInnerClasses: String
|
||||||
|
): PsiClass? {
|
||||||
|
val file = myPsiManager.findFile(this) as? PsiClassOwner ?: return null
|
||||||
|
return findClassInPsiFile(classNameWithInnerClasses, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun knownClassNamesInPackage(packageFqName: FqName): Set<String> {
|
||||||
|
val result = hashSetOf<String>()
|
||||||
|
index.traverseDirectoriesInPackage(packageFqName, continueSearch = {
|
||||||
|
dir, _ ->
|
||||||
|
|
||||||
|
for (child in dir.children) {
|
||||||
|
if (child.extension == "class" || child.extension == "java") {
|
||||||
|
result.add(child.nameWithoutExtension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
})
|
||||||
|
|
||||||
|
for (classId in singleJavaFileRootsIndex.findJavaSourceClasses(packageFqName)) {
|
||||||
|
assert(!classId.isNestedClass) { "ClassId of a single .java source class should not be nested: $classId" }
|
||||||
|
result.add(classId.shortClassName.asString())
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
override fun findModules(moduleName: String, scope: GlobalSearchScope): Collection<PsiJavaModule> {
|
||||||
|
// TODO
|
||||||
|
return emptySet()
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
override fun getNonTrivialPackagePrefixes(): Collection<String> = emptyList()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOG = Logger.getInstance(KotlinCliJavaFileManagerImpl::class.java)
|
||||||
|
|
||||||
|
private fun findClassInPsiFile(classNameWithInnerClassesDotSeparated: String, file: PsiClassOwner): PsiClass? {
|
||||||
|
for (topLevelClass in file.classes) {
|
||||||
|
val candidate = findClassByTopLevelClass(classNameWithInnerClassesDotSeparated, topLevelClass)
|
||||||
|
if (candidate != null) {
|
||||||
|
return candidate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findClassByTopLevelClass(className: String, topLevelClass: PsiClass): PsiClass? {
|
||||||
|
if (className.indexOf('.') < 0) {
|
||||||
|
return if (className == topLevelClass.name) topLevelClass else null
|
||||||
|
}
|
||||||
|
|
||||||
|
val segments = StringUtil.split(className, ".").iterator()
|
||||||
|
if (!segments.hasNext() || segments.next() != topLevelClass.name) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
var curClass = topLevelClass
|
||||||
|
while (segments.hasNext()) {
|
||||||
|
val innerClassName = segments.next()
|
||||||
|
val innerClass = curClass.findInnerClassByName(innerClassName, false) ?: return null
|
||||||
|
curClass = innerClass
|
||||||
|
}
|
||||||
|
return curClass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// a sad workaround to avoid throwing exception when called from inside IDEA code
|
||||||
|
private fun <T : Any> safely(compute: () -> T): T? = try {
|
||||||
|
compute()
|
||||||
|
}
|
||||||
|
catch (e: IllegalArgumentException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
catch (e: AssertionError) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.toSafeFqName(): FqName? = safely { FqName(this) }
|
||||||
|
private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) }
|
||||||
+484
@@ -0,0 +1,484 @@
|
|||||||
|
/*
|
||||||
|
* 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.cli.jvm.compiler
|
||||||
|
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.psi.impl.PsiModificationTrackerImpl
|
||||||
|
import com.intellij.psi.search.DelegatingGlobalSearchScope
|
||||||
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
|
import org.jetbrains.kotlin.analyzer.AnalysisResult
|
||||||
|
import org.jetbrains.kotlin.asJava.FilteredJvmDiagnostics
|
||||||
|
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
|
||||||
|
import org.jetbrains.kotlin.backend.common.output.SimpleOutputFileCollection
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
|
||||||
|
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||||
|
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||||
|
import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsage
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.OUTPUT
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.WARNING
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
|
import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
|
||||||
|
import org.jetbrains.kotlin.cli.common.output.outputUtils.writeAll
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
||||||
|
import org.jetbrains.kotlin.cli.jvm.config.*
|
||||||
|
import org.jetbrains.kotlin.codegen.*
|
||||||
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
|
import org.jetbrains.kotlin.codegen.state.GenerationStateEventCallback
|
||||||
|
import org.jetbrains.kotlin.config.*
|
||||||
|
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||||
|
import org.jetbrains.kotlin.idea.MainFunctionDetector
|
||||||
|
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||||
|
import org.jetbrains.kotlin.load.kotlin.ModuleVisibilityManager
|
||||||
|
import org.jetbrains.kotlin.modules.Module
|
||||||
|
import org.jetbrains.kotlin.modules.TargetId
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.script.tryConstructClassFromStringArgs
|
||||||
|
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||||
|
import org.jetbrains.kotlin.utils.newLinkedHashMapWithExpectedSize
|
||||||
|
import java.io.File
|
||||||
|
import java.lang.reflect.InvocationTargetException
|
||||||
|
import java.net.URLClassLoader
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
object KotlinToJVMBytecodeCompiler {
|
||||||
|
|
||||||
|
private fun getAbsolutePaths(buildFile: File, module: Module): List<String> {
|
||||||
|
return module.getSourceFiles().map { sourceFile ->
|
||||||
|
val source = File(sourceFile)
|
||||||
|
if (!source.isAbsolute) {
|
||||||
|
File(buildFile.absoluteFile.parentFile, sourceFile).absolutePath
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
source.absolutePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeOutput(
|
||||||
|
configuration: CompilerConfiguration,
|
||||||
|
outputFiles: OutputFileCollection,
|
||||||
|
mainClass: FqName?
|
||||||
|
) {
|
||||||
|
val reportOutputFiles = configuration.getBoolean(CommonConfigurationKeys.REPORT_OUTPUT_FILES)
|
||||||
|
val jarPath = configuration.get(JVMConfigurationKeys.OUTPUT_JAR)
|
||||||
|
val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, MessageCollector.NONE)
|
||||||
|
if (jarPath != null) {
|
||||||
|
val includeRuntime = configuration.get(JVMConfigurationKeys.INCLUDE_RUNTIME, false)
|
||||||
|
CompileEnvironmentUtil.writeToJar(jarPath, includeRuntime, mainClass, outputFiles)
|
||||||
|
if (reportOutputFiles) {
|
||||||
|
val message = OutputMessageUtil.formatOutputMessage(outputFiles.asList().flatMap { it.sourceFiles }.distinct(), jarPath)
|
||||||
|
messageCollector.report(OUTPUT, message)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val outputDir = configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY) ?: File(".")
|
||||||
|
outputFiles.writeAll(outputDir, messageCollector, reportOutputFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createOutputFilesFlushingCallbackIfPossible(configuration: CompilerConfiguration): GenerationStateEventCallback {
|
||||||
|
if (configuration.get(JVMConfigurationKeys.OUTPUT_DIRECTORY) == null) {
|
||||||
|
return GenerationStateEventCallback.DO_NOTHING
|
||||||
|
}
|
||||||
|
return GenerationStateEventCallback { state ->
|
||||||
|
val currentOutput = SimpleOutputFileCollection(state.factory.currentOutput)
|
||||||
|
writeOutput(configuration, currentOutput, mainClass = null)
|
||||||
|
if (!configuration.get(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, false)) {
|
||||||
|
state.factory.releaseGeneratedOutput()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun compileModules(environment: KotlinCoreEnvironment, buildFile: File, chunk: List<Module>): Boolean {
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|
||||||
|
val moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.project)
|
||||||
|
|
||||||
|
val projectConfiguration = environment.configuration
|
||||||
|
for (module in chunk) {
|
||||||
|
moduleVisibilityManager.addModule(module)
|
||||||
|
}
|
||||||
|
|
||||||
|
val friendPaths = environment.configuration.getList(JVMConfigurationKeys.FRIEND_PATHS)
|
||||||
|
for (path in friendPaths) {
|
||||||
|
moduleVisibilityManager.addFriendPath(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetDescription = "in targets [" + chunk.joinToString { input -> input.getModuleName() + "-" + input.getModuleType() } + "]"
|
||||||
|
|
||||||
|
val result = repeatAnalysisIfNeeded(analyze(environment, targetDescription), environment, targetDescription)
|
||||||
|
if (result == null || !result.shouldGenerateCode) return false
|
||||||
|
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|
||||||
|
result.throwIfError()
|
||||||
|
|
||||||
|
val outputs = newLinkedHashMapWithExpectedSize<Module, GenerationState>(chunk.size)
|
||||||
|
|
||||||
|
for (module in chunk) {
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
val ktFiles = CompileEnvironmentUtil.getKtFiles(
|
||||||
|
environment.project, getAbsolutePaths(buildFile, module), projectConfiguration
|
||||||
|
) { path -> throw IllegalStateException("Should have been checked before: $path") }
|
||||||
|
if (!checkKotlinPackageUsage(environment, ktFiles)) return false
|
||||||
|
|
||||||
|
val moduleConfiguration = projectConfiguration.copy().apply {
|
||||||
|
put(JVMConfigurationKeys.OUTPUT_DIRECTORY, File(module.getOutputDirectory()))
|
||||||
|
}
|
||||||
|
|
||||||
|
outputs[module] = generate(environment, moduleConfiguration, result, ktFiles, module)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
for ((_, state) in outputs) {
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
writeOutput(state.configuration, state.factory, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (projectConfiguration.getBoolean(JVMConfigurationKeys.COMPILE_JAVA)) {
|
||||||
|
val singleModule = chunk.singleOrNull()
|
||||||
|
if (singleModule != null) {
|
||||||
|
return JavacWrapper.getInstance(environment.project).use {
|
||||||
|
it.compile(File(singleModule.getOutputDirectory()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
projectConfiguration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).let {
|
||||||
|
it.report(WARNING, "A chunk contains multiple modules (${chunk.joinToString { it.getModuleName() }}). -Xuse-javac option couldn't be used to compile java files")
|
||||||
|
}
|
||||||
|
JavacWrapper.getInstance(environment.project).close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
outputs.values.forEach(GenerationState::destroy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun configureSourceRoots(configuration: CompilerConfiguration, chunk: List<Module>, buildFile: File) {
|
||||||
|
for (module in chunk) {
|
||||||
|
configuration.addKotlinSourceRoots(getAbsolutePaths(buildFile, module))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (module in chunk) {
|
||||||
|
for ((path, packagePrefix) in module.getJavaSourceRoots()) {
|
||||||
|
configuration.addJavaSourceRoot(File(path), packagePrefix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val isJava9Module = false /*chunk.any { module ->
|
||||||
|
module.getJavaSourceRoots().any { (path, packagePrefix) ->
|
||||||
|
val file = File(path)
|
||||||
|
packagePrefix == null &&
|
||||||
|
(file.name == PsiJavaModule.MODULE_INFO_FILE ||
|
||||||
|
(file.isDirectory && file.listFiles().any { it.name == PsiJavaModule.MODULE_INFO_FILE }))
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
for (module in chunk) {
|
||||||
|
for (classpathRoot in module.getClasspathRoots()) {
|
||||||
|
configuration.add(
|
||||||
|
JVMConfigurationKeys.CONTENT_ROOTS,
|
||||||
|
if (isJava9Module) JvmModulePathRoot(File(classpathRoot)) else JvmClasspathRoot(File(classpathRoot))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (module in chunk) {
|
||||||
|
val modularJdkRoot = module.modularJdkRoot
|
||||||
|
if (modularJdkRoot != null) {
|
||||||
|
// We use the SDK of the first module in the chunk, which is not always correct because some other module in the chunk
|
||||||
|
// might depend on a different SDK
|
||||||
|
configuration.put(JVMConfigurationKeys.JDK_HOME, File(modularJdkRoot))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configuration.addAll(JVMConfigurationKeys.MODULES, chunk)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findMainClass(generationState: GenerationState, files: List<KtFile>): FqName? {
|
||||||
|
val mainFunctionDetector = MainFunctionDetector(generationState.bindingContext)
|
||||||
|
return files.asSequence()
|
||||||
|
.map { file ->
|
||||||
|
if (mainFunctionDetector.hasMain(file.declarations))
|
||||||
|
JvmFileClassUtil.getFileClassInfoNoResolve(file).facadeClassFqName
|
||||||
|
else
|
||||||
|
null
|
||||||
|
}
|
||||||
|
.singleOrNull { it != null }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun compileBunchOfSources(environment: KotlinCoreEnvironment): Boolean {
|
||||||
|
val moduleVisibilityManager = ModuleVisibilityManager.SERVICE.getInstance(environment.project)
|
||||||
|
|
||||||
|
val friendPaths = environment.configuration.getList(JVMConfigurationKeys.FRIEND_PATHS)
|
||||||
|
for (path in friendPaths) {
|
||||||
|
moduleVisibilityManager.addFriendPath(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!checkKotlinPackageUsage(environment, environment.getSourceFiles())) return false
|
||||||
|
|
||||||
|
val generationState = analyzeAndGenerate(environment) ?: return false
|
||||||
|
|
||||||
|
val mainClass = findMainClass(generationState, environment.getSourceFiles())
|
||||||
|
|
||||||
|
try {
|
||||||
|
writeOutput(environment.configuration, generationState.factory, mainClass)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
generationState.destroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun compileAndExecuteScript(environment: KotlinCoreEnvironment, scriptArgs: List<String>): ExitCode {
|
||||||
|
val scriptClass = compileScript(environment) ?: return ExitCode.COMPILATION_ERROR
|
||||||
|
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
tryConstructClassFromStringArgs(scriptClass, scriptArgs)
|
||||||
|
?: throw RuntimeException("unable to find appropriate constructor for class ${scriptClass.name} accepting arguments $scriptArgs\n")
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
// NB: these lines are required (see KT-9546) but aren't covered by tests
|
||||||
|
System.out.flush()
|
||||||
|
System.err.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e: Throwable) {
|
||||||
|
reportExceptionFromScript(e)
|
||||||
|
return ExitCode.SCRIPT_EXECUTION_ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExitCode.OK
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun repeatAnalysisIfNeeded(
|
||||||
|
result: AnalysisResult?,
|
||||||
|
environment: KotlinCoreEnvironment,
|
||||||
|
targetDescription: String?
|
||||||
|
): AnalysisResult? {
|
||||||
|
if (result is AnalysisResult.RetryWithAdditionalJavaRoots) {
|
||||||
|
val configuration = environment.configuration
|
||||||
|
|
||||||
|
val oldReadOnlyValue = configuration.isReadOnly
|
||||||
|
configuration.isReadOnly = false
|
||||||
|
configuration.addJavaSourceRoots(result.additionalJavaRoots)
|
||||||
|
configuration.isReadOnly = oldReadOnlyValue
|
||||||
|
|
||||||
|
if (result.addToEnvironment) {
|
||||||
|
environment.updateClasspath(result.additionalJavaRoots.map { JavaSourceRoot(it, null) })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear package caches (see KotlinJavaPsiFacade)
|
||||||
|
ApplicationManager.getApplication().runWriteAction {
|
||||||
|
(PsiManager.getInstance(environment.project).modificationTracker as? PsiModificationTrackerImpl)?.incCounter()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear all diagnostic messages
|
||||||
|
configuration[CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY]?.clear()
|
||||||
|
|
||||||
|
// Repeat analysis with additional Java roots (kapt generated sources)
|
||||||
|
return analyze(environment, targetDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun reportExceptionFromScript(exception: Throwable) {
|
||||||
|
// expecting InvocationTargetException from constructor invocation with cause that describes the actual cause
|
||||||
|
val stream = System.err
|
||||||
|
val cause = exception.cause
|
||||||
|
if (exception !is InvocationTargetException || cause == null) {
|
||||||
|
exception.printStackTrace(stream)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
stream.println(cause)
|
||||||
|
val fullTrace = cause.stackTrace
|
||||||
|
for (i in 0 until fullTrace.size - exception.stackTrace.size) {
|
||||||
|
stream.println("\tat " + fullTrace[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun compileScript(environment: KotlinCoreEnvironment, parentClassLoader: ClassLoader? = null): Class<*>? {
|
||||||
|
val state = analyzeAndGenerate(environment) ?: return null
|
||||||
|
|
||||||
|
try {
|
||||||
|
val urls = environment.configuration.getList(JVMConfigurationKeys.CONTENT_ROOTS).mapNotNull { root ->
|
||||||
|
when (root) {
|
||||||
|
is JvmModulePathRoot -> root.file // TODO: only add required modules
|
||||||
|
is JvmClasspathRoot -> root.file
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}.map { it.toURI().toURL() }
|
||||||
|
|
||||||
|
val classLoader = GeneratedClassLoader(state.factory, parentClassLoader ?: URLClassLoader(urls.toTypedArray(), null))
|
||||||
|
|
||||||
|
val script = environment.getSourceFiles()[0].script ?: error("Script must be parsed")
|
||||||
|
return classLoader.loadClass(script.fqName.asString())
|
||||||
|
}
|
||||||
|
catch (e: Exception) {
|
||||||
|
throw RuntimeException("Failed to evaluate script: " + e, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun analyzeAndGenerate(environment: KotlinCoreEnvironment): GenerationState? {
|
||||||
|
val result = repeatAnalysisIfNeeded(analyze(environment, null), environment, null) ?: return null
|
||||||
|
|
||||||
|
if (!result.shouldGenerateCode) return null
|
||||||
|
|
||||||
|
result.throwIfError()
|
||||||
|
|
||||||
|
return generate(environment, environment.configuration, result, environment.getSourceFiles(), null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun analyze(environment: KotlinCoreEnvironment, targetDescription: String?): AnalysisResult? {
|
||||||
|
val sourceFiles = environment.getSourceFiles()
|
||||||
|
val collector = environment.messageCollector
|
||||||
|
|
||||||
|
val analysisStart = PerformanceCounter.currentTime()
|
||||||
|
val analyzerWithCompilerReport = AnalyzerWithCompilerReport(collector, environment.configuration.languageVersionSettings)
|
||||||
|
analyzerWithCompilerReport.analyzeAndReport(sourceFiles) {
|
||||||
|
val project = environment.project
|
||||||
|
val moduleOutputs = environment.configuration.get(JVMConfigurationKeys.MODULES)?.mapNotNullTo(hashSetOf()) { module ->
|
||||||
|
environment.findLocalFile(module.getOutputDirectory())
|
||||||
|
}.orEmpty()
|
||||||
|
val sourcesOnly = TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, sourceFiles)
|
||||||
|
// To support partial and incremental compilation, we add the scope which contains binaries from output directories
|
||||||
|
// of the compiled modules (.class) to the list of scopes of the source module
|
||||||
|
val scope = if (moduleOutputs.isEmpty()) sourcesOnly else sourcesOnly.uniteWith(DirectoriesScope(project, moduleOutputs))
|
||||||
|
TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(
|
||||||
|
project,
|
||||||
|
sourceFiles,
|
||||||
|
NoScopeRecordCliBindingTrace(),
|
||||||
|
environment.configuration,
|
||||||
|
environment::createPackagePartProvider,
|
||||||
|
sourceModuleSearchScope = scope
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val analysisNanos = PerformanceCounter.currentTime() - analysisStart
|
||||||
|
|
||||||
|
val sourceLinesOfCode = environment.countLinesOfCode(sourceFiles)
|
||||||
|
val time = TimeUnit.NANOSECONDS.toMillis(analysisNanos)
|
||||||
|
val speed = sourceLinesOfCode.toFloat() * 1000 / time
|
||||||
|
|
||||||
|
val message = "ANALYZE: ${sourceFiles.size} files ($sourceLinesOfCode lines) ${targetDescription ?: ""}" +
|
||||||
|
"in $time ms - ${"%.3f".format(speed)} loc/s"
|
||||||
|
|
||||||
|
K2JVMCompiler.reportPerf(environment.configuration, message)
|
||||||
|
|
||||||
|
val analysisResult = analyzerWithCompilerReport.analysisResult
|
||||||
|
|
||||||
|
return if (!analyzerWithCompilerReport.hasErrors() || analysisResult is AnalysisResult.RetryWithAdditionalJavaRoots)
|
||||||
|
analysisResult
|
||||||
|
else
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
class DirectoriesScope(
|
||||||
|
project: Project,
|
||||||
|
private val directories: Set<VirtualFile>
|
||||||
|
) : DelegatingGlobalSearchScope(GlobalSearchScope.allScope(project)) {
|
||||||
|
private val fileSystems = directories.mapTo(hashSetOf(), VirtualFile::getFileSystem)
|
||||||
|
|
||||||
|
override fun contains(file: VirtualFile): Boolean {
|
||||||
|
if (file.fileSystem !in fileSystems) return false
|
||||||
|
|
||||||
|
var parent: VirtualFile = file
|
||||||
|
while (true) {
|
||||||
|
if (parent in directories) return true
|
||||||
|
parent = parent.parent ?: return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString() = "All files under: $directories"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun GenerationState.Builder.withModule(module: Module?) =
|
||||||
|
apply {
|
||||||
|
targetId(module?.let { TargetId(it) })
|
||||||
|
moduleName(module?.getModuleName())
|
||||||
|
outDirectory(module?.let { File(it.getOutputDirectory()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generate(
|
||||||
|
environment: KotlinCoreEnvironment,
|
||||||
|
configuration: CompilerConfiguration,
|
||||||
|
result: AnalysisResult,
|
||||||
|
sourceFiles: List<KtFile>,
|
||||||
|
module: Module?
|
||||||
|
): GenerationState {
|
||||||
|
val isKapt2Enabled = environment.project.getUserData(IS_KAPT2_ENABLED_KEY) ?: false
|
||||||
|
val generationState = GenerationState.Builder(
|
||||||
|
environment.project,
|
||||||
|
ClassBuilderFactories.binaries(isKapt2Enabled),
|
||||||
|
result.moduleDescriptor,
|
||||||
|
result.bindingContext,
|
||||||
|
sourceFiles,
|
||||||
|
configuration
|
||||||
|
)
|
||||||
|
.codegenFactory(if (configuration.getBoolean(JVMConfigurationKeys.IR)) JvmIrCodegenFactory else DefaultCodegenFactory)
|
||||||
|
.withModule(module)
|
||||||
|
.onIndependentPartCompilationEnd(createOutputFilesFlushingCallbackIfPossible(configuration))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|
||||||
|
val generationStart = PerformanceCounter.currentTime()
|
||||||
|
|
||||||
|
KotlinCodegenFacade.compileCorrectFiles(generationState, CompilationErrorHandler.THROW_EXCEPTION)
|
||||||
|
|
||||||
|
val generationNanos = PerformanceCounter.currentTime() - generationStart
|
||||||
|
val desc = if (module != null) "target " + module.getModuleName() + "-" + module.getModuleType() + " " else ""
|
||||||
|
val numberOfSourceFiles = sourceFiles.size
|
||||||
|
val numberOfLines = environment.countLinesOfCode(sourceFiles)
|
||||||
|
val time = TimeUnit.NANOSECONDS.toMillis(generationNanos)
|
||||||
|
val speed = numberOfLines.toFloat() * 1000 / time
|
||||||
|
val message = "GENERATE: $numberOfSourceFiles files ($numberOfLines lines) ${desc}in $time ms - ${"%.3f".format(speed)} loc/s"
|
||||||
|
|
||||||
|
K2JVMCompiler.reportPerf(environment.configuration, message)
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|
||||||
|
AnalyzerWithCompilerReport.reportDiagnostics(
|
||||||
|
FilteredJvmDiagnostics(
|
||||||
|
generationState.collectedExtraJvmDiagnostics,
|
||||||
|
result.bindingContext.diagnostics
|
||||||
|
),
|
||||||
|
environment.messageCollector
|
||||||
|
)
|
||||||
|
|
||||||
|
AnalyzerWithCompilerReport.reportBytecodeVersionErrors(
|
||||||
|
generationState.extraJvmDiagnosticsTrace.bindingContext, environment.messageCollector
|
||||||
|
)
|
||||||
|
|
||||||
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
return generationState
|
||||||
|
}
|
||||||
|
|
||||||
|
private val KotlinCoreEnvironment.messageCollector: MessageCollector
|
||||||
|
get() = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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.cli.jvm.modules
|
||||||
|
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleFinder
|
||||||
|
|
||||||
|
class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder {
|
||||||
|
private val modulesRoot = jrtFileSystemRoot?.findChild("modules")
|
||||||
|
private val userModules = linkedMapOf<String, JavaModule>()
|
||||||
|
|
||||||
|
fun addUserModule(module: JavaModule) {
|
||||||
|
userModules.putIfAbsent(module.name, module)
|
||||||
|
}
|
||||||
|
|
||||||
|
val allObservableModules: Sequence<JavaModule>
|
||||||
|
get() = systemModules + userModules.values
|
||||||
|
|
||||||
|
val systemModules: Sequence<JavaModule.Explicit>
|
||||||
|
get() = modulesRoot?.children.orEmpty().asSequence().mapNotNull(this::findSystemModule)
|
||||||
|
|
||||||
|
override fun findModule(name: String): JavaModule? =
|
||||||
|
modulesRoot?.findChild(name)?.let(this::findSystemModule) ?: userModules[name]
|
||||||
|
|
||||||
|
private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? {
|
||||||
|
/*
|
||||||
|
val file = moduleRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) ?: return null
|
||||||
|
val moduleInfo = JavaModuleInfo.read(file) ?: return null
|
||||||
|
return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(moduleRoot, isBinary = true)), file)
|
||||||
|
*/
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
+133
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* 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.load.java.structure.impl
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiTypeParameter
|
||||||
|
import com.intellij.psi.search.SearchScope
|
||||||
|
import org.jetbrains.kotlin.asJava.KtLightClassMarker
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.*
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.contains
|
||||||
|
|
||||||
|
class JavaClassImpl(psiClass: PsiClass) : JavaClassifierImpl<PsiClass>(psiClass), VirtualFileBoundJavaClass, JavaAnnotationOwnerImpl, JavaModifierListOwnerImpl {
|
||||||
|
init {
|
||||||
|
assert(psiClass !is PsiTypeParameter) { "PsiTypeParameter should be wrapped in JavaTypeParameter, not JavaClass: use JavaClassifier.create()" }
|
||||||
|
}
|
||||||
|
|
||||||
|
override val innerClassNames: Collection<Name>
|
||||||
|
get() = psi.innerClasses.mapNotNull { it.name?.takeIf(Name::isValidIdentifier)?.let(Name::identifier) }
|
||||||
|
|
||||||
|
override fun findInnerClass(name: Name): JavaClass? {
|
||||||
|
return psi.findInnerClassByName(name.asString(), false)?.let(::JavaClassImpl)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val fqName: FqName?
|
||||||
|
get() {
|
||||||
|
val qualifiedName = psi.qualifiedName
|
||||||
|
return if (qualifiedName == null) null else FqName(qualifiedName)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val name: Name
|
||||||
|
get() = KtPsiUtil.safeName(psi.name)
|
||||||
|
|
||||||
|
override val isInterface: Boolean
|
||||||
|
get() = psi.isInterface
|
||||||
|
|
||||||
|
override val isAnnotationType: Boolean
|
||||||
|
get() = psi.isAnnotationType
|
||||||
|
|
||||||
|
override val isEnum: Boolean
|
||||||
|
get() = psi.isEnum
|
||||||
|
|
||||||
|
override val outerClass: JavaClassImpl?
|
||||||
|
get() {
|
||||||
|
val outer = psi.containingClass
|
||||||
|
return if (outer == null) null else JavaClassImpl(outer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val typeParameters: List<JavaTypeParameter>
|
||||||
|
get() = typeParameters(psi.typeParameters)
|
||||||
|
|
||||||
|
override val supertypes: Collection<JavaClassifierType>
|
||||||
|
get() = classifierTypes(psi.superTypes)
|
||||||
|
|
||||||
|
override val methods: Collection<JavaMethod>
|
||||||
|
get() {
|
||||||
|
assertNotLightClass()
|
||||||
|
// We apply distinct here because PsiClass#getMethods() can return duplicate PSI methods, for example in Lombok (see KT-11778)
|
||||||
|
// Return type seems to be null for example for the 'clone' Groovy method generated by @AutoClone (see EA-73795)
|
||||||
|
return methods(psi.methods.filter { method -> !method.isConstructor && method.returnType != null }).distinct()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val fields: Collection<JavaField>
|
||||||
|
get() {
|
||||||
|
assertNotLightClass()
|
||||||
|
return fields(psi.fields.filter { field ->
|
||||||
|
val name = field.name
|
||||||
|
// ex. Android plugin generates LightFields for resources started from '.' (.DS_Store file etc)
|
||||||
|
name != null && Name.isValidIdentifier(name)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override val constructors: Collection<JavaConstructor>
|
||||||
|
get() {
|
||||||
|
assertNotLightClass()
|
||||||
|
// See for example org.jetbrains.plugins.scala.lang.psi.light.ScFunctionWrapper,
|
||||||
|
// which is present in getConstructors(), but its isConstructor() returns false
|
||||||
|
return constructors(psi.constructors.filter { method -> method.isConstructor })
|
||||||
|
}
|
||||||
|
|
||||||
|
override val isAbstract: Boolean
|
||||||
|
get() = JavaElementUtil.isAbstract(this)
|
||||||
|
|
||||||
|
override val isStatic: Boolean
|
||||||
|
get() = JavaElementUtil.isStatic(this)
|
||||||
|
|
||||||
|
override val isFinal: Boolean
|
||||||
|
get() = JavaElementUtil.isFinal(this)
|
||||||
|
|
||||||
|
override val visibility: Visibility
|
||||||
|
get() = JavaElementUtil.getVisibility(this)
|
||||||
|
|
||||||
|
override val lightClassOriginKind: LightClassOriginKind?
|
||||||
|
get() = (psi as? KtLightClassMarker)?.originKind
|
||||||
|
|
||||||
|
override val virtualFile: VirtualFile?
|
||||||
|
get() = psi.containingFile?.virtualFile
|
||||||
|
|
||||||
|
override fun isFromSourceCodeInScope(scope: SearchScope): Boolean = psi.containingFile in scope
|
||||||
|
|
||||||
|
override fun getAnnotationOwnerPsi() = psi.modifierList
|
||||||
|
|
||||||
|
private fun assertNotLightClass() {
|
||||||
|
val psiClass = psi
|
||||||
|
if (psiClass !is KtLightClassMarker) return
|
||||||
|
|
||||||
|
val message = "Querying members of JavaClass created for $psiClass of type ${psiClass::class.java} defined in file ${psiClass.containingFile?.virtualFile?.canonicalPath}"
|
||||||
|
LOGGER.error(message)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val LOGGER = Logger.getInstance(JavaClassImpl::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
+73
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* 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.load.kotlin
|
||||||
|
|
||||||
|
import com.intellij.ide.highlighter.JavaClassFileType
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.components.ServiceManager
|
||||||
|
import com.intellij.openapi.util.Computable
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
|
||||||
|
class KotlinBinaryClassCache : Disposable {
|
||||||
|
private class RequestCache {
|
||||||
|
internal var virtualFile: VirtualFile? = null
|
||||||
|
internal var modificationStamp: Long = 0
|
||||||
|
internal var virtualFileKotlinClass: VirtualFileKotlinClass? = null
|
||||||
|
|
||||||
|
fun cache(file: VirtualFile, aClass: VirtualFileKotlinClass?): VirtualFileKotlinClass? {
|
||||||
|
virtualFile = file
|
||||||
|
virtualFileKotlinClass = aClass
|
||||||
|
modificationStamp = file.modificationStamp
|
||||||
|
|
||||||
|
return aClass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val cache = object : ThreadLocal<RequestCache>() {
|
||||||
|
override fun initialValue(): RequestCache {
|
||||||
|
return RequestCache()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
// This is only relevant for tests. We create a new instance of Application for each test, and so a new instance of this service is
|
||||||
|
// also created for each test. However all tests share the same event dispatch thread, which would collect all instances of this
|
||||||
|
// thread-local if they're not removed properly. Each instance would transitively retain VFS resulting in OutOfMemoryError
|
||||||
|
cache.remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
|
||||||
|
if (file.fileType !== JavaClassFileType.INSTANCE) return null
|
||||||
|
|
||||||
|
val service = ServiceManager.getService(KotlinBinaryClassCache::class.java)
|
||||||
|
val requestCache = service.cache.get()
|
||||||
|
|
||||||
|
if (file.modificationStamp == requestCache.modificationStamp && file == requestCache.virtualFile) {
|
||||||
|
return requestCache.virtualFileKotlinClass
|
||||||
|
}
|
||||||
|
|
||||||
|
val aClass = ApplicationManager.getApplication().runReadAction(Computable {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
VirtualFileKotlinClass.create(file, fileContent)
|
||||||
|
})
|
||||||
|
|
||||||
|
return requestCache.cache(file, aClass)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+89
@@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* 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.resolve.jvm.modules
|
||||||
|
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
//import com.intellij.psi.PsiJavaModule
|
||||||
|
import com.intellij.psi.PsiModifier
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.utils.compact
|
||||||
|
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||||
|
import org.jetbrains.org.objectweb.asm.ClassVisitor
|
||||||
|
//import org.jetbrains.org.objectweb.asm.ModuleVisitor
|
||||||
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
|
//import org.jetbrains.org.objectweb.asm.Opcodes.ACC_TRANSITIVE
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class JavaModuleInfo(
|
||||||
|
val moduleName: String,
|
||||||
|
val requires: List<Requires>,
|
||||||
|
val exports: List<Exports>
|
||||||
|
) {
|
||||||
|
data class Requires(val moduleName: String, val isTransitive: Boolean)
|
||||||
|
|
||||||
|
data class Exports(val packageFqName: FqName, val toModules: List<String>)
|
||||||
|
|
||||||
|
override fun toString(): String =
|
||||||
|
"Module $moduleName (${requires.size} requires, ${exports.size} exports)"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/*fun create(psiJavaModule: PsiJavaModule): JavaModuleInfo {
|
||||||
|
return JavaModuleInfo(
|
||||||
|
psiJavaModule.name,
|
||||||
|
psiJavaModule.requires.mapNotNull { statement ->
|
||||||
|
statement.moduleName?.let { moduleName ->
|
||||||
|
JavaModuleInfo.Requires(moduleName, statement.hasModifierProperty(PsiModifier.TRANSITIVE))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
psiJavaModule.exports.mapNotNull { statement ->
|
||||||
|
statement.packageName?.let { packageName ->
|
||||||
|
JavaModuleInfo.Exports(FqName(packageName), statement.moduleNames)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
/*fun read(file: VirtualFile): JavaModuleInfo? {
|
||||||
|
val contents = try { file.contentsToByteArray() } catch (e: IOException) { return null }
|
||||||
|
|
||||||
|
var moduleName: String? = null
|
||||||
|
val requires = arrayListOf<Requires>()
|
||||||
|
val exports = arrayListOf<Exports>()
|
||||||
|
|
||||||
|
ClassReader(contents).accept(object : ClassVisitor(Opcodes.ASM6) {
|
||||||
|
override fun visitModule(name: String, access: Int, version: String?): ModuleVisitor {
|
||||||
|
moduleName = name
|
||||||
|
|
||||||
|
return object : ModuleVisitor(Opcodes.ASM6) {
|
||||||
|
override fun visitRequire(module: String, access: Int, version: String?) {
|
||||||
|
requires.add(Requires(module, (access and ACC_TRANSITIVE) != 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitExport(packageFqName: String, access: Int, modules: Array<String>?) {
|
||||||
|
// For some reason, '/' is the delimiter in packageFqName here
|
||||||
|
exports.add(Exports(FqName(packageFqName.replace('/', '.')), modules?.toList().orEmpty()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, ClassReader.SKIP_DEBUG or ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES)
|
||||||
|
|
||||||
|
return if (moduleName != null)
|
||||||
|
JavaModuleInfo(moduleName!!, requires.compact(), exports.compact())
|
||||||
|
else null
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile(projectTests(":compiler:cli"))
|
||||||
|
compile(projectTests(":idea:idea-maven"))
|
||||||
|
compile(projectTests(":j2k"))
|
||||||
|
compile(projectTests(":idea:idea-android"))
|
||||||
|
compile(projectTests(":jps-plugin"))
|
||||||
|
compile(projectTests(":plugins:android-extensions-compiler"))
|
||||||
|
compile(projectTests(":plugins:android-extensions-ide"))
|
||||||
|
compile(projectTests(":plugins:android-extensions-jps"))
|
||||||
|
compile(projectTests(":kotlin-annotation-processing"))
|
||||||
|
compile(projectTests(":kotlin-allopen-compiler-plugin"))
|
||||||
|
compile(projectTests(":kotlin-noarg-compiler-plugin"))
|
||||||
|
compile(projectTests(":kotlin-sam-with-receiver-compiler-plugin"))
|
||||||
|
compile(projectTests(":generators:test-generator"))
|
||||||
|
// testCompileOnly(intellijDep("jps-build-test"))
|
||||||
|
testCompileOnly(project(":kotlin-reflect-api"))
|
||||||
|
testRuntime(intellijDep()) { includeJars("idea_rt") }
|
||||||
|
testRuntime(projectDist(":kotlin-reflect"))
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { }
|
||||||
|
"test" { projectDefault() }
|
||||||
|
}
|
||||||
|
|
||||||
|
projectTest {
|
||||||
|
workingDir = rootDir
|
||||||
|
}
|
||||||
|
|
||||||
|
val generateTests by generator("org.jetbrains.kotlin.generators.tests.GenerateTestsKt")
|
||||||
|
|
||||||
|
val generateProtoBuf by generator("org.jetbrains.kotlin.generators.protobuf.GenerateProtoBufKt")
|
||||||
|
val generateProtoBufCompare by generator("org.jetbrains.kotlin.generators.protobuf.GenerateProtoBufCompare")
|
||||||
|
|
||||||
|
val generateGradleOptions by generator("org.jetbrains.kotlin.generators.arguments.GenerateGradleOptionsKt")
|
||||||
|
|
||||||
|
testsJar()
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(project(":idea"))
|
||||||
|
compileOnly(project(":idea:idea-maven"))
|
||||||
|
compileOnly(project(":idea:idea-gradle"))
|
||||||
|
compileOnly(project(":idea:idea-jvm"))
|
||||||
|
|
||||||
|
compile(intellijDep())
|
||||||
|
|
||||||
|
runtimeOnly(files(toolsJar()))
|
||||||
|
}
|
||||||
|
|
||||||
|
val ideaPluginDir: File by rootProject.extra
|
||||||
|
val ideaSandboxDir: File by rootProject.extra
|
||||||
|
|
||||||
|
runIdeTask("runIde", ideaPluginDir, ideaSandboxDir) {
|
||||||
|
dependsOn(":dist", ":ideaPlugin")
|
||||||
|
}
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
import org.gradle.jvm.tasks.Jar
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testRuntime(intellijDep())
|
||||||
|
|
||||||
|
compile(project(":kotlin-stdlib"))
|
||||||
|
compileOnly(project(":kotlin-reflect-api"))
|
||||||
|
compile(project(":core:descriptors"))
|
||||||
|
compile(project(":core:descriptors.jvm"))
|
||||||
|
compile(project(":compiler:backend"))
|
||||||
|
compile(project(":compiler:cli-common"))
|
||||||
|
compile(project(":compiler:frontend"))
|
||||||
|
compile(project(":compiler:frontend.java"))
|
||||||
|
compile(project(":compiler:frontend.script"))
|
||||||
|
compile(project(":js:js.frontend"))
|
||||||
|
compile(project(":js:js.serializer"))
|
||||||
|
compile(project(":compiler:light-classes"))
|
||||||
|
compile(project(":compiler:util"))
|
||||||
|
compile(project(":kotlin-build-common"))
|
||||||
|
compile(project(":compiler:daemon-common"))
|
||||||
|
compile(projectRuntimeJar(":kotlin-daemon-client"))
|
||||||
|
compile(project(":kotlin-compiler-runner")) { isTransitive = false }
|
||||||
|
compile(project(":compiler:plugin-api"))
|
||||||
|
compile(project(":eval4j"))
|
||||||
|
compile(project(":j2k"))
|
||||||
|
compile(project(":idea:formatter"))
|
||||||
|
compile(project(":idea:idea-core"))
|
||||||
|
compile(project(":idea:ide-common"))
|
||||||
|
compile(project(":idea:idea-jps-common"))
|
||||||
|
compile(project(":idea:kotlin-gradle-tooling"))
|
||||||
|
compile(project(":plugins:uast-kotlin"))
|
||||||
|
compile(project(":plugins:uast-kotlin-idea"))
|
||||||
|
compile(project(":kotlin-script-util")) { isTransitive = false }
|
||||||
|
|
||||||
|
compile(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false }
|
||||||
|
compile(commonDep("org.jetbrains", "markdown"))
|
||||||
|
|
||||||
|
compileOnly(project(":kotlin-daemon-client"))
|
||||||
|
|
||||||
|
compileOnly(intellijDep())
|
||||||
|
compileOnly(commonDep("com.google.code.findbugs", "jsr305"))
|
||||||
|
compileOnly(intellijPluginDep("IntelliLang"))
|
||||||
|
compileOnly(intellijPluginDep("copyright"))
|
||||||
|
compileOnly(intellijPluginDep("properties"))
|
||||||
|
compileOnly(intellijPluginDep("java-i18n"))
|
||||||
|
|
||||||
|
testCompile(project(":kotlin-test:kotlin-test-junit"))
|
||||||
|
testCompile(projectTests(":compiler:tests-common"))
|
||||||
|
testCompile(projectTests(":idea:idea-test-framework")) { isTransitive = false }
|
||||||
|
testCompile(project(":idea:idea-jvm")) { isTransitive = false }
|
||||||
|
testCompile(project(":idea:idea-gradle")) { isTransitive = false }
|
||||||
|
testCompile(project(":idea:idea-maven")) { isTransitive = false }
|
||||||
|
testCompile(commonDep("junit:junit"))
|
||||||
|
|
||||||
|
testRuntime(project(":plugins:kapt3-idea")) { isTransitive = false }
|
||||||
|
testRuntime(projectDist(":kotlin-reflect"))
|
||||||
|
testRuntime(projectDist(":kotlin-preloader"))
|
||||||
|
|
||||||
|
testCompile(project(":kotlin-sam-with-receiver-compiler-plugin")) { isTransitive = false }
|
||||||
|
|
||||||
|
testRuntime(project(":plugins:android-extensions-compiler"))
|
||||||
|
testRuntime(project(":plugins:android-extensions-ide")) { isTransitive = false }
|
||||||
|
testRuntime(project(":allopen-ide-plugin")) { isTransitive = false }
|
||||||
|
testRuntime(project(":kotlin-allopen-compiler-plugin"))
|
||||||
|
testRuntime(project(":noarg-ide-plugin")) { isTransitive = false }
|
||||||
|
testRuntime(project(":kotlin-noarg-compiler-plugin"))
|
||||||
|
testRuntime(project(":plugins:annotation-based-compiler-plugins-ide-support")) { isTransitive = false }
|
||||||
|
testRuntime(project(":sam-with-receiver-ide-plugin")) { isTransitive = false }
|
||||||
|
testRuntime(project(":idea:idea-android")) { isTransitive = false }
|
||||||
|
testRuntime(project(":plugins:lint")) { isTransitive = false }
|
||||||
|
testRuntime(project(":plugins:uast-kotlin"))
|
||||||
|
|
||||||
|
(rootProject.extra["compilerModules"] as Array<String>).forEach {
|
||||||
|
testRuntime(project(it))
|
||||||
|
}
|
||||||
|
|
||||||
|
testCompile(intellijPluginDep("IntelliLang"))
|
||||||
|
testCompile(intellijPluginDep("copyright"))
|
||||||
|
testCompile(intellijPluginDep("properties"))
|
||||||
|
testCompile(intellijPluginDep("java-i18n"))
|
||||||
|
testCompileOnly(intellijDep())
|
||||||
|
testCompileOnly(commonDep("com.google.code.findbugs", "jsr305"))
|
||||||
|
testCompileOnly(intellijPluginDep("gradle"))
|
||||||
|
testCompileOnly(intellijPluginDep("Groovy"))
|
||||||
|
//testCompileOnly(intellijPluginDep("maven"))
|
||||||
|
|
||||||
|
testRuntime(intellijPluginDep("junit"))
|
||||||
|
testRuntime(intellijPluginDep("gradle"))
|
||||||
|
testRuntime(intellijPluginDep("Groovy"))
|
||||||
|
testRuntime(intellijPluginDep("coverage"))
|
||||||
|
//testRuntime(intellijPluginDep("maven"))
|
||||||
|
testRuntime(intellijPluginDep("android"))
|
||||||
|
testRuntime(intellijPluginDep("smali"))
|
||||||
|
testRuntime(intellijPluginDep("testng"))
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" {
|
||||||
|
projectDefault()
|
||||||
|
java.srcDirs("idea-completion/src",
|
||||||
|
"idea-live-templates/src",
|
||||||
|
"idea-repl/src")
|
||||||
|
resources.srcDirs("idea-repl/src").apply { include("META-INF/**") }
|
||||||
|
}
|
||||||
|
"test" {
|
||||||
|
projectDefault()
|
||||||
|
java.srcDirs(
|
||||||
|
"idea-completion/tests",
|
||||||
|
"idea-live-templates/tests")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
projectTest {
|
||||||
|
dependsOn(":dist")
|
||||||
|
workingDir = rootDir
|
||||||
|
}
|
||||||
|
|
||||||
|
testsJar {}
|
||||||
|
|
||||||
|
classesDirsArtifact()
|
||||||
|
configureInstrumentation()
|
||||||
|
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testRuntime(intellijDep())
|
||||||
|
|
||||||
|
compileOnly(project(":kotlin-reflect-api"))
|
||||||
|
compile(project(":compiler:util"))
|
||||||
|
compile(project(":compiler:light-classes"))
|
||||||
|
compile(project(":compiler:frontend"))
|
||||||
|
compile(project(":compiler:frontend.java"))
|
||||||
|
compile(project(":idea"))
|
||||||
|
compile(project(":idea:idea-jvm"))
|
||||||
|
compile(project(":idea:idea-core"))
|
||||||
|
compile(project(":idea:ide-common"))
|
||||||
|
compile(project(":idea:idea-gradle"))
|
||||||
|
|
||||||
|
compile(androidDxJar())
|
||||||
|
|
||||||
|
compileOnly(project(":kotlin-android-extensions-runtime"))
|
||||||
|
compileOnly(intellijDep())
|
||||||
|
compileOnly(intellijPluginDep("android"))
|
||||||
|
|
||||||
|
testCompile(projectDist(":kotlin-test:kotlin-test-jvm"))
|
||||||
|
testCompile(projectTests(":idea:idea-test-framework")) { isTransitive = false }
|
||||||
|
testCompile(project(":plugins:lint")) { isTransitive = false }
|
||||||
|
testCompile(project(":idea:idea-jvm"))
|
||||||
|
testCompile(projectTests(":compiler:tests-common"))
|
||||||
|
testCompile(projectTests(":idea"))
|
||||||
|
testCompile(projectTests(":idea:idea-gradle"))
|
||||||
|
testCompile(commonDep("junit:junit"))
|
||||||
|
|
||||||
|
testCompile(intellijDep())
|
||||||
|
testCompile(intellijPluginDep("properties"))
|
||||||
|
testCompileOnly(intellijPluginDep("android"))
|
||||||
|
|
||||||
|
testRuntime(projectDist(":kotlin-reflect"))
|
||||||
|
testRuntime(project(":plugins:android-extensions-ide"))
|
||||||
|
testRuntime(project(":plugins:kapt3-idea"))
|
||||||
|
testRuntime(project(":sam-with-receiver-ide-plugin"))
|
||||||
|
testRuntime(project(":noarg-ide-plugin"))
|
||||||
|
testRuntime(project(":allopen-ide-plugin"))
|
||||||
|
|
||||||
|
testRuntime(intellijPluginDep("android"))
|
||||||
|
testRuntime(intellijPluginDep("smali"))
|
||||||
|
testRuntime(intellijPluginDep("copyright"))
|
||||||
|
testRuntime(intellijPluginDep("coverage"))
|
||||||
|
testRuntime(intellijPluginDep("gradle"))
|
||||||
|
testRuntime(intellijPluginDep("Groovy"))
|
||||||
|
testRuntime(intellijPluginDep("IntelliLang"))
|
||||||
|
testRuntime(intellijPluginDep("java-decompiler"))
|
||||||
|
testRuntime(intellijPluginDep("java-i18n"))
|
||||||
|
testRuntime(intellijPluginDep("junit"))
|
||||||
|
//testRuntime(intellijPluginDep("maven"))
|
||||||
|
testRuntime(intellijPluginDep("testng"))
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { projectDefault() }
|
||||||
|
"test" { projectDefault() }
|
||||||
|
}
|
||||||
|
|
||||||
|
projectTest {
|
||||||
|
workingDir = rootDir
|
||||||
|
useAndroidSdk()
|
||||||
|
}
|
||||||
|
|
||||||
|
testsJar {}
|
||||||
|
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.android
|
||||||
|
|
||||||
|
import com.android.tools.idea.npw.template.ConvertJavaToKotlinProvider
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.psi.PsiJavaFile
|
||||||
|
import org.jetbrains.kotlin.android.configure.KotlinAndroidGradleModuleConfigurator
|
||||||
|
import org.jetbrains.kotlin.idea.actions.JavaToKotlinAction
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.getCanBeConfiguredModules
|
||||||
|
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
|
||||||
|
|
||||||
|
class ConvertJavaToKotlinProviderImpl : ConvertJavaToKotlinProvider {
|
||||||
|
override fun configureKotlin(project: Project) {
|
||||||
|
val configurator = KotlinProjectConfigurator.EP_NAME.findExtension(KotlinAndroidGradleModuleConfigurator::class.java)
|
||||||
|
val nonConfiguredModules = getCanBeConfiguredModules(project, configurator)
|
||||||
|
configurator.configureSilently(project, nonConfiguredModules, bundledRuntimeVersion())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getKotlinVersion(): String {
|
||||||
|
return bundledRuntimeVersion()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun convertToKotlin(project: Project, files: List<PsiJavaFile>): List<PsiFile> {
|
||||||
|
return JavaToKotlinAction.convertFiles(files, project, askExternalCodeProcessing = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
-1
@@ -25,7 +25,6 @@ import com.android.resources.ResourceType;
|
|||||||
import com.android.tools.idea.configurations.Configuration;
|
import com.android.tools.idea.configurations.Configuration;
|
||||||
import com.android.tools.idea.configurations.ConfigurationManager;
|
import com.android.tools.idea.configurations.ConfigurationManager;
|
||||||
import com.android.tools.idea.res.AppResourceRepository;
|
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.res.ResourceHelper;
|
||||||
import com.android.tools.idea.ui.resourcechooser.ColorPicker;
|
import com.android.tools.idea.ui.resourcechooser.ColorPicker;
|
||||||
import com.android.utils.XmlUtils;
|
import com.android.utils.XmlUtils;
|
||||||
|
|||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.android.configure
|
||||||
|
|
||||||
|
import com.android.tools.idea.gradle.project.model.JavaModuleModel
|
||||||
|
import com.android.tools.idea.gradle.project.sync.idea.data.service.AndroidProjectKeys
|
||||||
|
import com.android.tools.idea.io.FilePaths
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.OrderRootType
|
||||||
|
import com.intellij.openapi.roots.impl.libraries.LibraryEx
|
||||||
|
import com.intellij.openapi.roots.libraries.Library
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.detectPlatformByPlugin
|
||||||
|
import org.jetbrains.kotlin.idea.framework.detectLibraryKind
|
||||||
|
import org.jetbrains.kotlin.idea.framework.libraryKind
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class KotlinAndroidGradleLibraryDataService : AbstractProjectDataService<JavaModuleModel, Void>() {
|
||||||
|
override fun getTargetDataKey() = AndroidProjectKeys.JAVA_MODULE_MODEL
|
||||||
|
|
||||||
|
override fun postProcess(
|
||||||
|
toImport: MutableCollection<DataNode<JavaModuleModel>>,
|
||||||
|
projectData: ProjectData?,
|
||||||
|
project: Project,
|
||||||
|
modelsProvider: IdeModifiableModelsProvider
|
||||||
|
) {
|
||||||
|
for (dataNode in toImport) {
|
||||||
|
val targetLibraryKind = detectPlatformByPlugin(dataNode.parent as DataNode<ModuleData>)?.libraryKind
|
||||||
|
if (targetLibraryKind != null) {
|
||||||
|
for (dep in dataNode.data.jarLibraryDependencies) {
|
||||||
|
val library = modelsProvider.findLibraryByBinaryPath(dep.binaryPath) as LibraryEx? ?: continue
|
||||||
|
if (library.kind == null) {
|
||||||
|
val model = modelsProvider.getModifiableLibraryModel(library) as LibraryEx.ModifiableModelEx
|
||||||
|
detectLibraryKind(model.getFiles(OrderRootType.CLASSES))?.let { model.kind = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IdeModifiableModelsProvider.findLibraryByBinaryPath(path: File?): Library? {
|
||||||
|
if (path == null) return null
|
||||||
|
val url = FilePaths.pathToIdeaUrl(path)
|
||||||
|
return allLibraries.firstOrNull { url in getModifiableLibraryModel(it).getUrls(OrderRootType.CLASSES) }
|
||||||
|
}
|
||||||
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.android.configure
|
||||||
|
|
||||||
|
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
|
||||||
|
import com.android.tools.idea.gradle.project.sync.setup.post.ModuleSetupStep
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.progress.ProgressIndicator
|
||||||
|
import org.jetbrains.android.facet.AndroidFacet
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.compilerArgumentsBySourceSet
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.configureFacetByCompilerArguments
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.sourceSetName
|
||||||
|
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||||
|
|
||||||
|
class KotlinAndroidModuleSetupStep : ModuleSetupStep() {
|
||||||
|
override fun setUpModule(module: Module, progressIndicator: ProgressIndicator?) {
|
||||||
|
val facet = AndroidFacet.getInstance(module) ?: return
|
||||||
|
val androidModel = AndroidModuleModel.get(facet) ?: return
|
||||||
|
val sourceSetName = androidModel.selectedVariant.name
|
||||||
|
if (module.sourceSetName == sourceSetName) return
|
||||||
|
val argsInfo = module.compilerArgumentsBySourceSet?.get(sourceSetName) ?: return
|
||||||
|
val kotlinFacet = KotlinFacet.get(module) ?: return
|
||||||
|
module.sourceSetName = sourceSetName
|
||||||
|
configureFacetByCompilerArguments(kotlinFacet, argsInfo, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.android.configure
|
||||||
|
|
||||||
|
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import com.intellij.openapi.externalSystem.model.Key
|
||||||
|
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
|
||||||
|
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.GradleProjectImportHandler
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.configureFacetByGradleModule
|
||||||
|
|
||||||
|
class KotlinGradleAndroidModuleModelProjectDataService : AbstractProjectDataService<AndroidModuleModel, Void>() {
|
||||||
|
companion object {
|
||||||
|
val KEY = Key<AndroidModuleModel>(AndroidModuleModel::class.qualifiedName!!, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTargetDataKey() = KEY
|
||||||
|
|
||||||
|
override fun postProcess(
|
||||||
|
toImport: MutableCollection<DataNode<AndroidModuleModel>>,
|
||||||
|
projectData: ProjectData?,
|
||||||
|
project: Project,
|
||||||
|
modelsProvider: IdeModifiableModelsProvider
|
||||||
|
) {
|
||||||
|
super.postProcess(toImport, projectData, project, modelsProvider)
|
||||||
|
for (moduleModelNode in toImport) {
|
||||||
|
val moduleNode = ExternalSystemApiUtil.findParent(moduleModelNode, ProjectKeys.MODULE) ?: continue
|
||||||
|
val moduleData = moduleNode.data
|
||||||
|
val ideModule = modelsProvider.findIdeModule(moduleData) ?: continue
|
||||||
|
val sourceSetName = moduleModelNode.data.selectedVariant.name
|
||||||
|
val kotlinFacet = configureFacetByGradleModule(moduleNode, sourceSetName, ideModule, modelsProvider) ?: continue
|
||||||
|
GradleProjectImportHandler.getInstances(project).forEach { it.importByModule(kotlinFacet, moduleNode) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.android.navigation
|
||||||
|
|
||||||
|
import org.jetbrains.android.util.AndroidResourceUtil
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.android.facet.AndroidFacet
|
||||||
|
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import org.jetbrains.android.util.AndroidUtils
|
||||||
|
import com.android.SdkConstants
|
||||||
|
import org.jetbrains.android.augment.AndroidPsiElementFinder
|
||||||
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
|
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
|
|
||||||
|
fun getReferenceExpression(element: PsiElement?): KtSimpleNameExpression? {
|
||||||
|
return PsiTreeUtil.getParentOfType<KtSimpleNameExpression>(element, KtSimpleNameExpression::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
// given 'R.a.b' returns info for all three parts of the expression 'a', 'b', 'R'
|
||||||
|
fun getInfo(
|
||||||
|
referenceExpression: KtSimpleNameExpression,
|
||||||
|
facet: AndroidFacet
|
||||||
|
): AndroidResourceUtil.MyReferredResourceFieldInfo? {
|
||||||
|
val info = getReferredInfo(referenceExpression, facet)
|
||||||
|
if (info != null) return info
|
||||||
|
|
||||||
|
val topMostQualified = referenceExpression.getParentQualified().getParentQualified() ?: return null
|
||||||
|
val selectorCandidate = topMostQualified.selectorExpression as? KtSimpleNameExpression ?: return null
|
||||||
|
return getReferredInfo(selectorCandidate, facet)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KtExpression?.getParentQualified(): KtDotQualifiedExpression? {
|
||||||
|
return this?.parent as? KtDotQualifiedExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns info if passed expression is 'b' in 'R.a.b'
|
||||||
|
private fun getReferredInfo(
|
||||||
|
lastPart: KtSimpleNameExpression,
|
||||||
|
facet: AndroidFacet
|
||||||
|
): AndroidResourceUtil.MyReferredResourceFieldInfo? {
|
||||||
|
val resFieldName = lastPart.getReferencedName()
|
||||||
|
if (resFieldName.isEmpty()) return null
|
||||||
|
|
||||||
|
val middlePart = getReceiverAsSimpleNameExpression(lastPart) ?: return null
|
||||||
|
|
||||||
|
val resClassName = middlePart.getReferencedName()
|
||||||
|
if (resClassName.isEmpty()) return null
|
||||||
|
|
||||||
|
val firstPart = getReceiverAsSimpleNameExpression(middlePart) ?: return null
|
||||||
|
|
||||||
|
val resolvedClass = firstPart.mainReference.resolve() as? PsiClass ?: return null
|
||||||
|
|
||||||
|
//the following code is copied from
|
||||||
|
// org.jetbrains.android.util.AndroidResourceUtil.getReferredResourceOrManifestField
|
||||||
|
// (org.jetbrains.android.facet.AndroidFacet, com.intellij.psi.PsiReferenceExpression, java.lang.String, boolean)
|
||||||
|
val classShortName = resolvedClass.name
|
||||||
|
|
||||||
|
val fromManifest = AndroidUtils.MANIFEST_CLASS_NAME == classShortName
|
||||||
|
|
||||||
|
if (!fromManifest && AndroidUtils.R_CLASS_NAME != classShortName) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val qName = resolvedClass.qualifiedName
|
||||||
|
|
||||||
|
if (SdkConstants.CLASS_R == qName || AndroidPsiElementFinder.INTERNAL_R_CLASS_QNAME == qName) {
|
||||||
|
return AndroidResourceUtil.MyReferredResourceFieldInfo(resClassName, resFieldName, facet.module, true, false)
|
||||||
|
}
|
||||||
|
val containingFile = resolvedClass.containingFile ?: return null
|
||||||
|
|
||||||
|
val isFromCorrectFile =
|
||||||
|
if (fromManifest) AndroidResourceUtil.isManifestJavaFile(facet, containingFile)
|
||||||
|
else AndroidResourceUtil.isRJavaFile(facet, containingFile)
|
||||||
|
|
||||||
|
if (!isFromCorrectFile) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return AndroidResourceUtil.MyReferredResourceFieldInfo(resClassName, resFieldName, facet.module, false, fromManifest)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getReceiverAsSimpleNameExpression(exp: KtSimpleNameExpression): KtSimpleNameExpression? {
|
||||||
|
val receiver = exp.getReceiverExpression()
|
||||||
|
return when (receiver) {
|
||||||
|
is KtSimpleNameExpression -> {
|
||||||
|
receiver
|
||||||
|
}
|
||||||
|
is KtDotQualifiedExpression -> {
|
||||||
|
receiver.selectorExpression as? KtSimpleNameExpression
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.android.quickfix
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.FileModificationService
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
|
import org.jetbrains.android.inspections.lint.AndroidLintQuickFix
|
||||||
|
import org.jetbrains.android.inspections.lint.AndroidQuickfixContexts
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.codeInsight.surroundWith.statement.KotlinIfSurrounder
|
||||||
|
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.findExistingEditor
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
|
|
||||||
|
|
||||||
|
class AddTargetVersionCheckQuickFix(val api: Int) : AndroidLintQuickFix {
|
||||||
|
|
||||||
|
override fun apply(startElement: PsiElement, endElement: PsiElement, context: AndroidQuickfixContexts.Context) {
|
||||||
|
val targetExpression = getTargetExpression(startElement)
|
||||||
|
val project = targetExpression?.project ?: return
|
||||||
|
val editor = targetExpression.findExistingEditor() ?: return
|
||||||
|
|
||||||
|
val file = targetExpression.containingFile
|
||||||
|
val documentManager = PsiDocumentManager.getInstance(project)
|
||||||
|
val document = documentManager.getDocument(file) ?: return
|
||||||
|
|
||||||
|
if (!FileModificationService.getInstance().prepareFileForWrite(file)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val surrounder = getSurrounder(targetExpression, "\"VERSION.SDK_INT < ${getVersionField(api, false)}\"")
|
||||||
|
val conditionRange = surrounder.surroundElements(project, editor, arrayOf(targetExpression)) ?: return
|
||||||
|
val conditionText = "android.os.Build.VERSION.SDK_INT >= ${getVersionField(api, true)}"
|
||||||
|
document.replaceString(conditionRange.startOffset, conditionRange.endOffset, conditionText)
|
||||||
|
documentManager.commitDocument(document)
|
||||||
|
|
||||||
|
ShortenReferences.DEFAULT.process(documentManager.getPsiFile(document) as KtFile,
|
||||||
|
conditionRange.startOffset,
|
||||||
|
conditionRange.startOffset + conditionText.length)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isApplicable(startElement: PsiElement, endElement: PsiElement, contextType: AndroidQuickfixContexts.ContextType): Boolean =
|
||||||
|
getTargetExpression(startElement) != null
|
||||||
|
|
||||||
|
override fun getName(): String = "Surround with if (VERSION.SDK_INT >= VERSION_CODES.${getVersionField(api, false)}) { ... }"
|
||||||
|
|
||||||
|
private fun getTargetExpression(element: PsiElement): KtElement? {
|
||||||
|
var current = PsiTreeUtil.getParentOfType(element, KtExpression::class.java)
|
||||||
|
while (current != null) {
|
||||||
|
if (current.parent is KtBlockExpression ||
|
||||||
|
current.parent is KtContainerNode ||
|
||||||
|
current.parent is KtWhenEntry ||
|
||||||
|
current.parent is KtFunction ||
|
||||||
|
current.parent is KtPropertyAccessor ||
|
||||||
|
current.parent is KtProperty ||
|
||||||
|
current.parent is KtReturnExpression ||
|
||||||
|
current.parent is KtDestructuringDeclaration) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
current = PsiTreeUtil.getParentOfType(current, KtExpression::class.java, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return current
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSurrounder(element: KtElement, todoText: String?): KotlinIfSurrounder {
|
||||||
|
val used = element.analyze(BodyResolveMode.PARTIAL_WITH_CFA)[BindingContext.USED_AS_EXPRESSION, element] ?: false
|
||||||
|
return if (used) {
|
||||||
|
object : KotlinIfSurrounder() {
|
||||||
|
override fun getCodeTemplate(): String = "if (a) { \n} else {\nTODO(${todoText ?: ""})\n}"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
KotlinIfSurrounder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testRuntime(intellijDep())
|
||||||
|
|
||||||
|
compileOnly(project(":idea"))
|
||||||
|
compileOnly(project(":idea:idea-jvm"))
|
||||||
|
compile(project(":idea:kotlin-gradle-tooling"))
|
||||||
|
|
||||||
|
compile(project(":compiler:frontend"))
|
||||||
|
compile(project(":compiler:frontend.java"))
|
||||||
|
compile(project(":compiler:frontend.script"))
|
||||||
|
|
||||||
|
compile(project(":js:js.frontend"))
|
||||||
|
|
||||||
|
compileOnly(intellijDep())
|
||||||
|
compileOnly(intellijPluginDep("gradle"))
|
||||||
|
compileOnly(intellijPluginDep("Groovy"))
|
||||||
|
compileOnly(intellijPluginDep("junit"))
|
||||||
|
|
||||||
|
testCompile(projectTests(":idea"))
|
||||||
|
testCompile(projectTests(":idea:idea-test-framework"))
|
||||||
|
|
||||||
|
testCompile(intellijPluginDep("gradle"))
|
||||||
|
testCompileOnly(intellijPluginDep("Groovy"))
|
||||||
|
testCompileOnly(intellijDep())
|
||||||
|
|
||||||
|
testRuntime(projectDist(":kotlin-reflect"))
|
||||||
|
testRuntime(project(":idea:idea-jvm"))
|
||||||
|
testRuntime(project(":idea:idea-android"))
|
||||||
|
testRuntime(project(":plugins:kapt3-idea"))
|
||||||
|
testRuntime(project(":plugins:android-extensions-ide"))
|
||||||
|
testRuntime(project(":plugins:lint"))
|
||||||
|
testRuntime(project(":sam-with-receiver-ide-plugin"))
|
||||||
|
testRuntime(project(":allopen-ide-plugin"))
|
||||||
|
testRuntime(project(":noarg-ide-plugin"))
|
||||||
|
// TODO: the order of the plugins matters here, consider avoiding order-dependency
|
||||||
|
testRuntime(intellijPluginDep("junit"))
|
||||||
|
testRuntime(intellijPluginDep("testng"))
|
||||||
|
testRuntime(intellijPluginDep("properties"))
|
||||||
|
testRuntime(intellijPluginDep("gradle"))
|
||||||
|
testRuntime(intellijPluginDep("Groovy"))
|
||||||
|
testRuntime(intellijPluginDep("coverage"))
|
||||||
|
//testRuntime(intellijPluginDep("maven"))
|
||||||
|
testRuntime(intellijPluginDep("android"))
|
||||||
|
testRuntime(intellijPluginDep("smali"))
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" {
|
||||||
|
projectDefault()
|
||||||
|
resources.srcDir("res").apply { include("**") }
|
||||||
|
}
|
||||||
|
"test" { projectDefault() }
|
||||||
|
}
|
||||||
|
|
||||||
|
testsJar()
|
||||||
|
|
||||||
|
projectTest {
|
||||||
|
workingDir = rootDir
|
||||||
|
useAndroidSdk()
|
||||||
|
}
|
||||||
|
|
||||||
|
configureInstrumentation()
|
||||||
+277
@@ -0,0 +1,277 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.configuration
|
||||||
|
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.LibraryData
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
|
||||||
|
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.module.isQualifiedModuleNamesEnabled
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.OrderRootType
|
||||||
|
import com.intellij.openapi.roots.impl.libraries.LibraryEx
|
||||||
|
import com.intellij.openapi.roots.impl.libraries.LibraryImpl
|
||||||
|
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
|
||||||
|
import com.intellij.openapi.util.Key
|
||||||
|
import com.intellij.util.PathUtil
|
||||||
|
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||||
|
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||||
|
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
|
||||||
|
import org.jetbrains.kotlin.config.CoroutineSupport
|
||||||
|
import org.jetbrains.kotlin.config.JvmTarget
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.TargetPlatformKind
|
||||||
|
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
||||||
|
import org.jetbrains.kotlin.gradle.ArgsInfo
|
||||||
|
import org.jetbrains.kotlin.gradle.CompilerArgumentsBySourceSet
|
||||||
|
import org.jetbrains.kotlin.idea.facet.*
|
||||||
|
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
|
||||||
|
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
|
||||||
|
import org.jetbrains.kotlin.idea.framework.detectLibraryKind
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.gradle.findAll
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
|
||||||
|
import org.jetbrains.kotlin.idea.inspections.gradle.getResolvedKotlinStdlibVersionByModuleData
|
||||||
|
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||||
|
import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData
|
||||||
|
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
var Module.compilerArgumentsBySourceSet
|
||||||
|
by UserDataProperty(Key.create<CompilerArgumentsBySourceSet>("CURRENT_COMPILER_ARGUMENTS"))
|
||||||
|
|
||||||
|
var Module.sourceSetName
|
||||||
|
by UserDataProperty(Key.create<String>("SOURCE_SET_NAME"))
|
||||||
|
|
||||||
|
interface GradleProjectImportHandler {
|
||||||
|
companion object : ProjectExtensionDescriptor<GradleProjectImportHandler>(
|
||||||
|
"org.jetbrains.kotlin.gradleProjectImportHandler",
|
||||||
|
GradleProjectImportHandler::class.java
|
||||||
|
)
|
||||||
|
|
||||||
|
fun importBySourceSet(facet: KotlinFacet, sourceSetNode: DataNode<GradleSourceSetData>)
|
||||||
|
fun importByModule(facet: KotlinFacet, moduleNode: DataNode<ModuleData>)
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinGradleSourceSetDataService : AbstractProjectDataService<GradleSourceSetData, Void>() {
|
||||||
|
override fun getTargetDataKey() = GradleSourceSetData.KEY
|
||||||
|
|
||||||
|
override fun postProcess(
|
||||||
|
toImport: Collection<DataNode<GradleSourceSetData>>,
|
||||||
|
projectData: ProjectData?,
|
||||||
|
project: Project,
|
||||||
|
modelsProvider: IdeModifiableModelsProvider
|
||||||
|
) {
|
||||||
|
for (sourceSetNode in toImport) {
|
||||||
|
val sourceSetData = sourceSetNode.data
|
||||||
|
val ideModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
|
||||||
|
|
||||||
|
val moduleNode = ExternalSystemApiUtil.findParent(sourceSetNode, ProjectKeys.MODULE) ?: continue
|
||||||
|
val sourceSetName = sourceSetNode.data.id.let { it.substring(it.lastIndexOf(':') + 1) }
|
||||||
|
val kotlinFacet = configureFacetByGradleModule(moduleNode, sourceSetName, ideModule, modelsProvider) ?: continue
|
||||||
|
GradleProjectImportHandler.getInstances(project).forEach { it.importBySourceSet(kotlinFacet, sourceSetNode) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinGradleProjectDataService : AbstractProjectDataService<ModuleData, Void>() {
|
||||||
|
override fun getTargetDataKey() = ProjectKeys.MODULE
|
||||||
|
|
||||||
|
override fun postProcess(
|
||||||
|
toImport: MutableCollection<DataNode<ModuleData>>,
|
||||||
|
projectData: ProjectData?,
|
||||||
|
project: Project,
|
||||||
|
modelsProvider: IdeModifiableModelsProvider
|
||||||
|
) {
|
||||||
|
for (moduleNode in toImport) {
|
||||||
|
// If source sets are present, configure facets in the their modules
|
||||||
|
if (ExternalSystemApiUtil.getChildren(moduleNode, GradleSourceSetData.KEY).isNotEmpty()) continue
|
||||||
|
|
||||||
|
val moduleData = moduleNode.data
|
||||||
|
val ideModule = modelsProvider.findIdeModule(moduleData) ?: continue
|
||||||
|
val kotlinFacet = configureFacetByGradleModule(moduleNode, null, ideModule, modelsProvider) ?: continue
|
||||||
|
GradleProjectImportHandler.getInstances(project).forEach { it.importByModule(kotlinFacet, moduleNode) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KotlinGradleLibraryDataService : AbstractProjectDataService<LibraryData, Void>() {
|
||||||
|
override fun getTargetDataKey() = ProjectKeys.LIBRARY
|
||||||
|
|
||||||
|
override fun postProcess(
|
||||||
|
toImport: MutableCollection<DataNode<LibraryData>>,
|
||||||
|
projectData: ProjectData?,
|
||||||
|
project: Project,
|
||||||
|
modelsProvider: IdeModifiableModelsProvider
|
||||||
|
) {
|
||||||
|
if (toImport.isEmpty()) return
|
||||||
|
val projectDataNode = toImport.first().parent!!
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
val moduleDataNodes = projectDataNode.children.filter { it.data is ModuleData } as List<DataNode<ModuleData>>
|
||||||
|
val anyNonJvmModules = moduleDataNodes.any { detectPlatformByPlugin(it)?.takeIf { it !is TargetPlatformKind.Jvm } != null }
|
||||||
|
for (libraryDataNode in toImport) {
|
||||||
|
val ideLibrary = modelsProvider.findIdeLibrary(libraryDataNode.data) ?: continue
|
||||||
|
|
||||||
|
val modifiableModel = modelsProvider.getModifiableLibraryModel(ideLibrary) as LibraryEx.ModifiableModelEx
|
||||||
|
if (anyNonJvmModules || ideLibrary.name?.looksAsNonJvmLibraryName() == true) {
|
||||||
|
detectLibraryKind(modifiableModel.getFiles(OrderRootType.CLASSES))?.let { modifiableModel.kind = it }
|
||||||
|
} else if (ideLibrary is LibraryImpl && (ideLibrary.kind === JSLibraryKind || ideLibrary.kind === CommonLibraryKind)) {
|
||||||
|
resetLibraryKind(modifiableModel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.looksAsNonJvmLibraryName() = nonJvmSuffixes.any { it in this }
|
||||||
|
|
||||||
|
private fun resetLibraryKind(modifiableModel: LibraryEx.ModifiableModelEx) {
|
||||||
|
try {
|
||||||
|
val cls = LibraryImpl::class.java
|
||||||
|
// Don't use name-based lookup because field names are scrambled in IDEA Ultimate
|
||||||
|
for (field in cls.declaredFields) {
|
||||||
|
if (field.type == PersistentLibraryKind::class.java) {
|
||||||
|
field.isAccessible = true
|
||||||
|
field.set(modifiableModel, null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG.info("Could not find field of type PersistentLibraryKind in LibraryImpl.class")
|
||||||
|
} catch (e: Exception) {
|
||||||
|
LOG.info("Failed to reset library kind", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val LOG = Logger.getInstance(KotlinGradleLibraryDataService::class.java)
|
||||||
|
|
||||||
|
val nonJvmSuffixes = listOf("-common", "-js", "-native", "-kjsm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun detectPlatformByPlugin(moduleNode: DataNode<ModuleData>): TargetPlatformKind<*>? {
|
||||||
|
return when (moduleNode.platformPluginId) {
|
||||||
|
"kotlin-platform-jvm" -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]
|
||||||
|
"kotlin-platform-js" -> TargetPlatformKind.JavaScript
|
||||||
|
"kotlin-platform-common" -> TargetPlatformKind.Common
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun detectPlatformByLibrary(moduleNode: DataNode<ModuleData>): TargetPlatformKind<*>? {
|
||||||
|
val detectedPlatforms =
|
||||||
|
mavenLibraryIdToPlatform.entries
|
||||||
|
.filter { moduleNode.getResolvedKotlinStdlibVersionByModuleData(listOf(it.key)) != null }
|
||||||
|
.map { it.value }.distinct()
|
||||||
|
return detectedPlatforms.singleOrNull() ?: detectedPlatforms.firstOrNull { it != TargetPlatformKind.Common }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun configureFacetByGradleModule(
|
||||||
|
moduleNode: DataNode<ModuleData>,
|
||||||
|
sourceSetName: String?,
|
||||||
|
ideModule: Module,
|
||||||
|
modelsProvider: IdeModifiableModelsProvider
|
||||||
|
): KotlinFacet? {
|
||||||
|
if (!moduleNode.isResolved) return null
|
||||||
|
|
||||||
|
if (!moduleNode.hasKotlinPlugin) {
|
||||||
|
val facetModel = modelsProvider.getModifiableFacetModel(ideModule)
|
||||||
|
val facet = facetModel.getFacetByType(KotlinFacetType.TYPE_ID)
|
||||||
|
if (facet != null) {
|
||||||
|
facetModel.removeFacet(facet)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val compilerVersion = moduleNode.findAll(BuildScriptClasspathData.KEY).firstOrNull()?.data?.let(::findKotlinPluginVersion)
|
||||||
|
?: return null
|
||||||
|
val platformKind = detectPlatformByPlugin(moduleNode) ?: detectPlatformByLibrary(moduleNode)
|
||||||
|
|
||||||
|
val coroutinesProperty = CoroutineSupport.byCompilerArgument(
|
||||||
|
moduleNode.coroutines ?: findKotlinCoroutinesProperty(ideModule.project)
|
||||||
|
)
|
||||||
|
|
||||||
|
val kotlinFacet = ideModule.getOrCreateFacet(modelsProvider, false)
|
||||||
|
kotlinFacet.configureFacet(compilerVersion, coroutinesProperty, platformKind, modelsProvider)
|
||||||
|
|
||||||
|
ideModule.compilerArgumentsBySourceSet = moduleNode.compilerArgumentsBySourceSet
|
||||||
|
ideModule.sourceSetName = sourceSetName
|
||||||
|
|
||||||
|
val argsInfo = moduleNode.compilerArgumentsBySourceSet?.get(sourceSetName ?: "main")
|
||||||
|
if (argsInfo != null) {
|
||||||
|
configureFacetByCompilerArguments(kotlinFacet, argsInfo, modelsProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
with(kotlinFacet.configuration.settings) {
|
||||||
|
implementedModuleNames = getImplementedModuleNames(moduleNode, sourceSetName, ideModule.project)
|
||||||
|
productionOutputPath = getExplicitOutputPath(moduleNode, platformKind, "main")
|
||||||
|
testOutputPath = getExplicitOutputPath(moduleNode, platformKind, "test")
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinFacet.noVersionAutoAdvance()
|
||||||
|
|
||||||
|
return kotlinFacet
|
||||||
|
}
|
||||||
|
|
||||||
|
fun configureFacetByCompilerArguments(kotlinFacet: KotlinFacet, argsInfo: ArgsInfo, modelsProvider: IdeModifiableModelsProvider?) {
|
||||||
|
val currentCompilerArguments = argsInfo.currentArguments
|
||||||
|
val defaultCompilerArguments = argsInfo.defaultArguments
|
||||||
|
val dependencyClasspath = argsInfo.dependencyClasspath.map { PathUtil.toSystemIndependentName(it) }
|
||||||
|
if (currentCompilerArguments.isNotEmpty()) {
|
||||||
|
parseCompilerArgumentsToFacet(currentCompilerArguments, defaultCompilerArguments, kotlinFacet, modelsProvider)
|
||||||
|
}
|
||||||
|
adjustClasspath(kotlinFacet, dependencyClasspath)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getImplementedModuleNames(moduleNode: DataNode<ModuleData>, sourceSetName: String?, project: Project): List<String> {
|
||||||
|
val baseModuleNames = moduleNode.implementedModuleNames
|
||||||
|
if (baseModuleNames.isEmpty() || sourceSetName == null) return baseModuleNames
|
||||||
|
val delimiter = if(isQualifiedModuleNamesEnabled(project)) "." else "_"
|
||||||
|
return baseModuleNames.map { "$it$delimiter$sourceSetName" }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getExplicitOutputPath(moduleNode: DataNode<ModuleData>, platformKind: TargetPlatformKind<*>?, sourceSet: String): String? {
|
||||||
|
if (platformKind !== TargetPlatformKind.JavaScript) return null
|
||||||
|
val k2jsArgumentList = moduleNode.compilerArgumentsBySourceSet?.get(sourceSet)?.currentArguments ?: return null
|
||||||
|
return K2JSCompilerArguments().apply { parseCommandLineArguments(k2jsArgumentList, this) }.outputFile
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun adjustClasspath(kotlinFacet: KotlinFacet, dependencyClasspath: List<String>) {
|
||||||
|
if (dependencyClasspath.isEmpty()) return
|
||||||
|
val arguments = kotlinFacet.configuration.settings.compilerArguments as? K2JVMCompilerArguments ?: return
|
||||||
|
val fullClasspath = arguments.classpath?.split(File.pathSeparator) ?: emptyList()
|
||||||
|
if (fullClasspath.isEmpty()) return
|
||||||
|
val newClasspath = fullClasspath - dependencyClasspath
|
||||||
|
arguments.classpath = if (newClasspath.isNotEmpty()) newClasspath.joinToString(File.pathSeparator) else null
|
||||||
|
}
|
||||||
|
|
||||||
|
private val gradlePropertyFiles = listOf("local.properties", "gradle.properties")
|
||||||
|
|
||||||
|
private fun findKotlinCoroutinesProperty(project: Project): String {
|
||||||
|
for (propertyFileName in gradlePropertyFiles) {
|
||||||
|
val propertyFile = project.baseDir.findChild(propertyFileName) ?: continue
|
||||||
|
val properties = Properties()
|
||||||
|
properties.load(propertyFile.inputStream)
|
||||||
|
properties.getProperty("kotlin.coroutines")?.let { return it }
|
||||||
|
}
|
||||||
|
|
||||||
|
return CoroutineSupport.getCompilerArgument(LanguageFeature.Coroutines.defaultState)
|
||||||
|
}
|
||||||
+375
@@ -0,0 +1,375 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.configuration
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.CodeInsightUtilCore
|
||||||
|
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix
|
||||||
|
import com.intellij.ide.actions.OpenFileAction
|
||||||
|
import com.intellij.openapi.extensions.Extensions
|
||||||
|
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||||
|
import com.intellij.openapi.fileEditor.OpenFileDescriptor
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.module.ModuleUtil
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.projectRoots.Sdk
|
||||||
|
import com.intellij.openapi.roots.DependencyScope
|
||||||
|
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||||
|
import com.intellij.openapi.roots.ModuleRootManager
|
||||||
|
import com.intellij.openapi.ui.Messages
|
||||||
|
import com.intellij.openapi.vfs.VfsUtil
|
||||||
|
import com.intellij.openapi.vfs.WritingAccessProvider
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import org.jetbrains.kotlin.config.ApiVersion
|
||||||
|
import org.jetbrains.kotlin.config.CoroutineSupport
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.idea.facet.getRuntimeLibraryVersion
|
||||||
|
import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.ChangeCoroutineSupportFix
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.executeCommand
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.versions.getStdlibArtifactId
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||||
|
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
|
||||||
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
|
||||||
|
|
||||||
|
override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus {
|
||||||
|
val module = moduleSourceRootGroup.baseModule
|
||||||
|
if (!isApplicable(module)) {
|
||||||
|
return ConfigureKotlinStatus.NON_APPLICABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moduleSourceRootGroup.sourceRootModules.all(::hasAnyKotlinRuntimeInScope)) {
|
||||||
|
return ConfigureKotlinStatus.CONFIGURED
|
||||||
|
}
|
||||||
|
|
||||||
|
val buildFiles = runReadAction {
|
||||||
|
listOf(
|
||||||
|
module.getBuildScriptPsiFile(),
|
||||||
|
module.project.getTopLevelBuildScriptPsiFile()
|
||||||
|
).filterNotNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildFiles.isEmpty()) {
|
||||||
|
return ConfigureKotlinStatus.NON_APPLICABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildFiles.none { it.isConfiguredByAnyGradleConfigurator() }) {
|
||||||
|
return ConfigureKotlinStatus.CAN_BE_CONFIGURED
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConfigureKotlinStatus.BROKEN
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PsiFile.isConfiguredByAnyGradleConfigurator(): Boolean {
|
||||||
|
return Extensions.getExtensions(KotlinProjectConfigurator.EP_NAME)
|
||||||
|
.filterIsInstance<KotlinWithGradleConfigurator>()
|
||||||
|
.any { it.isFileConfigured(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun isApplicable(module: Module): Boolean =
|
||||||
|
module.getBuildSystemType() == Gradle
|
||||||
|
|
||||||
|
protected open fun getMinimumSupportedVersion() = "1.0.0"
|
||||||
|
|
||||||
|
private fun isFileConfigured(buildScript: PsiFile): Boolean = getManipulator(buildScript).isConfigured(kotlinPluginName)
|
||||||
|
|
||||||
|
@JvmSuppressWildcards
|
||||||
|
override fun configure(project: Project, excludeModules: Collection<Module>) {
|
||||||
|
val dialog = ConfigureDialogWithModulesAndVersion(project, this, excludeModules, getMinimumSupportedVersion())
|
||||||
|
|
||||||
|
dialog.show()
|
||||||
|
if (!dialog.isOK) return
|
||||||
|
|
||||||
|
val collector = configureSilently(project, dialog.modulesToConfigure, dialog.kotlinVersion)
|
||||||
|
collector.showNotification()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun configureSilently(project: Project, modules: List<Module>, version: String): NotificationMessageCollector {
|
||||||
|
return project.executeCommand("Configure Kotlin") {
|
||||||
|
val collector = createConfigureKotlinNotificationCollector(project)
|
||||||
|
val changedFiles = configureWithVersion(project, modules, version, collector)
|
||||||
|
|
||||||
|
for (file in changedFiles) {
|
||||||
|
OpenFileAction.openFile(file.virtualFile, project)
|
||||||
|
}
|
||||||
|
collector
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun configureWithVersion(
|
||||||
|
project: Project,
|
||||||
|
modulesToConfigure: List<Module>,
|
||||||
|
kotlinVersion: String,
|
||||||
|
collector: NotificationMessageCollector
|
||||||
|
): HashSet<PsiFile> {
|
||||||
|
val filesToOpen = HashSet<PsiFile>()
|
||||||
|
val buildScript = project.getTopLevelBuildScriptPsiFile()
|
||||||
|
if (buildScript != null && canConfigureFile(buildScript)) {
|
||||||
|
val isModified = configureBuildScript(buildScript, true, kotlinVersion, collector)
|
||||||
|
if (isModified) {
|
||||||
|
filesToOpen.add(buildScript)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (module in modulesToConfigure) {
|
||||||
|
val file = module.getBuildScriptPsiFile()
|
||||||
|
if (file != null && canConfigureFile(file)) {
|
||||||
|
configureModule(module, file, false, kotlinVersion, collector, filesToOpen)
|
||||||
|
} else {
|
||||||
|
showErrorMessage(project, "Cannot find build.gradle file for module " + module.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filesToOpen
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun configureModule(
|
||||||
|
module: Module,
|
||||||
|
file: PsiFile,
|
||||||
|
isTopLevelProjectFile: Boolean,
|
||||||
|
version: String,
|
||||||
|
collector: NotificationMessageCollector,
|
||||||
|
filesToOpen: MutableCollection<PsiFile>
|
||||||
|
) {
|
||||||
|
val isModified = configureBuildScript(file, isTopLevelProjectFile, version, collector)
|
||||||
|
if (isModified) {
|
||||||
|
filesToOpen.add(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun configureModuleBuildScript(file: PsiFile, version: String): Boolean {
|
||||||
|
val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk }
|
||||||
|
val jvmTarget = getJvmTarget(sdk, version)
|
||||||
|
return getManipulator(file).configureModuleBuildScript(
|
||||||
|
kotlinPluginName,
|
||||||
|
getStdlibArtifactName(sdk, version),
|
||||||
|
version,
|
||||||
|
jvmTarget
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun getStdlibArtifactName(sdk: Sdk?, version: String) = getStdlibArtifactId(sdk, version)
|
||||||
|
|
||||||
|
protected open fun getJvmTarget(sdk: Sdk?, version: String): String? = null
|
||||||
|
|
||||||
|
protected abstract val kotlinPluginName: String
|
||||||
|
|
||||||
|
protected open fun addElementsToFile(
|
||||||
|
file: PsiFile,
|
||||||
|
isTopLevelProjectFile: Boolean,
|
||||||
|
version: String
|
||||||
|
): Boolean {
|
||||||
|
if (!isTopLevelProjectFile) {
|
||||||
|
var wasModified = configureProjectFile(file, version)
|
||||||
|
wasModified = wasModified or configureModuleBuildScript(file, version)
|
||||||
|
return wasModified
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun configureBuildScript(
|
||||||
|
file: PsiFile,
|
||||||
|
isTopLevelProjectFile: Boolean,
|
||||||
|
version: String,
|
||||||
|
collector: NotificationMessageCollector
|
||||||
|
): Boolean {
|
||||||
|
val isModified = file.project.executeWriteCommand("Configure ${file.name}", null) {
|
||||||
|
val isModified = addElementsToFile(file, isTopLevelProjectFile, version)
|
||||||
|
|
||||||
|
CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(file)
|
||||||
|
isModified
|
||||||
|
}
|
||||||
|
|
||||||
|
val virtualFile = file.virtualFile
|
||||||
|
if (virtualFile != null && isModified) {
|
||||||
|
collector.addMessage(virtualFile.path + " was modified")
|
||||||
|
}
|
||||||
|
return isModified
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateLanguageVersion(
|
||||||
|
module: Module,
|
||||||
|
languageVersion: String?,
|
||||||
|
apiVersion: String?,
|
||||||
|
requiredStdlibVersion: ApiVersion,
|
||||||
|
forTests: Boolean
|
||||||
|
) {
|
||||||
|
val runtimeUpdateRequired = getRuntimeLibraryVersion(module)?.let { ApiVersion.parse(it) }?.let { runtimeVersion ->
|
||||||
|
runtimeVersion < requiredStdlibVersion
|
||||||
|
} ?: false
|
||||||
|
|
||||||
|
if (runtimeUpdateRequired) {
|
||||||
|
Messages.showErrorDialog(
|
||||||
|
module.project,
|
||||||
|
"This language feature requires version $requiredStdlibVersion or later of the Kotlin runtime library. " +
|
||||||
|
"Please update the version in your build script.",
|
||||||
|
"Update Language Version"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val element = changeLanguageVersion(module, languageVersion, apiVersion, forTests)
|
||||||
|
|
||||||
|
element?.let {
|
||||||
|
OpenFileDescriptor(module.project, it.containingFile.virtualFile, it.textRange.startOffset).navigate(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun changeCoroutineConfiguration(module: Module, state: LanguageFeature.State) {
|
||||||
|
val runtimeUpdateRequired = state != LanguageFeature.State.DISABLED &&
|
||||||
|
(getRuntimeLibraryVersion(module)?.startsWith("1.0") ?: false)
|
||||||
|
|
||||||
|
if (runtimeUpdateRequired) {
|
||||||
|
Messages.showErrorDialog(
|
||||||
|
module.project,
|
||||||
|
"Coroutines support requires version 1.1 or later of the Kotlin runtime library. " +
|
||||||
|
"Please update the version in your build script.",
|
||||||
|
ChangeCoroutineSupportFix.getFixText(state)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val element = changeCoroutineConfiguration(module, CoroutineSupport.getCompilerArgument(state))
|
||||||
|
if (element != null) {
|
||||||
|
OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addLibraryDependency(
|
||||||
|
module: Module,
|
||||||
|
element: PsiElement,
|
||||||
|
library: ExternalLibraryDescriptor,
|
||||||
|
libraryJarDescriptors: List<LibraryJarDescriptor>
|
||||||
|
) {
|
||||||
|
val scope = OrderEntryFix.suggestScopeByLocation(module, element)
|
||||||
|
KotlinWithGradleConfigurator.addKotlinLibraryToModule(module, scope, library)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun getManipulator(file: PsiFile): GradleBuildScriptManipulator = when (file) {
|
||||||
|
is KtFile -> KotlinBuildScriptManipulator(file)
|
||||||
|
is GroovyFile -> GroovyBuildScriptManipulator(file)
|
||||||
|
else -> error("Unknown build script file type!")
|
||||||
|
}
|
||||||
|
|
||||||
|
val GROUP_ID = "org.jetbrains.kotlin"
|
||||||
|
val GRADLE_PLUGIN_ID = "kotlin-gradle-plugin"
|
||||||
|
|
||||||
|
val CLASSPATH = "classpath \"$GROUP_ID:$GRADLE_PLUGIN_ID:\$kotlin_version\""
|
||||||
|
|
||||||
|
private val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts"
|
||||||
|
|
||||||
|
fun getGroovyDependencySnippet(artifactName: String, scope: String) =
|
||||||
|
"$scope \"org.jetbrains.kotlin:$artifactName:\$kotlin_version\""
|
||||||
|
|
||||||
|
fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'"
|
||||||
|
|
||||||
|
fun addKotlinLibraryToModule(module: Module, scope: DependencyScope, libraryDescriptor: ExternalLibraryDescriptor) {
|
||||||
|
val buildScript = module.getBuildScriptPsiFile() ?: return
|
||||||
|
if (!canConfigureFile(buildScript)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
getManipulator(buildScript)
|
||||||
|
.addKotlinLibraryToModuleBuildScript(scope, libraryDescriptor, module.getBuildSystemType() == AndroidGradle)
|
||||||
|
|
||||||
|
buildScript.virtualFile?.let {
|
||||||
|
createConfigureKotlinNotificationCollector(buildScript.project)
|
||||||
|
.addMessage(it.path + " was modified")
|
||||||
|
.showNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeCoroutineConfiguration(module: Module, coroutineOption: String): PsiElement? = changeBuildGradle(module) {
|
||||||
|
getManipulator(it).changeCoroutineConfiguration(coroutineOption)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeLanguageVersion(module: Module, languageVersion: String?, apiVersion: String?, forTests: Boolean) =
|
||||||
|
changeBuildGradle(module) { buildScriptFile ->
|
||||||
|
val manipulator = getManipulator(buildScriptFile)
|
||||||
|
var result: PsiElement? = null
|
||||||
|
if (languageVersion != null) {
|
||||||
|
result = manipulator.changeLanguageVersion(languageVersion, forTests)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiVersion != null) {
|
||||||
|
result = manipulator.changeApiVersion(apiVersion, forTests)
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun changeBuildGradle(module: Module, body: (PsiFile) -> PsiElement?): PsiElement? {
|
||||||
|
val buildScriptFile = module.getBuildScriptPsiFile()
|
||||||
|
if (buildScriptFile != null && canConfigureFile(buildScriptFile)) {
|
||||||
|
return buildScriptFile.project.executeWriteCommand("Change build.gradle configuration", null) {
|
||||||
|
body(buildScriptFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getKotlinStdlibVersion(module: Module): String? {
|
||||||
|
return module.getBuildScriptPsiFile()?.let {
|
||||||
|
getManipulator(it).getKotlinStdlibVersion()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun configureProjectFile(file: PsiFile, version: String): Boolean = getManipulator(file).configureProjectBuildScript(version)
|
||||||
|
|
||||||
|
private fun canConfigureFile(file: PsiFile): Boolean = WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null)
|
||||||
|
|
||||||
|
private fun Module.getBuildScriptPsiFile() = getBuildScriptFile()?.getPsiFile(project)
|
||||||
|
|
||||||
|
private fun Project.getTopLevelBuildScriptPsiFile() = basePath?.let { findBuildGradleFile(it)?.getPsiFile(this) }
|
||||||
|
|
||||||
|
private fun Module.getBuildScriptFile(): File? {
|
||||||
|
val moduleDir = File(moduleFilePath).parent
|
||||||
|
findBuildGradleFile(moduleDir)?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleRootManager.getInstance(this).contentRoots.forEach { root ->
|
||||||
|
findBuildGradleFile(root.path)?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExternalSystemApiUtil.getExternalProjectPath(this)?.let { externalProjectPath ->
|
||||||
|
findBuildGradleFile(externalProjectPath)?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findBuildGradleFile(path: String): File? =
|
||||||
|
File(path + "/" + GradleConstants.DEFAULT_SCRIPT_NAME).takeIf { it.exists() }
|
||||||
|
?: File(path + "/" + KOTLIN_BUILD_SCRIPT_NAME).takeIf { it.exists() }
|
||||||
|
|
||||||
|
private fun File.getPsiFile(project: Project) = VfsUtil.findFileByIoFile(this, true)?.let {
|
||||||
|
PsiManager.getInstance(project).findFile(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showErrorMessage(project: Project, message: String?) {
|
||||||
|
Messages.showErrorDialog(
|
||||||
|
project,
|
||||||
|
"<html>Couldn't configure kotlin-gradle plugin automatically.<br/>" +
|
||||||
|
(if (message != null) message + "<br/>" else "") +
|
||||||
|
"<br/>See manual installation instructions <a href=\"https://kotlinlang.org/docs/reference/using-gradle.html\">here</a>.</html>",
|
||||||
|
"Configure Kotlin-Gradle Plugin"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1912
File diff suppressed because it is too large
Load Diff
+51
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.framework;
|
||||||
|
|
||||||
|
import com.intellij.framework.library.LibraryVersionProperties;
|
||||||
|
import com.intellij.openapi.roots.libraries.LibraryPresentationProvider;
|
||||||
|
import com.intellij.openapi.roots.libraries.LibraryProperties;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinIcons;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class JavaRuntimePresentationProvider extends LibraryPresentationProvider<LibraryVersionProperties> {
|
||||||
|
public static JavaRuntimePresentationProvider getInstance() {
|
||||||
|
return LibraryPresentationProvider.EP_NAME.findExtension(JavaRuntimePresentationProvider.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JavaRuntimePresentationProvider() {
|
||||||
|
super(JavaRuntimeLibraryDescription.Companion.getKOTLIN_JAVA_RUNTIME_KIND());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Icon getIcon(@Nullable LibraryVersionProperties properties) {
|
||||||
|
return KotlinIcons.SMALL_LOGO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public LibraryVersionProperties detect(@NotNull List<VirtualFile> classesRoots) {
|
||||||
|
String version = JavaRuntimeDetectionUtil.getJavaRuntimeVersion(classesRoots);
|
||||||
|
return version == null ? null : new LibraryVersionProperties(version);
|
||||||
|
}
|
||||||
|
}
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.quickfix
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.intention.IntentionAction
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.module.ModuleUtilCore
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.BuildSystemType
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.findApplicableConfigurator
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.getBuildSystemType
|
||||||
|
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
|
||||||
|
sealed class ChangeCoroutineSupportFix(
|
||||||
|
element: PsiElement,
|
||||||
|
protected val coroutineSupport: LanguageFeature.State
|
||||||
|
) : KotlinQuickFixAction<PsiElement>(element) {
|
||||||
|
protected val coroutineSupportEnabled: Boolean
|
||||||
|
get() = coroutineSupport == LanguageFeature.State.ENABLED || coroutineSupport == LanguageFeature.State.ENABLED_WITH_WARNING
|
||||||
|
|
||||||
|
class InModule(element: PsiElement, coroutineSupport: LanguageFeature.State) : ChangeCoroutineSupportFix(element, coroutineSupport) {
|
||||||
|
override fun getText() = "${super.getText()} in the current module"
|
||||||
|
|
||||||
|
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
|
val module = ModuleUtilCore.findModuleForPsiElement(file) ?: return
|
||||||
|
|
||||||
|
findApplicableConfigurator(module).changeCoroutineConfiguration(module, coroutineSupport)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InProject(element: PsiElement, coroutineSupport: LanguageFeature.State) : ChangeCoroutineSupportFix(element, coroutineSupport) {
|
||||||
|
override fun getText() = "${super.getText()} in the project"
|
||||||
|
|
||||||
|
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||||
|
if (coroutineSupportEnabled) {
|
||||||
|
if (!checkUpdateRuntime(project, LanguageFeature.Coroutines.sinceApiVersion)) return
|
||||||
|
}
|
||||||
|
|
||||||
|
KotlinCommonCompilerArgumentsHolder.getInstance(project).update {
|
||||||
|
coroutinesState = when (coroutineSupport) {
|
||||||
|
LanguageFeature.State.ENABLED -> CommonCompilerArguments.ENABLE
|
||||||
|
LanguageFeature.State.ENABLED_WITH_WARNING -> CommonCompilerArguments.WARN
|
||||||
|
LanguageFeature.State.ENABLED_WITH_ERROR, LanguageFeature.State.DISABLED -> CommonCompilerArguments.ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ProjectRootManagerEx.getInstanceEx(project).makeRootsChange({}, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFamilyName() = "Enable/Disable coroutine support"
|
||||||
|
|
||||||
|
override fun getText(): String {
|
||||||
|
return getFixText(coroutineSupport)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : KotlinIntentionActionsFactory() {
|
||||||
|
fun getFixText(state: LanguageFeature.State): String {
|
||||||
|
return when (state) {
|
||||||
|
LanguageFeature.State.ENABLED -> "Enable coroutine support"
|
||||||
|
LanguageFeature.State.ENABLED_WITH_WARNING -> "Enable coroutine support (with warning)"
|
||||||
|
LanguageFeature.State.ENABLED_WITH_ERROR, LanguageFeature.State.DISABLED -> "Disable coroutine support"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||||
|
val newCoroutineSupports = when (diagnostic.factory) {
|
||||||
|
Errors.EXPERIMENTAL_FEATURE_ERROR -> {
|
||||||
|
if (Errors.EXPERIMENTAL_FEATURE_ERROR.cast(diagnostic).a.first != LanguageFeature.Coroutines) return emptyList()
|
||||||
|
listOf(LanguageFeature.State.ENABLED_WITH_WARNING, LanguageFeature.State.ENABLED)
|
||||||
|
}
|
||||||
|
Errors.EXPERIMENTAL_FEATURE_WARNING -> {
|
||||||
|
if (Errors.EXPERIMENTAL_FEATURE_WARNING.cast(diagnostic).a.first != LanguageFeature.Coroutines) return emptyList()
|
||||||
|
listOf(LanguageFeature.State.ENABLED, LanguageFeature.State.ENABLED_WITH_ERROR)
|
||||||
|
}
|
||||||
|
else -> return emptyList()
|
||||||
|
}
|
||||||
|
val module = ModuleUtilCore.findModuleForPsiElement(diagnostic.psiElement) ?: return emptyList()
|
||||||
|
val facetSettings = KotlinFacet.get(module)?.configuration?.settings
|
||||||
|
|
||||||
|
val configureInProject = (facetSettings == null || facetSettings.useProjectSettings) &&
|
||||||
|
module.getBuildSystemType() == BuildSystemType.JPS
|
||||||
|
val quickFixConstructor: (PsiElement, LanguageFeature.State) -> ChangeCoroutineSupportFix =
|
||||||
|
if (configureInProject) ::InProject else ::InModule
|
||||||
|
return newCoroutineSupports.map { quickFixConstructor(diagnostic.psiElement, it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile(project(":core:util.runtime"))
|
||||||
|
compile(project(":compiler:frontend"))
|
||||||
|
compile(project(":compiler:frontend.java"))
|
||||||
|
compile(project(":compiler:util"))
|
||||||
|
compile(project(":compiler:cli-common"))
|
||||||
|
compile(project(":kotlin-build-common"))
|
||||||
|
|
||||||
|
compile(project(":js:js.frontend"))
|
||||||
|
|
||||||
|
compile(project(":idea"))
|
||||||
|
compile(project(":idea:idea-jvm"))
|
||||||
|
compile(project(":idea:idea-jps-common"))
|
||||||
|
|
||||||
|
compileOnly(intellijDep())
|
||||||
|
excludeInAndroidStudio(rootProject) { compileOnly(intellijPluginDep("maven")) }
|
||||||
|
|
||||||
|
testCompile(projectTests(":idea"))
|
||||||
|
testCompile(projectTests(":compiler:tests-common"))
|
||||||
|
testCompile(projectTests(":idea:idea-test-framework"))
|
||||||
|
|
||||||
|
testCompileOnly(intellijDep())
|
||||||
|
//testCompileOnly(intellijPluginDep("maven"))
|
||||||
|
|
||||||
|
testRuntime(projectDist(":kotlin-reflect"))
|
||||||
|
testRuntime(project(":idea:idea-jvm"))
|
||||||
|
testRuntime(project(":idea:idea-android"))
|
||||||
|
testRuntime(project(":plugins:android-extensions-ide"))
|
||||||
|
testRuntime(project(":plugins:lint"))
|
||||||
|
testRuntime(project(":sam-with-receiver-ide-plugin"))
|
||||||
|
testRuntime(project(":allopen-ide-plugin"))
|
||||||
|
testRuntime(project(":noarg-ide-plugin"))
|
||||||
|
|
||||||
|
testRuntime(intellijDep())
|
||||||
|
// TODO: the order of the plugins matters here, consider avoiding order-dependency
|
||||||
|
testRuntime(intellijPluginDep("junit"))
|
||||||
|
testRuntime(intellijPluginDep("testng"))
|
||||||
|
testRuntime(intellijPluginDep("properties"))
|
||||||
|
testRuntime(intellijPluginDep("gradle"))
|
||||||
|
testRuntime(intellijPluginDep("Groovy"))
|
||||||
|
testRuntime(intellijPluginDep("coverage"))
|
||||||
|
//testRuntime(intellijPluginDep("maven"))
|
||||||
|
testRuntime(intellijPluginDep("android"))
|
||||||
|
testRuntime(intellijPluginDep("smali"))
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { /*projectDefault()*/ }
|
||||||
|
"test" { /*projectDefault()*/ }
|
||||||
|
}
|
||||||
|
|
||||||
|
testsJar()
|
||||||
|
|
||||||
|
projectTest {
|
||||||
|
workingDir = rootDir
|
||||||
|
}
|
||||||
+326
@@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.maven.configuration
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.CodeInsightUtilCore
|
||||||
|
import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix
|
||||||
|
import com.intellij.ide.actions.OpenFileAction
|
||||||
|
import com.intellij.ide.highlighter.JavaFileType
|
||||||
|
import com.intellij.openapi.command.WriteCommandAction
|
||||||
|
import com.intellij.openapi.fileEditor.OpenFileDescriptor
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.module.ModuleUtilCore
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.roots.ExternalLibraryDescriptor
|
||||||
|
import com.intellij.openapi.roots.JavaProjectModelModificationService
|
||||||
|
import com.intellij.openapi.ui.Messages
|
||||||
|
import com.intellij.openapi.vfs.WritingAccessProvider
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.psi.search.FileTypeIndex
|
||||||
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
|
import com.intellij.psi.xml.XmlFile
|
||||||
|
import org.jetbrains.idea.maven.dom.MavenDomUtil
|
||||||
|
import org.jetbrains.idea.maven.dom.model.MavenDomPlugin
|
||||||
|
import org.jetbrains.idea.maven.model.MavenId
|
||||||
|
import org.jetbrains.idea.maven.project.MavenProjectsManager
|
||||||
|
import org.jetbrains.idea.maven.utils.MavenArtifactScope
|
||||||
|
import org.jetbrains.kotlin.config.ApiVersion
|
||||||
|
import org.jetbrains.kotlin.config.CoroutineSupport
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.idea.configuration.*
|
||||||
|
import org.jetbrains.kotlin.idea.facet.getRuntimeLibraryVersion
|
||||||
|
import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion
|
||||||
|
import org.jetbrains.kotlin.idea.maven.*
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.ChangeCoroutineSupportFix
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
|
||||||
|
|
||||||
|
abstract class KotlinMavenConfigurator
|
||||||
|
protected constructor(
|
||||||
|
private val testArtifactId: String?,
|
||||||
|
private val addJunit: Boolean,
|
||||||
|
override val name: String,
|
||||||
|
override val presentableText: String
|
||||||
|
) : KotlinProjectConfigurator {
|
||||||
|
|
||||||
|
override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus {
|
||||||
|
val module = moduleSourceRootGroup.baseModule
|
||||||
|
if (module.getBuildSystemType() != Maven)
|
||||||
|
return ConfigureKotlinStatus.NON_APPLICABLE
|
||||||
|
|
||||||
|
val psi = runReadAction { findModulePomFile(module) }
|
||||||
|
if (psi == null
|
||||||
|
|| !psi.isValid
|
||||||
|
|| psi !is XmlFile
|
||||||
|
|| psi.virtualFile == null) {
|
||||||
|
return ConfigureKotlinStatus.BROKEN
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isKotlinModule(module)) {
|
||||||
|
return runReadAction { checkKotlinPlugin(module) }
|
||||||
|
}
|
||||||
|
return ConfigureKotlinStatus.CAN_BE_CONFIGURED
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkKotlinPlugin(module: Module): ConfigureKotlinStatus {
|
||||||
|
val psi = findModulePomFile(module) as? XmlFile ?: return ConfigureKotlinStatus.BROKEN
|
||||||
|
val pom = PomFile.forFileOrNull(psi) ?: return ConfigureKotlinStatus.NON_APPLICABLE
|
||||||
|
|
||||||
|
if (hasKotlinPlugin(pom)) {
|
||||||
|
return ConfigureKotlinStatus.CONFIGURED
|
||||||
|
}
|
||||||
|
|
||||||
|
val mavenProjectsManager = MavenProjectsManager.getInstance(module.project)
|
||||||
|
val mavenProject = mavenProjectsManager.findProject(module) ?: return ConfigureKotlinStatus.BROKEN
|
||||||
|
|
||||||
|
val kotlinPluginId = kotlinPluginId(null)
|
||||||
|
val kotlinPlugin = mavenProject.plugins.find { it.mavenId.equals(kotlinPluginId.groupId, kotlinPluginId.artifactId) }
|
||||||
|
?: return ConfigureKotlinStatus.CAN_BE_CONFIGURED
|
||||||
|
|
||||||
|
if (kotlinPlugin.executions.any { it.goals.any(this::isRelevantGoal) }) {
|
||||||
|
return ConfigureKotlinStatus.CONFIGURED
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConfigureKotlinStatus.CAN_BE_CONFIGURED
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hasKotlinPlugin(pom: PomFile): Boolean {
|
||||||
|
val plugin = pom.findPlugin(kotlinPluginId(null)) ?: return false
|
||||||
|
|
||||||
|
return plugin.executions.executions.any {
|
||||||
|
it.goals.goals.any { isRelevantGoal(it.stringValue ?: "") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun configure(project: Project, excludeModules: Collection<Module>) {
|
||||||
|
val dialog = ConfigureDialogWithModulesAndVersion(project, this, excludeModules, getMinimumSupportedVersion())
|
||||||
|
|
||||||
|
dialog.show()
|
||||||
|
if (!dialog.isOK) return
|
||||||
|
|
||||||
|
WriteCommandAction.runWriteCommandAction(project) {
|
||||||
|
val collector = createConfigureKotlinNotificationCollector(project)
|
||||||
|
for (module in excludeMavenChildrenModules(project, dialog.modulesToConfigure)) {
|
||||||
|
val file = findModulePomFile(module)
|
||||||
|
if (file != null && canConfigureFile(file)) {
|
||||||
|
configureModule(module, file, dialog.kotlinVersion, collector)
|
||||||
|
OpenFileAction.openFile(file.virtualFile, project)
|
||||||
|
} else {
|
||||||
|
showErrorMessage(project, "Cannot find pom.xml for module " + module.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collector.showNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun getMinimumSupportedVersion() = "1.0.0"
|
||||||
|
|
||||||
|
protected abstract fun isKotlinModule(module: Module): Boolean
|
||||||
|
protected abstract fun isRelevantGoal(goalName: String): Boolean
|
||||||
|
|
||||||
|
protected abstract fun createExecutions(pomFile: PomFile, kotlinPlugin: MavenDomPlugin, module: Module)
|
||||||
|
protected abstract fun getStdlibArtifactId(module: Module, version: String): String
|
||||||
|
|
||||||
|
open fun configureModule(module: Module, file: PsiFile, version: String, collector: NotificationMessageCollector): Boolean =
|
||||||
|
changePomFile(module, file, version, collector)
|
||||||
|
|
||||||
|
private fun changePomFile(
|
||||||
|
module: Module,
|
||||||
|
file: PsiFile,
|
||||||
|
version: String,
|
||||||
|
collector: NotificationMessageCollector
|
||||||
|
): Boolean {
|
||||||
|
val virtualFile = file.virtualFile ?: error("Virtual file should exists for psi file " + file.name)
|
||||||
|
val domModel = MavenDomUtil.getMavenDomProjectModel(module.project, virtualFile)
|
||||||
|
if (domModel == null) {
|
||||||
|
showErrorMessage(module.project, null)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val pom = PomFile.forFileOrNull(file as XmlFile) ?: return false
|
||||||
|
pom.addProperty(KOTLIN_VERSION_PROPERTY, version)
|
||||||
|
|
||||||
|
pom.addDependency(
|
||||||
|
MavenId(GROUP_ID, getStdlibArtifactId(module, version), "\${$KOTLIN_VERSION_PROPERTY}"),
|
||||||
|
MavenArtifactScope.COMPILE,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
if (testArtifactId != null) {
|
||||||
|
pom.addDependency(MavenId(GROUP_ID, testArtifactId, "\${$KOTLIN_VERSION_PROPERTY}"), MavenArtifactScope.TEST, null, false, null)
|
||||||
|
}
|
||||||
|
if (addJunit) {
|
||||||
|
// TODO currently it is always disabled: junit version selection could be shown in the configurator dialog
|
||||||
|
pom.addDependency(MavenId("junit", "junit", "4.12"), MavenArtifactScope.TEST, null, false, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
val repositoryDescription = getRepositoryForVersion(version)
|
||||||
|
if (repositoryDescription != null) {
|
||||||
|
pom.addLibraryRepository(repositoryDescription)
|
||||||
|
pom.addPluginRepository(repositoryDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
val plugin = pom.addPlugin(MavenId(GROUP_ID, MAVEN_PLUGIN_ID, "\${$KOTLIN_VERSION_PROPERTY}"))
|
||||||
|
createExecutions(pom, plugin, module)
|
||||||
|
|
||||||
|
configurePlugin(pom, plugin, module, version)
|
||||||
|
|
||||||
|
CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement<PsiFile>(file)
|
||||||
|
|
||||||
|
collector.addMessage(virtualFile.path + " was modified")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun configurePlugin(pom: PomFile, plugin: MavenDomPlugin, module: Module, version: String) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun createExecution(
|
||||||
|
pomFile: PomFile,
|
||||||
|
kotlinPlugin: MavenDomPlugin,
|
||||||
|
executionId: String,
|
||||||
|
goalName: String,
|
||||||
|
module: Module,
|
||||||
|
isTest: Boolean
|
||||||
|
) {
|
||||||
|
pomFile.addKotlinExecution(module, kotlinPlugin, executionId, PomFile.getPhase(false, isTest), isTest, listOf(goalName))
|
||||||
|
|
||||||
|
if (hasJavaFiles(module)) {
|
||||||
|
pomFile.addJavacExecutions(module, kotlinPlugin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateLanguageVersion(
|
||||||
|
module: Module,
|
||||||
|
languageVersion: String?,
|
||||||
|
apiVersion: String?,
|
||||||
|
requiredStdlibVersion: ApiVersion,
|
||||||
|
forTests: Boolean
|
||||||
|
) {
|
||||||
|
fun doUpdateMavenLanguageVersion(): PsiElement? {
|
||||||
|
val psi = KotlinMavenConfigurator.findModulePomFile(module) as? XmlFile ?: return null
|
||||||
|
val pom = PomFile.forFileOrNull(psi) ?: return null
|
||||||
|
return pom.changeLanguageVersion(
|
||||||
|
languageVersion,
|
||||||
|
apiVersion
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val runtimeUpdateRequired = getRuntimeLibraryVersion(module)?.let { ApiVersion.parse(it) }?.let { runtimeVersion ->
|
||||||
|
runtimeVersion < requiredStdlibVersion
|
||||||
|
} ?: false
|
||||||
|
|
||||||
|
if (runtimeUpdateRequired) {
|
||||||
|
Messages.showErrorDialog(
|
||||||
|
module.project,
|
||||||
|
"This language feature requires version $requiredStdlibVersion or later of the Kotlin runtime library. " +
|
||||||
|
"Please update the version in your build script.",
|
||||||
|
"Update Language Version"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val element = doUpdateMavenLanguageVersion()
|
||||||
|
if (element == null) {
|
||||||
|
Messages.showErrorDialog(
|
||||||
|
module.project,
|
||||||
|
"Failed to update.pom.xml. Please update the file manually.",
|
||||||
|
"Update Language Version"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addLibraryDependency(
|
||||||
|
module: Module,
|
||||||
|
element: PsiElement,
|
||||||
|
library: ExternalLibraryDescriptor,
|
||||||
|
libraryJarDescriptors: List<LibraryJarDescriptor>
|
||||||
|
) {
|
||||||
|
val scope = OrderEntryFix.suggestScopeByLocation(module, element)
|
||||||
|
JavaProjectModelModificationService.getInstance(module.project).addDependency(module, library, scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun changeCoroutineConfiguration(module: Module, state: LanguageFeature.State) {
|
||||||
|
val runtimeUpdateRequired = state != LanguageFeature.State.DISABLED &&
|
||||||
|
(getRuntimeLibraryVersion(module)?.startsWith("1.0") ?: false)
|
||||||
|
|
||||||
|
val messageTitle = ChangeCoroutineSupportFix.getFixText(state)
|
||||||
|
if (runtimeUpdateRequired) {
|
||||||
|
Messages.showErrorDialog(
|
||||||
|
module.project,
|
||||||
|
"Coroutines support requires version 1.1 or later of the Kotlin runtime library. " +
|
||||||
|
"Please update the version in your build script.",
|
||||||
|
messageTitle
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val element = changeMavenCoroutineConfiguration(module, CoroutineSupport.getCompilerArgument(state), messageTitle)
|
||||||
|
|
||||||
|
if (element != null) {
|
||||||
|
OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun changeMavenCoroutineConfiguration(module: Module, value: String, messageTitle: String): PsiElement? {
|
||||||
|
fun doChangeMavenCoroutineConfiguration(): PsiElement? {
|
||||||
|
val psi = KotlinMavenConfigurator.findModulePomFile(module) as? XmlFile ?: return null
|
||||||
|
val pom = PomFile.forFileOrNull(psi) ?: return null
|
||||||
|
return pom.changeCoroutineConfiguration(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
val element = doChangeMavenCoroutineConfiguration()
|
||||||
|
if (element == null) {
|
||||||
|
Messages.showErrorDialog(
|
||||||
|
module.project,
|
||||||
|
"Failed to update.pom.xml. Please update the file manually.",
|
||||||
|
messageTitle
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val GROUP_ID = "org.jetbrains.kotlin"
|
||||||
|
const val MAVEN_PLUGIN_ID = "kotlin-maven-plugin"
|
||||||
|
private const val KOTLIN_VERSION_PROPERTY = "kotlin.version"
|
||||||
|
|
||||||
|
private fun hasJavaFiles(module: Module): Boolean {
|
||||||
|
return !FileTypeIndex.getFiles(JavaFileType.INSTANCE, GlobalSearchScope.moduleScope(module)).isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findModulePomFile(module: Module): PsiFile? {
|
||||||
|
val files = MavenProjectsManager.getInstance(module.project).projectsFiles
|
||||||
|
for (file in files) {
|
||||||
|
val fileModule = ModuleUtilCore.findModuleForFile(file, module.project)
|
||||||
|
if (module != fileModule) continue
|
||||||
|
val psiFile = PsiManager.getInstance(module.project).findFile(file) ?: continue
|
||||||
|
if (!MavenDomUtil.isProjectFile(psiFile)) continue
|
||||||
|
return psiFile
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun canConfigureFile(file: PsiFile): Boolean {
|
||||||
|
return WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showErrorMessage(project: Project, message: String?) {
|
||||||
|
Messages.showErrorDialog(
|
||||||
|
project,
|
||||||
|
"<html>Couldn't configure kotlin-maven plugin automatically.<br/>" +
|
||||||
|
(if (message != null) "$message</br>" else "") +
|
||||||
|
"See manual installation instructions <a href=\"http://confluence.jetbrains.com/display/Kotlin/Kotlin+Build+Tools#KotlinBuildTools-Maven\">here</a>.</html>",
|
||||||
|
"Configure Kotlin-Maven Plugin"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<idea-plugin>
|
||||||
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
|
<externalAnnotator language="kotlin" implementationClass="org.jetbrains.android.inspections.lint.AndroidLintExternalAnnotator"/>
|
||||||
|
</extensions>
|
||||||
|
</idea-plugin>
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
|
<xi:include href="android-lint.xml" xpointer="xpointer(/idea-plugin/*)"/>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
|
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.android.navigation.KotlinAndroidGotoDeclarationHandler"/>
|
||||||
|
|
||||||
|
<moduleService serviceInterface="org.jetbrains.kotlin.android.synthetic.res.AndroidLayoutXmlFileManager"
|
||||||
|
serviceImplementation="org.jetbrains.kotlin.android.synthetic.idea.res.IDEAndroidLayoutXmlFileManager"/>
|
||||||
|
<psi.treeChangePreprocessor implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidPsiTreeChangePreprocessor"/>
|
||||||
|
<errorHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsReportSubmitter"/>
|
||||||
|
<gotoDeclarationHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidGotoDeclarationHandler"/>
|
||||||
|
|
||||||
|
<localInspection implementationClass="org.jetbrains.kotlin.android.inspection.IllegalIdentifierInspection"
|
||||||
|
displayName="Illegal Android Identifier"
|
||||||
|
groupName="Kotlin Android"
|
||||||
|
enabledByDefault="true"
|
||||||
|
level="ERROR"/>
|
||||||
|
|
||||||
|
<localInspection implementationClass="org.jetbrains.kotlin.android.inspection.TypeParameterFindViewByIdInspection"
|
||||||
|
displayName="Cast can be converted to findViewById with type parameter"
|
||||||
|
groupName="Kotlin Android"
|
||||||
|
enabledByDefault="true"
|
||||||
|
cleanupTool="true"
|
||||||
|
level="WEAK WARNING"
|
||||||
|
language="kotlin" />
|
||||||
|
|
||||||
|
<codeInsight.lineMarkerProvider language="kotlin" implementationClass="org.jetbrains.kotlin.android.KotlinAndroidLineMarkerProvider"/>
|
||||||
|
|
||||||
|
<intentionAction>
|
||||||
|
<className>org.jetbrains.kotlin.android.intention.KotlinAndroidAddStringResource</className>
|
||||||
|
<category>Kotlin Android</category>
|
||||||
|
</intentionAction>
|
||||||
|
|
||||||
|
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinGradleAndroidModuleModelProjectDataService"/>
|
||||||
|
|
||||||
|
<intentionAction>
|
||||||
|
<className>org.jetbrains.kotlin.android.intention.AddActivityToManifest</className>
|
||||||
|
<category>Kotlin Android</category>
|
||||||
|
</intentionAction>
|
||||||
|
|
||||||
|
<intentionAction>
|
||||||
|
<className>org.jetbrains.kotlin.android.intention.AddServiceToManifest</className>
|
||||||
|
<category>Kotlin Android</category>
|
||||||
|
</intentionAction>
|
||||||
|
|
||||||
|
<intentionAction>
|
||||||
|
<className>org.jetbrains.kotlin.android.intention.AddBroadcastReceiverToManifest</className>
|
||||||
|
<category>Kotlin Android</category>
|
||||||
|
</intentionAction>
|
||||||
|
<intentionAction>
|
||||||
|
<className>org.jetbrains.kotlin.android.intention.ImplementParcelableAction</className>
|
||||||
|
<category>Kotlin Android</category>
|
||||||
|
</intentionAction>
|
||||||
|
|
||||||
|
<intentionAction>
|
||||||
|
<className>org.jetbrains.kotlin.android.intention.RemoveParcelableAction</className>
|
||||||
|
<category>Kotlin Android</category>
|
||||||
|
</intentionAction>
|
||||||
|
|
||||||
|
<intentionAction>
|
||||||
|
<className>org.jetbrains.kotlin.android.intention.RedoParcelableAction</className>
|
||||||
|
<category>Kotlin Android</category>
|
||||||
|
</intentionAction>
|
||||||
|
|
||||||
|
<codeInsight.unresolvedReferenceQuickFixProvider
|
||||||
|
implementation="org.jetbrains.kotlin.android.inspection.KotlinAndroidResourceQuickFixProvider"/>
|
||||||
|
|
||||||
|
<lang.foldingBuilder language="kotlin" implementationClass="org.jetbrains.kotlin.android.folding.ResourceFoldingBuilder" />
|
||||||
|
|
||||||
|
<annotator language="kotlin" implementationClass="org.jetbrains.kotlin.android.AndroidResourceReferenceAnnotator" />
|
||||||
|
|
||||||
|
<referencesSearch implementation="org.jetbrains.kotlin.AndroidExtensionsReferenceSearchExecutor"/>
|
||||||
|
|
||||||
|
<externalProjectDataService implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleLibraryDataService"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||||
|
<projectResolve implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsProjectResolverExtension"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||||
|
<expressionCodegenExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.IDEAndroidExtensionsExpressionCodegenExtension"/>
|
||||||
|
<storageComponentContainerContributor implementation="org.jetbrains.kotlin.android.synthetic.AndroidExtensionPropertiesComponentContainerContributor"/>
|
||||||
|
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.IDEAndroidOnDestroyClassBuilderInterceptorExtension"/>
|
||||||
|
<packageFragmentProviderExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.res.IDEAndroidPackageFragmentProviderExtension"/>
|
||||||
|
<simpleNameReferenceExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidSimpleNameReferenceExtension"/>
|
||||||
|
<kotlinIndicesHelperExtension implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidIndicesHelperExtension"/>
|
||||||
|
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.android.synthetic.idea.AndroidExtensionsGradleImportHandler"/>
|
||||||
|
|
||||||
|
<quickFixContributor implementation="org.jetbrains.kotlin.android.quickfix.AndroidQuickFixRegistrar"/>
|
||||||
|
<projectConfigurator implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidGradleModuleConfigurator"/>
|
||||||
|
<gradleModelFacade implementation="org.jetbrains.kotlin.android.configure.AndroidGradleModelFacade"/>
|
||||||
|
<completionInformationProvider implementation="org.jetbrains.kotlin.AndroidExtensionsCompletionInformationProvider" />
|
||||||
|
|
||||||
|
<expressionCodegenExtension implementation="org.jetbrains.kotlin.android.parcel.IDEParcelableCodegenExtension"/>
|
||||||
|
<syntheticResolveExtension implementation="org.jetbrains.kotlin.android.parcel.IDEParcelableResolveExtension"/>
|
||||||
|
<classBuilderFactoryInterceptorExtension implementation="org.jetbrains.kotlin.android.synthetic.codegen.ParcelableClinitClassBuilderInterceptorExtension"/>
|
||||||
|
<quickFixContributor implementation="org.jetbrains.kotlin.android.parcel.quickfixes.ParcelableQuickFixContributor"/>
|
||||||
|
|
||||||
|
<androidDexer implementation="org.jetbrains.kotlin.android.debugger.AndroidDexerImpl"/>
|
||||||
|
|
||||||
|
<highlighterExtension implementation="org.jetbrains.kotlin.android.AndroidHighlighterExtension"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="com.android.tools.idea">
|
||||||
|
<npw.template.convertJavaToKotlinProvider implementation="org.jetbrains.kotlin.android.ConvertJavaToKotlinProviderImpl"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="org.jetbrains.android">
|
||||||
|
<androidLintQuickFixProvider implementation="org.jetbrains.kotlin.android.quickfix.KotlinAndroidQuickFixProvider" />
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="com.android.gradle.sync">
|
||||||
|
<postSyncModuleSetupStep implementation="org.jetbrains.kotlin.android.configure.KotlinAndroidModuleSetupStep"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
<extensions defaultExtensionNs="org.jetbrains.kotlin.android.model">
|
||||||
|
<androidModuleInfoProvider implementation="org.jetbrains.kotlin.android.model.impl.AndroidModuleInfoProviderImpl"/>
|
||||||
|
</extensions>
|
||||||
|
</idea-plugin>
|
||||||
@@ -6,9 +6,10 @@
|
|||||||
<version>@snapshot@</version>
|
<version>@snapshot@</version>
|
||||||
<vendor url="http://www.jetbrains.com">JetBrains</vendor>
|
<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.platform</depends>
|
||||||
|
<depends>com.intellij.modules.remoteServers</depends>
|
||||||
|
|
||||||
<!-- required for Kotlin/Native plugin -->
|
<!-- required for Kotlin/Native plugin -->
|
||||||
<depends optional="true">org.jetbrains.kotlin.native.platform.deps</depends>
|
<depends optional="true">org.jetbrains.kotlin.native.platform.deps</depends>
|
||||||
|
|||||||
@@ -0,0 +1,218 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.actions
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.navigation.NavigationUtil
|
||||||
|
import com.intellij.ide.scratch.ScratchFileService
|
||||||
|
import com.intellij.ide.scratch.ScratchRootType
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent
|
||||||
|
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||||
|
import com.intellij.openapi.command.CommandProcessor
|
||||||
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
|
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||||
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.ui.Messages
|
||||||
|
import com.intellij.openapi.ui.ex.MessagesEx
|
||||||
|
import com.intellij.openapi.vfs.VfsUtilCore
|
||||||
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
|
import com.intellij.openapi.vfs.VirtualFileVisitor
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.psi.PsiErrorElement
|
||||||
|
import com.intellij.psi.PsiJavaFile
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
|
import org.jetbrains.kotlin.idea.j2k.IdeaJavaToKotlinServices
|
||||||
|
import org.jetbrains.kotlin.idea.j2k.J2kPostProcessor
|
||||||
|
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
|
import org.jetbrains.kotlin.j2k.ConverterSettings
|
||||||
|
import org.jetbrains.kotlin.j2k.JavaToKotlinConverter
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import java.io.File
|
||||||
|
import java.io.IOException
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class JavaToKotlinAction : AnAction() {
|
||||||
|
companion object {
|
||||||
|
private fun uniqueKotlinFileName(javaFile: VirtualFile): String {
|
||||||
|
val ioFile = File(javaFile.path.replace('/', File.separatorChar))
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
while (true) {
|
||||||
|
val fileName = javaFile.nameWithoutExtension + (if (i > 0) i else "") + ".kt"
|
||||||
|
if (!ioFile.resolveSibling(fileName).exists()) return fileName
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val title = "Convert Java to Kotlin"
|
||||||
|
|
||||||
|
private fun saveResults(javaFiles: List<PsiJavaFile>, convertedTexts: List<String>): List<VirtualFile> {
|
||||||
|
val result = ArrayList<VirtualFile>()
|
||||||
|
for ((psiFile, text) in javaFiles.zip(convertedTexts)) {
|
||||||
|
try {
|
||||||
|
val document = PsiDocumentManager.getInstance(psiFile.project).getDocument(psiFile)
|
||||||
|
if (document == null) {
|
||||||
|
MessagesEx.error(psiFile.project, "Failed to save conversion result: couldn't find document for " + psiFile.name).showLater()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
document.replaceString(0, document.textLength, text)
|
||||||
|
FileDocumentManager.getInstance().saveDocument(document)
|
||||||
|
|
||||||
|
val virtualFile = psiFile.virtualFile
|
||||||
|
if (ScratchRootType.getInstance().containsFile(virtualFile)) {
|
||||||
|
val mapping = ScratchFileService.getInstance().scratchesMapping
|
||||||
|
mapping.setMapping(virtualFile, KotlinFileType.INSTANCE.language)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val fileName = uniqueKotlinFileName(virtualFile)
|
||||||
|
virtualFile.rename(this, fileName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e: IOException) {
|
||||||
|
MessagesEx.error(psiFile.project, e.message ?: "").showLater()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun convertFiles(javaFiles: List<PsiJavaFile>, project: Project,
|
||||||
|
enableExternalCodeProcessing: Boolean = true,
|
||||||
|
askExternalCodeProcessing: Boolean = true): List<KtFile> {
|
||||||
|
var converterResult: JavaToKotlinConverter.FilesResult? = null
|
||||||
|
fun convert() {
|
||||||
|
val converter = JavaToKotlinConverter(project, ConverterSettings.defaultSettings, IdeaJavaToKotlinServices)
|
||||||
|
converterResult = converter.filesToKotlin(javaFiles, J2kPostProcessor(formatCode = true), ProgressManager.getInstance().progressIndicator!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
||||||
|
::convert,
|
||||||
|
title,
|
||||||
|
true,
|
||||||
|
project)) return emptyList()
|
||||||
|
|
||||||
|
|
||||||
|
var externalCodeUpdate: (() -> Unit)? = null
|
||||||
|
|
||||||
|
if (enableExternalCodeProcessing && converterResult!!.externalCodeProcessing != null) {
|
||||||
|
val question = "Some code in the rest of your project may require corrections after performing this conversion. Do you want to find such code and correct it too?"
|
||||||
|
if (!askExternalCodeProcessing || (Messages.showOkCancelDialog(project, question, title, Messages.getQuestionIcon()) == Messages.OK)) {
|
||||||
|
ProgressManager.getInstance().runProcessWithProgressSynchronously(
|
||||||
|
{
|
||||||
|
runReadAction {
|
||||||
|
externalCodeUpdate = converterResult!!.externalCodeProcessing!!.prepareWriteOperation(ProgressManager.getInstance().progressIndicator!!)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title,
|
||||||
|
true,
|
||||||
|
project)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return project.executeWriteCommand("Convert files from Java to Kotlin", null) {
|
||||||
|
CommandProcessor.getInstance().markCurrentCommandAsGlobal(project)
|
||||||
|
|
||||||
|
val newFiles = saveResults(javaFiles, converterResult!!.results)
|
||||||
|
|
||||||
|
externalCodeUpdate?.invoke()
|
||||||
|
|
||||||
|
PsiDocumentManager.getInstance(project).commitAllDocuments()
|
||||||
|
|
||||||
|
newFiles.singleOrNull()?.let {
|
||||||
|
FileEditorManager.getInstance(project).openFile(it, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
newFiles.map { it.toPsiFile(project) as KtFile }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun actionPerformed(e: AnActionEvent) {
|
||||||
|
val javaFiles = selectedJavaFiles(e).filter { it.isWritable }.toList()
|
||||||
|
val project = CommonDataKeys.PROJECT.getData(e.dataContext)!!
|
||||||
|
|
||||||
|
val firstSyntaxError = javaFiles.asSequence().map { PsiTreeUtil.findChildOfType(it, PsiErrorElement::class.java) }.firstOrNull()
|
||||||
|
|
||||||
|
if (firstSyntaxError != null) {
|
||||||
|
val count = javaFiles.filter { PsiTreeUtil.hasErrorElements(it) }.count()
|
||||||
|
val question = firstSyntaxError.containingFile.name +
|
||||||
|
(if (count > 1) " and ${count - 1} more Java files" else " file") +
|
||||||
|
" contain syntax errors, the conversion result may be incorrect"
|
||||||
|
|
||||||
|
val okText = "Investigate Errors"
|
||||||
|
val cancelText = "Proceed with Conversion"
|
||||||
|
if (Messages.showOkCancelDialog(
|
||||||
|
project,
|
||||||
|
question,
|
||||||
|
title,
|
||||||
|
okText,
|
||||||
|
cancelText,
|
||||||
|
Messages.getWarningIcon()
|
||||||
|
) == Messages.OK) {
|
||||||
|
NavigationUtil.activateFileWithPsiElement(firstSyntaxError.navigationElement)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
convertFiles(javaFiles, project)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun update(e: AnActionEvent) {
|
||||||
|
val virtualFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return
|
||||||
|
val project = e.project ?: return
|
||||||
|
|
||||||
|
e.presentation.isEnabled = isAnyJavaFileSelected(project, virtualFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isAnyJavaFileSelected(project: Project, files: Array<VirtualFile>): Boolean {
|
||||||
|
val manager = PsiManager.getInstance(project)
|
||||||
|
|
||||||
|
if (files.any { manager.findFile(it) is PsiJavaFile && it.isWritable }) return true
|
||||||
|
return files.any { it.isDirectory && isAnyJavaFileSelected(project, it.children) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectedJavaFiles(e: AnActionEvent): Sequence<PsiJavaFile> {
|
||||||
|
val virtualFiles = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return sequenceOf()
|
||||||
|
val project = e.project ?: return sequenceOf()
|
||||||
|
return allJavaFiles(virtualFiles, project)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun allJavaFiles(filesOrDirs: Array<VirtualFile>, project: Project): Sequence<PsiJavaFile> {
|
||||||
|
val manager = PsiManager.getInstance(project)
|
||||||
|
return allFiles(filesOrDirs)
|
||||||
|
.asSequence()
|
||||||
|
.mapNotNull { manager.findFile(it) as? PsiJavaFile }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun allFiles(filesOrDirs: Array<VirtualFile>): Collection<VirtualFile> {
|
||||||
|
val result = ArrayList<VirtualFile>()
|
||||||
|
for (file in filesOrDirs) {
|
||||||
|
VfsUtilCore.visitChildrenRecursively(file, object : VirtualFileVisitor<Unit>() {
|
||||||
|
override fun visitFile(file: VirtualFile): Boolean {
|
||||||
|
result.add(file)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,282 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.facet
|
||||||
|
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
|
||||||
|
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProviderImpl
|
||||||
|
import com.intellij.openapi.module.Module
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.openapi.projectRoots.JavaSdk
|
||||||
|
import com.intellij.openapi.projectRoots.JavaSdkVersion
|
||||||
|
import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||||
|
import com.intellij.openapi.roots.ModuleRootManager
|
||||||
|
import com.intellij.openapi.roots.ModuleRootModel
|
||||||
|
import com.intellij.openapi.roots.ProjectRootModificationTracker
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.openapi.util.text.StringUtil
|
||||||
|
import com.intellij.psi.util.CachedValueProvider
|
||||||
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
|
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
|
||||||
|
import org.jetbrains.kotlin.cli.common.arguments.*
|
||||||
|
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
|
||||||
|
import org.jetbrains.kotlin.config.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.caches.project.*
|
||||||
|
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JsCompilerArgumentsHolder
|
||||||
|
import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JvmCompilerArgumentsHolder
|
||||||
|
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
|
||||||
|
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
|
||||||
|
import org.jetbrains.kotlin.idea.framework.KotlinSdkType
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
|
import org.jetbrains.kotlin.idea.versions.*
|
||||||
|
import kotlin.reflect.KProperty1
|
||||||
|
|
||||||
|
private fun getDefaultTargetPlatform(module: Module, rootModel: ModuleRootModel?): TargetPlatformKind<*> {
|
||||||
|
for (platform in TargetPlatformKind.ALL_PLATFORMS) {
|
||||||
|
if (getRuntimeLibraryVersions(module, rootModel, platform).isNotEmpty()) {
|
||||||
|
return platform
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val sdk = ((rootModel ?: ModuleRootManager.getInstance(module))).sdk
|
||||||
|
val sdkVersion = (sdk?.sdkType as? JavaSdk)?.getVersion(sdk!!)
|
||||||
|
return when {
|
||||||
|
sdkVersion == null || sdkVersion >= JavaSdkVersion.JDK_1_8 -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_8]
|
||||||
|
else -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KotlinFacetSettings.initializeIfNeeded(
|
||||||
|
module: Module,
|
||||||
|
rootModel: ModuleRootModel?,
|
||||||
|
platformKind: TargetPlatformKind<*>? = null, // if null, detect by module dependencies
|
||||||
|
languageVersion: String? = null
|
||||||
|
) {
|
||||||
|
val project = module.project
|
||||||
|
|
||||||
|
val shouldInferLanguageLevel = languageLevel == null
|
||||||
|
val shouldInferAPILevel = apiLevel == null
|
||||||
|
|
||||||
|
if (compilerSettings == null) {
|
||||||
|
compilerSettings = KotlinCompilerSettings.getInstance(project).settings
|
||||||
|
}
|
||||||
|
|
||||||
|
val commonArguments = KotlinCommonCompilerArgumentsHolder.getInstance(module.project).settings
|
||||||
|
|
||||||
|
if (compilerArguments == null) {
|
||||||
|
val targetPlatformKind = platformKind ?: getDefaultTargetPlatform(module, rootModel)
|
||||||
|
compilerArguments = targetPlatformKind.createCompilerArguments {
|
||||||
|
targetPlatformKind.getPlatformCompilerArgumentsByProject(module.project)?.let { mergeBeans(it, this) }
|
||||||
|
mergeBeans(commonArguments, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldInferLanguageLevel) {
|
||||||
|
languageLevel = (if (useProjectSettings) LanguageVersion.fromVersionString(commonArguments.languageVersion) else null)
|
||||||
|
?: getDefaultLanguageLevel(module, languageVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldInferAPILevel) {
|
||||||
|
apiLevel = if (useProjectSettings) {
|
||||||
|
LanguageVersion.fromVersionString(commonArguments.apiVersion) ?: languageLevel
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
languageLevel!!.coerceAtMost(getLibraryLanguageLevel(module, rootModel, targetPlatformKind))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun TargetPlatformKind<*>.getPlatformCompilerArgumentsByProject(project: Project): CommonCompilerArguments? {
|
||||||
|
return when (this) {
|
||||||
|
is TargetPlatformKind.Jvm -> Kotlin2JvmCompilerArgumentsHolder.getInstance(project).settings
|
||||||
|
is TargetPlatformKind.JavaScript -> Kotlin2JsCompilerArgumentsHolder.getInstance(project).settings
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val TargetPlatformKind<*>.mavenLibraryIds: List<String>
|
||||||
|
get() = when (this) {
|
||||||
|
is TargetPlatformKind.Jvm -> listOf(MAVEN_STDLIB_ID, MAVEN_STDLIB_ID_JRE7, MAVEN_STDLIB_ID_JDK7, MAVEN_STDLIB_ID_JRE8, MAVEN_STDLIB_ID_JDK8)
|
||||||
|
is TargetPlatformKind.JavaScript -> listOf(MAVEN_JS_STDLIB_ID, MAVEN_OLD_JS_STDLIB_ID)
|
||||||
|
is TargetPlatformKind.Common -> listOf(MAVEN_COMMON_STDLIB_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
val mavenLibraryIdToPlatform: Map<String, TargetPlatformKind<*>> by lazy {
|
||||||
|
TargetPlatformKind.ALL_PLATFORMS
|
||||||
|
.flatMap { platform -> platform.mavenLibraryIds.map { it to platform } }
|
||||||
|
.sortedByDescending { it.first.length }
|
||||||
|
.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Module.getOrCreateFacet(modelsProvider: IdeModifiableModelsProvider,
|
||||||
|
useProjectSettings: Boolean,
|
||||||
|
commitModel: Boolean = false): KotlinFacet {
|
||||||
|
val facetModel = modelsProvider.getModifiableFacetModel(this)
|
||||||
|
|
||||||
|
val facet = facetModel.findFacet(KotlinFacetType.TYPE_ID, KotlinFacetType.INSTANCE.defaultFacetName)
|
||||||
|
?: with(KotlinFacetType.INSTANCE) { createFacet(this@getOrCreateFacet, defaultFacetName, createDefaultConfiguration(), null) }
|
||||||
|
.apply { facetModel.addFacet(this) }
|
||||||
|
facet.configuration.settings.useProjectSettings = useProjectSettings
|
||||||
|
if (commitModel) {
|
||||||
|
runWriteAction {
|
||||||
|
facetModel.commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return facet
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KotlinFacet.configureFacet(
|
||||||
|
compilerVersion: String,
|
||||||
|
coroutineSupport: LanguageFeature.State,
|
||||||
|
platformKind: TargetPlatformKind<*>?, // if null, detect by module dependencies
|
||||||
|
modelsProvider: IdeModifiableModelsProvider
|
||||||
|
) {
|
||||||
|
val module = module
|
||||||
|
with(configuration.settings) {
|
||||||
|
compilerArguments = null
|
||||||
|
compilerSettings = null
|
||||||
|
initializeIfNeeded(
|
||||||
|
module,
|
||||||
|
modelsProvider.getModifiableRootModel(module),
|
||||||
|
platformKind,
|
||||||
|
compilerVersion
|
||||||
|
)
|
||||||
|
val apiLevel = apiLevel
|
||||||
|
val languageLevel = languageLevel
|
||||||
|
if (languageLevel != null && apiLevel != null && apiLevel > languageLevel) {
|
||||||
|
this.apiLevel = languageLevel
|
||||||
|
}
|
||||||
|
this.coroutineSupport = coroutineSupport
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KotlinFacet.noVersionAutoAdvance() {
|
||||||
|
configuration.settings.compilerArguments?.let {
|
||||||
|
it.autoAdvanceLanguageVersion = false
|
||||||
|
it.autoAdvanceApiVersion = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// "Primary" fields are written to argument beans directly and thus not presented in the "additional arguments" string
|
||||||
|
// Update these lists when facet/project settings UI changes
|
||||||
|
val commonUIExposedFields = listOf(CommonCompilerArguments::languageVersion.name,
|
||||||
|
CommonCompilerArguments::apiVersion.name,
|
||||||
|
CommonCompilerArguments::suppressWarnings.name,
|
||||||
|
CommonCompilerArguments::coroutinesState.name)
|
||||||
|
private val commonUIHiddenFields = listOf(CommonCompilerArguments::pluginClasspaths.name,
|
||||||
|
CommonCompilerArguments::pluginOptions.name)
|
||||||
|
private val commonPrimaryFields = commonUIExposedFields + commonUIHiddenFields
|
||||||
|
|
||||||
|
private val jvmSpecificUIExposedFields = listOf(K2JVMCompilerArguments::jvmTarget.name,
|
||||||
|
K2JVMCompilerArguments::destination.name,
|
||||||
|
K2JVMCompilerArguments::classpath.name)
|
||||||
|
val jvmUIExposedFields = commonUIExposedFields + jvmSpecificUIExposedFields
|
||||||
|
private val jvmPrimaryFields = commonPrimaryFields + jvmSpecificUIExposedFields
|
||||||
|
|
||||||
|
private val jsSpecificUIExposedFields = listOf(K2JSCompilerArguments::sourceMap.name,
|
||||||
|
K2JSCompilerArguments::sourceMapPrefix.name,
|
||||||
|
K2JSCompilerArguments::sourceMapEmbedSources.name,
|
||||||
|
K2JSCompilerArguments::outputPrefix.name,
|
||||||
|
K2JSCompilerArguments::outputPostfix.name,
|
||||||
|
K2JSCompilerArguments::moduleKind.name)
|
||||||
|
val jsUIExposedFields = commonUIExposedFields + jsSpecificUIExposedFields
|
||||||
|
private val jsPrimaryFields = commonPrimaryFields + jsSpecificUIExposedFields
|
||||||
|
|
||||||
|
private val metadataSpecificUIExposedFields = listOf(K2MetadataCompilerArguments::destination.name,
|
||||||
|
K2MetadataCompilerArguments::classpath.name)
|
||||||
|
val metadataUIExposedFields = commonUIExposedFields + metadataSpecificUIExposedFields
|
||||||
|
private val metadataPrimaryFields = commonPrimaryFields + metadataSpecificUIExposedFields
|
||||||
|
|
||||||
|
private val CommonCompilerArguments.primaryFields: List<String>
|
||||||
|
get() = when (this) {
|
||||||
|
is K2JVMCompilerArguments -> jvmPrimaryFields
|
||||||
|
is K2JSCompilerArguments -> jsPrimaryFields
|
||||||
|
is K2MetadataCompilerArguments -> metadataPrimaryFields
|
||||||
|
else -> commonPrimaryFields
|
||||||
|
}
|
||||||
|
|
||||||
|
private val CommonCompilerArguments.ignoredFields: List<String>
|
||||||
|
get() = when (this) {
|
||||||
|
is K2JVMCompilerArguments -> listOf(K2JVMCompilerArguments::noJdk.name, K2JVMCompilerArguments::jdkHome.name)
|
||||||
|
else -> emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Module.configureSdkIfPossible(compilerArguments: CommonCompilerArguments, modelsProvider: IdeModifiableModelsProvider) {
|
||||||
|
val allSdks = ProjectJdkTable.getInstance().allJdks
|
||||||
|
val sdk = if (compilerArguments is K2JVMCompilerArguments) {
|
||||||
|
val jdkHome = compilerArguments.jdkHome ?: return
|
||||||
|
allSdks.firstOrNull { it.sdkType is JavaSdk && FileUtil.comparePaths(it.homePath, jdkHome) == 0 } ?: return
|
||||||
|
} else {
|
||||||
|
allSdks.firstOrNull { it.sdkType is KotlinSdkType } ?: KotlinSdkType.INSTANCE.createSdkWithUniqueName(allSdks.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
modelsProvider.getModifiableRootModel(this).sdk = sdk
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseCompilerArgumentsToFacet(
|
||||||
|
arguments: List<String>,
|
||||||
|
defaultArguments: List<String>,
|
||||||
|
kotlinFacet: KotlinFacet,
|
||||||
|
modelsProvider: IdeModifiableModelsProvider?
|
||||||
|
) {
|
||||||
|
with(kotlinFacet.configuration.settings) {
|
||||||
|
val compilerArguments = this.compilerArguments ?: return
|
||||||
|
|
||||||
|
val defaultCompilerArguments = compilerArguments::class.java.newInstance()
|
||||||
|
parseCommandLineArguments(defaultArguments, defaultCompilerArguments)
|
||||||
|
defaultCompilerArguments.convertPathsToSystemIndependent()
|
||||||
|
|
||||||
|
parseCommandLineArguments(arguments, compilerArguments)
|
||||||
|
|
||||||
|
compilerArguments.convertPathsToSystemIndependent()
|
||||||
|
|
||||||
|
// Retain only fields exposed (and not explicitly ignored) in facet configuration editor.
|
||||||
|
// The rest is combined into string and stored in CompilerSettings.additionalArguments
|
||||||
|
|
||||||
|
if (modelsProvider != null)
|
||||||
|
kotlinFacet.module.configureSdkIfPossible(compilerArguments, modelsProvider)
|
||||||
|
|
||||||
|
val primaryFields = compilerArguments.primaryFields
|
||||||
|
val ignoredFields = compilerArguments.ignoredFields
|
||||||
|
|
||||||
|
fun exposeAsAdditionalArgument(property: KProperty1<CommonCompilerArguments, Any?>) =
|
||||||
|
property.name !in primaryFields && property.get(compilerArguments) != property.get(defaultCompilerArguments)
|
||||||
|
|
||||||
|
val additionalArgumentsString = with(compilerArguments::class.java.newInstance()) {
|
||||||
|
copyFieldsSatisfying(compilerArguments, this) { exposeAsAdditionalArgument(it) && it.name !in ignoredFields }
|
||||||
|
ArgumentUtils.convertArgumentsToStringList(this).joinToString(separator = " ") {
|
||||||
|
if (StringUtil.containsWhitespaces(it) || it.startsWith('"')) {
|
||||||
|
StringUtil.wrapWithDoubleQuote(StringUtil.escapeQuotes(it))
|
||||||
|
} else it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compilerSettings?.additionalArguments =
|
||||||
|
if (additionalArgumentsString.isNotEmpty()) additionalArgumentsString else CompilerSettings.DEFAULT_ADDITIONAL_ARGUMENTS
|
||||||
|
|
||||||
|
with(compilerArguments::class.java.newInstance()) {
|
||||||
|
copyFieldsSatisfying(this, compilerArguments) { exposeAsAdditionalArgument(it) || it.name in ignoredFields }
|
||||||
|
}
|
||||||
|
|
||||||
|
val languageLevel = languageLevel
|
||||||
|
val apiLevel = apiLevel
|
||||||
|
if (languageLevel != null && apiLevel != null && apiLevel > languageLevel) {
|
||||||
|
this.apiLevel = languageLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMergedArguments()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.idea.reporter
|
||||||
|
|
||||||
|
import com.intellij.diagnostic.ITNReporter
|
||||||
|
import com.intellij.openapi.diagnostic.IdeaLoggingEvent
|
||||||
|
import com.intellij.openapi.diagnostic.SubmittedReportInfo
|
||||||
|
import com.intellij.openapi.ui.Messages
|
||||||
|
import com.intellij.util.Consumer
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinPluginUpdater
|
||||||
|
import org.jetbrains.kotlin.idea.KotlinPluginUtil
|
||||||
|
import org.jetbrains.kotlin.idea.PluginUpdateStatus
|
||||||
|
import org.jetbrains.kotlin.idea.actions.internal.KotlinInternalMode
|
||||||
|
import java.awt.Component
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We need to wrap ITNReporter for force showing or errors from kotlin plugin even from released version of IDEA.
|
||||||
|
*/
|
||||||
|
class KotlinReportSubmitter : ITNReporter() {
|
||||||
|
private var hasUpdate = false
|
||||||
|
private var hasLatestVersion = false
|
||||||
|
|
||||||
|
override fun showErrorInRelease(event: IdeaLoggingEvent): Boolean {
|
||||||
|
val notificationEnabled = "disabled" != System.getProperty("kotlin.fatal.error.notification", "enabled")
|
||||||
|
return notificationEnabled && (!hasUpdate || KotlinInternalMode.enabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun submit(events: Array<IdeaLoggingEvent>, additionalInfo: String?, parentComponent: Component?, consumer: Consumer<SubmittedReportInfo>): Boolean {
|
||||||
|
if (hasUpdate) {
|
||||||
|
if (KotlinInternalMode.enabled) {
|
||||||
|
return super.submit(events, additionalInfo, parentComponent, consumer)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasLatestVersion) {
|
||||||
|
return super.submit(events, additionalInfo, parentComponent, consumer)
|
||||||
|
}
|
||||||
|
|
||||||
|
KotlinPluginUpdater.getInstance().runUpdateCheck { status ->
|
||||||
|
if (status is PluginUpdateStatus.Update) {
|
||||||
|
hasUpdate = true
|
||||||
|
if (parentComponent != null) {
|
||||||
|
|
||||||
|
if (KotlinInternalMode.enabled) {
|
||||||
|
super.submit(events, additionalInfo, parentComponent, consumer)
|
||||||
|
}
|
||||||
|
|
||||||
|
val rc = Messages.showDialog(parentComponent,
|
||||||
|
"You're running Kotlin plugin version ${KotlinPluginUtil.getPluginVersion()}, " +
|
||||||
|
"while the latest version is ${status.pluginDescriptor.version}",
|
||||||
|
"Update Kotlin Plugin",
|
||||||
|
arrayOf("Update", "Ignore"),
|
||||||
|
0, Messages.getInformationIcon())
|
||||||
|
if (rc == 0) {
|
||||||
|
KotlinPluginUpdater.getInstance().installPluginUpdate(status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
hasLatestVersion = true
|
||||||
|
super.submit(events, additionalInfo, parentComponent, consumer)
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// "class org.jetbrains.kotlin.idea.quickfix.AddArrayOfTypeFix" "false"
|
||||||
|
// ACTION: Add 'value =' to argument
|
||||||
|
// ACTION: Create test
|
||||||
|
// ACTION: Do not show hints for current method
|
||||||
|
// ACTION: Make internal
|
||||||
|
// ACTION: Make private
|
||||||
|
// ACTION: To raw string literal
|
||||||
|
// ACTION: Do not show hints for current method
|
||||||
|
|
||||||
|
@ArrAnn(<caret>"123") class My
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin
|
||||||
|
|
||||||
|
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
||||||
|
import com.intellij.psi.codeStyle.PackageEntry
|
||||||
|
import com.intellij.testFramework.LightProjectDescriptor
|
||||||
|
import junit.framework.TestCase
|
||||||
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
abstract class AbstractImportsTest : KotlinLightCodeInsightFixtureTestCase() {
|
||||||
|
override fun getTestDataPath() = KotlinTestUtils.getHomeDirectory()
|
||||||
|
override fun getProjectDescriptor(): LightProjectDescriptor = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||||
|
|
||||||
|
protected fun doTest(testPath: String) {
|
||||||
|
val settingManager = CodeStyleSettingsManager.getInstance(project)
|
||||||
|
val tempSettings = settingManager.currentSettings.clone()
|
||||||
|
settingManager.setTemporarySettings(tempSettings)
|
||||||
|
|
||||||
|
val codeStyleSettings = KotlinCodeStyleSettings.getInstance(project)
|
||||||
|
|
||||||
|
try {
|
||||||
|
val fixture = myFixture
|
||||||
|
val dependencySuffixes = listOf(".dependency.kt", ".dependency.java", ".dependency1.kt", ".dependency2.kt")
|
||||||
|
for (suffix in dependencySuffixes) {
|
||||||
|
val dependencyPath = testPath.replace(".kt", suffix)
|
||||||
|
if (File(dependencyPath).exists()) {
|
||||||
|
fixture.configureByFile(dependencyPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fixture.configureByFile(testPath)
|
||||||
|
|
||||||
|
val file = fixture.file as KtFile
|
||||||
|
|
||||||
|
val fileText = file.text
|
||||||
|
|
||||||
|
codeStyleSettings.NAME_COUNT_TO_USE_STAR_IMPORT = InTextDirectivesUtils.getPrefixedInt(fileText, "// NAME_COUNT_TO_USE_STAR_IMPORT:") ?: nameCountToUseStarImportDefault
|
||||||
|
codeStyleSettings.NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS = InTextDirectivesUtils.getPrefixedInt(fileText, "// NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS:") ?: nameCountToUseStarImportForMembersDefault
|
||||||
|
codeStyleSettings.IMPORT_NESTED_CLASSES = InTextDirectivesUtils.getPrefixedBoolean(fileText, "// IMPORT_NESTED_CLASSES:") ?: false
|
||||||
|
|
||||||
|
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGE_TO_USE_STAR_IMPORTS:").forEach {
|
||||||
|
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(PackageEntry(false, it.trim(), false))
|
||||||
|
}
|
||||||
|
InTextDirectivesUtils.findLinesWithPrefixesRemoved(fileText, "// PACKAGES_TO_USE_STAR_IMPORTS:").forEach {
|
||||||
|
codeStyleSettings.PACKAGES_TO_USE_STAR_IMPORTS.addEntry(PackageEntry(false, it.trim(), true))
|
||||||
|
}
|
||||||
|
|
||||||
|
val log = project.executeWriteCommand<String?>("") { doTest(file) }
|
||||||
|
|
||||||
|
KotlinTestUtils.assertEqualsToFile(File(testPath + ".after"), myFixture.file.text)
|
||||||
|
if (log != null) {
|
||||||
|
val logFile = File(testPath + ".log")
|
||||||
|
if (log.isNotEmpty()) {
|
||||||
|
KotlinTestUtils.assertEqualsToFile(logFile, log)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TestCase.assertFalse(logFile.exists())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
settingManager.dropTemporarySettings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns test log
|
||||||
|
protected abstract fun doTest(file: KtFile): String?
|
||||||
|
|
||||||
|
protected open val nameCountToUseStarImportDefault: Int
|
||||||
|
get() = 1
|
||||||
|
|
||||||
|
protected open val nameCountToUseStarImportForMembersDefault: Int
|
||||||
|
get() = 3
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testRuntime(intellijDep())
|
||||||
|
|
||||||
|
compile(projectDist(":kotlin-stdlib"))
|
||||||
|
compile(project(":compiler:frontend"))
|
||||||
|
compile(project(":compiler:frontend.java"))
|
||||||
|
compile(project(":compiler:light-classes"))
|
||||||
|
compile(project(":compiler:util"))
|
||||||
|
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||||
|
|
||||||
|
testCompile(project(":idea"))
|
||||||
|
testCompile(projectTests(":idea:idea-test-framework"))
|
||||||
|
testCompile(project(":compiler:light-classes"))
|
||||||
|
testCompile(projectDist(":kotlin-test:kotlin-test-junit"))
|
||||||
|
testCompile(commonDep("junit:junit"))
|
||||||
|
testCompileOnly(intellijDep()) { includeJars("platform-api", "platform-impl") }
|
||||||
|
|
||||||
|
testRuntime(project(":plugins:kapt3-idea")) { isTransitive = false }
|
||||||
|
testRuntime(project(":idea:idea-jvm"))
|
||||||
|
testRuntime(project(":idea:idea-android"))
|
||||||
|
testRuntime(project(":plugins:android-extensions-ide"))
|
||||||
|
testRuntime(project(":sam-with-receiver-ide-plugin"))
|
||||||
|
testRuntime(project(":allopen-ide-plugin"))
|
||||||
|
testRuntime(project(":noarg-ide-plugin"))
|
||||||
|
testRuntime(intellijPluginDep("properties"))
|
||||||
|
testRuntime(intellijPluginDep("gradle"))
|
||||||
|
testRuntime(intellijPluginDep("Groovy"))
|
||||||
|
testRuntime(intellijPluginDep("coverage"))
|
||||||
|
//testRuntime(intellijPluginDep("maven"))
|
||||||
|
testRuntime(intellijPluginDep("android"))
|
||||||
|
testRuntime(intellijPluginDep("smali"))
|
||||||
|
testRuntime(intellijPluginDep("junit"))
|
||||||
|
testRuntime(intellijPluginDep("testng"))
|
||||||
|
testRuntime(intellijPluginDep("IntelliLang"))
|
||||||
|
testRuntime(intellijPluginDep("testng"))
|
||||||
|
testRuntime(intellijPluginDep("copyright"))
|
||||||
|
testRuntime(intellijPluginDep("properties"))
|
||||||
|
testRuntime(intellijPluginDep("java-i18n"))
|
||||||
|
testRuntime(intellijPluginDep("java-decompiler"))
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { projectDefault() }
|
||||||
|
"test" { projectDefault() }
|
||||||
|
}
|
||||||
|
|
||||||
|
projectTest {
|
||||||
|
dependsOn(":dist")
|
||||||
|
workingDir = rootDir
|
||||||
|
}
|
||||||
|
|
||||||
|
testsJar()
|
||||||
|
|
||||||
|
|
||||||
|
val testForWebDemo by task<Test> {
|
||||||
|
include("**/*JavaToKotlinConverterForWebDemoTestGenerated*")
|
||||||
|
classpath = the<JavaPluginConvention>().sourceSets["test"].runtimeClasspath
|
||||||
|
workingDir = rootDir
|
||||||
|
}
|
||||||
|
val cleanTestForWebDemo by tasks
|
||||||
|
|
||||||
|
val test: Test by tasks
|
||||||
|
test.apply {
|
||||||
|
exclude("**/*JavaToKotlinConverterForWebDemoTestGenerated*")
|
||||||
|
dependsOn(testForWebDemo)
|
||||||
|
}
|
||||||
|
val cleanTest by tasks
|
||||||
|
cleanTest.dependsOn(cleanTestForWebDemo)
|
||||||
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
val compilerModules: Array<String> by rootProject.extra
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile(project(":kotlin-build-common"))
|
||||||
|
compile(project(":core:descriptors"))
|
||||||
|
compile(project(":core:descriptors.jvm"))
|
||||||
|
compile(project(":kotlin-compiler-runner"))
|
||||||
|
compile(project(":compiler:daemon-common"))
|
||||||
|
compile(projectRuntimeJar(":kotlin-daemon-client"))
|
||||||
|
compile(project(":compiler:frontend.java"))
|
||||||
|
compile(projectRuntimeJar(":kotlin-preloader"))
|
||||||
|
compile(project(":idea:idea-jps-common"))
|
||||||
|
compileOnly(intellijDep()) { includeJars("jdom", "trove4j", "jps-model", "openapi", "platform-api", "util", "asm-all") }
|
||||||
|
compileOnly(intellijDep("jps-standalone")) { includeJars("jps-builders", "jps-builders-6") }
|
||||||
|
testCompileOnly(project(":kotlin-reflect-api"))
|
||||||
|
testCompile(project(":compiler:incremental-compilation-impl"))
|
||||||
|
testCompile(projectTests(":compiler:tests-common"))
|
||||||
|
testCompile(projectTests(":compiler:incremental-compilation-impl"))
|
||||||
|
testCompile(commonDep("junit:junit"))
|
||||||
|
testCompile(projectDist(":kotlin-test:kotlin-test-jvm"))
|
||||||
|
testCompile(projectTests(":kotlin-build-common"))
|
||||||
|
testCompileOnly(intellijDep("jps-standalone")) { includeJars("jps-builders", "jps-builders-6") }
|
||||||
|
testCompileOnly(intellijDep()) { includeJars("openapi", "idea", "platform-api", "log4j") }
|
||||||
|
testCompile(intellijDep("jps-build-test"))
|
||||||
|
compilerModules.forEach {
|
||||||
|
testRuntime(project(it))
|
||||||
|
}
|
||||||
|
testRuntime(intellijDep())
|
||||||
|
testRuntime(projectDist(":kotlin-reflect"))
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { projectDefault() }
|
||||||
|
"test" {
|
||||||
|
/*java.srcDirs("jps-tests/test"
|
||||||
|
/*, "kannotator-jps-plugin-test/test"*/ // Obsolete
|
||||||
|
)*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
projectTest {
|
||||||
|
dependsOn(":kotlin-compiler:dist")
|
||||||
|
workingDir = rootDir
|
||||||
|
}
|
||||||
|
|
||||||
|
testsJar {}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
description = "Kotlin Android Extensions IDEA"
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
jvmTarget = "1.6"
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testRuntime(intellijDep())
|
||||||
|
|
||||||
|
compile(project(":compiler:util"))
|
||||||
|
compile(project(":compiler:light-classes"))
|
||||||
|
compile(project(":idea:idea-core"))
|
||||||
|
compile(project(":idea"))
|
||||||
|
compile(project(":idea:idea-jvm"))
|
||||||
|
compile(project(":idea:idea-gradle"))
|
||||||
|
compile(project(":plugins:android-extensions-compiler"))
|
||||||
|
compileOnly(project(":kotlin-android-extensions-runtime"))
|
||||||
|
compileOnly(intellijPluginDep("android"))
|
||||||
|
compileOnly(intellijPluginDep("Groovy"))
|
||||||
|
compileOnly(intellijDep())
|
||||||
|
|
||||||
|
testCompile(project(":compiler:tests-common"))
|
||||||
|
testCompile(project(":compiler:cli"))
|
||||||
|
testCompile(project(":compiler:frontend.java"))
|
||||||
|
testCompile(projectTests(":idea:idea-test-framework")) { isTransitive = false }
|
||||||
|
testCompile(project(":plugins:kapt3-idea"))
|
||||||
|
testCompile(projectTests(":compiler:tests-common"))
|
||||||
|
testCompile(projectTests(":idea"))
|
||||||
|
testCompile(projectTests(":idea:idea-android"))
|
||||||
|
testCompile(projectDist(":kotlin-test:kotlin-test-jvm"))
|
||||||
|
testCompile(commonDep("junit:junit"))
|
||||||
|
testRuntime(projectDist(":kotlin-reflect"))
|
||||||
|
testCompile(intellijPluginDep("android"))
|
||||||
|
testCompile(intellijPluginDep("Groovy"))
|
||||||
|
testCompile(intellijDep())
|
||||||
|
|
||||||
|
testRuntime(project(":idea:idea-jvm"))
|
||||||
|
testRuntime(project(":plugins:android-extensions-jps"))
|
||||||
|
testRuntime(project(":sam-with-receiver-ide-plugin"))
|
||||||
|
testRuntime(project(":noarg-ide-plugin"))
|
||||||
|
testRuntime(project(":allopen-ide-plugin"))
|
||||||
|
testRuntime(project(":plugins:lint"))
|
||||||
|
testRuntime(intellijPluginDep("junit"))
|
||||||
|
testRuntime(intellijPluginDep("IntelliLang"))
|
||||||
|
testRuntime(intellijPluginDep("properties"))
|
||||||
|
testRuntime(intellijPluginDep("java-i18n"))
|
||||||
|
testRuntime(intellijPluginDep("gradle"))
|
||||||
|
testRuntime(intellijPluginDep("Groovy"))
|
||||||
|
testRuntime(intellijPluginDep("java-decompiler"))
|
||||||
|
//testRuntime(intellijPluginDep("maven"))
|
||||||
|
testRuntime(intellijPluginDep("android"))
|
||||||
|
testRuntime(intellijPluginDep("smali"))
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { projectDefault() }
|
||||||
|
"test" { projectDefault() }
|
||||||
|
}
|
||||||
|
|
||||||
|
testsJar {}
|
||||||
|
|
||||||
|
projectTest {
|
||||||
|
dependsOn(":kotlin-android-extensions-runtime:dist")
|
||||||
|
workingDir = rootDir
|
||||||
|
useAndroidSdk()
|
||||||
|
useAndroidJar()
|
||||||
|
}
|
||||||
|
|
||||||
|
runtimeJar()
|
||||||
|
|
||||||
|
ideaPlugin()
|
||||||
+202
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.kapt.idea
|
||||||
|
|
||||||
|
import com.android.tools.idea.gradle.project.model.AndroidModuleModel
|
||||||
|
import com.intellij.openapi.diagnostic.Logger
|
||||||
|
import com.intellij.openapi.externalSystem.model.DataNode
|
||||||
|
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||||
|
import com.intellij.openapi.externalSystem.model.project.*
|
||||||
|
import org.gradle.api.Plugin
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.tooling.model.idea.IdeaModule
|
||||||
|
import org.jetbrains.kotlin.gradle.AbstractKotlinGradleModelBuilder
|
||||||
|
import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
|
||||||
|
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||||
|
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
|
||||||
|
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
|
||||||
|
import java.io.File
|
||||||
|
import java.io.Serializable
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.lang.reflect.Modifier
|
||||||
|
|
||||||
|
interface KaptSourceSetModel : Serializable {
|
||||||
|
val sourceSetName: String
|
||||||
|
val isTest: Boolean
|
||||||
|
val generatedSourcesDir: String
|
||||||
|
val generatedClassesDir: String
|
||||||
|
val generatedKotlinSourcesDir: String
|
||||||
|
|
||||||
|
val generatedSourcesDirFile get() = generatedSourcesDir.takeIf { it.isNotEmpty() }?.let(::File)
|
||||||
|
val generatedClassesDirFile get() = generatedClassesDir.takeIf { it.isNotEmpty() }?.let(::File)
|
||||||
|
val generatedKotlinSourcesDirFile get() = generatedKotlinSourcesDir.takeIf { it.isNotEmpty() }?.let(::File)
|
||||||
|
}
|
||||||
|
|
||||||
|
class KaptSourceSetModelImpl(
|
||||||
|
override val sourceSetName: String,
|
||||||
|
override val isTest: Boolean,
|
||||||
|
override val generatedSourcesDir: String,
|
||||||
|
override val generatedClassesDir: String,
|
||||||
|
override val generatedKotlinSourcesDir: String
|
||||||
|
) : KaptSourceSetModel
|
||||||
|
|
||||||
|
interface KaptGradleModel : Serializable {
|
||||||
|
val isEnabled: Boolean
|
||||||
|
val buildDirectory: File
|
||||||
|
val sourceSets: List<KaptSourceSetModel>
|
||||||
|
}
|
||||||
|
|
||||||
|
class KaptGradleModelImpl(
|
||||||
|
override val isEnabled: Boolean,
|
||||||
|
override val buildDirectory: File,
|
||||||
|
override val sourceSets: List<KaptSourceSetModel>
|
||||||
|
) : KaptGradleModel
|
||||||
|
|
||||||
|
internal typealias AndroidGradleModel = AndroidModuleModel
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
class KaptProjectResolverExtension : AbstractProjectResolverExtension() {
|
||||||
|
private companion object {
|
||||||
|
private val LOG = Logger.getInstance(KaptProjectResolverExtension::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getExtraProjectModelClasses() = setOf(KaptGradleModel::class.java)
|
||||||
|
override fun getToolingExtensionsClasses() = setOf(KaptModelBuilderService::class.java, Unit::class.java)
|
||||||
|
|
||||||
|
override fun populateModuleExtraModels(gradleModule: IdeaModule, ideModule: DataNode<ModuleData>) {
|
||||||
|
val kaptModel = resolverCtx.getExtraProject(gradleModule, KaptGradleModel::class.java) ?: return
|
||||||
|
|
||||||
|
if (kaptModel.isEnabled) {
|
||||||
|
for (sourceSet in kaptModel.sourceSets) {
|
||||||
|
populateAndroidModuleModelIfNeeded(ideModule, sourceSet)
|
||||||
|
|
||||||
|
val sourceSetDataNode = ideModule.findGradleSourceSet(sourceSet.sourceSetName) ?: continue
|
||||||
|
|
||||||
|
fun addSourceSet(path: String, type: ExternalSystemSourceType) {
|
||||||
|
val contentRootData = ContentRootData(GRADLE_SYSTEM_ID, path)
|
||||||
|
contentRootData.storePath(type, path)
|
||||||
|
sourceSetDataNode.createChild(ProjectKeys.CONTENT_ROOT, contentRootData)
|
||||||
|
}
|
||||||
|
|
||||||
|
val sourceType = if (sourceSet.isTest) ExternalSystemSourceType.TEST_GENERATED else ExternalSystemSourceType.SOURCE_GENERATED
|
||||||
|
sourceSet.generatedSourcesDirFile?.let { addSourceSet(it.absolutePath, sourceType) }
|
||||||
|
sourceSet.generatedKotlinSourcesDirFile?.let { addSourceSet(it.absolutePath, sourceType) }
|
||||||
|
|
||||||
|
sourceSet.generatedClassesDirFile?.let { generatedClassesDir ->
|
||||||
|
val libraryData = LibraryData(GRADLE_SYSTEM_ID, "kaptGeneratedClasses")
|
||||||
|
libraryData.addPath(LibraryPathType.BINARY, generatedClassesDir.absolutePath)
|
||||||
|
val libraryDependencyData = LibraryDependencyData(sourceSetDataNode.data, libraryData, LibraryLevel.MODULE)
|
||||||
|
sourceSetDataNode.createChild(ProjectKeys.LIBRARY_DEPENDENCY, libraryDependencyData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.populateModuleExtraModels(gradleModule, ideModule)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun populateAndroidModuleModelIfNeeded(ideModule: DataNode<ModuleData>, sourceSet: KaptSourceSetModel) {
|
||||||
|
ideModule.findAndroidModuleModel()?.let { androidModelAny ->
|
||||||
|
// We can cast to AndroidModuleModel cause we already checked in findAndroidModuleModel() that the class exists
|
||||||
|
|
||||||
|
val generatedKotlinSources = sourceSet.generatedKotlinSourcesDirFile ?: return
|
||||||
|
|
||||||
|
val androidModel = androidModelAny.data as? AndroidModuleModel ?: return
|
||||||
|
val variant = androidModel.findVariantByName(sourceSet.sourceSetName) ?: return
|
||||||
|
|
||||||
|
androidModel.registerExtraGeneratedSourceFolder(generatedKotlinSources)
|
||||||
|
|
||||||
|
// TODO remove this when IDEA eventually migrate to the newer Android plugin
|
||||||
|
try {
|
||||||
|
variant.mainArtifact.generatedSourceFolders += generatedKotlinSources
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
// There was an error being thrown here, but the code above doesn't work for the newer versions of Android Studio 3
|
||||||
|
// (generatedSourceFolders returns a wrapped unmodifiable list), and the thrown exception breaks the import.
|
||||||
|
// The error will be moved back when I find a work-around for AS3.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DataNode<ModuleData>.findAndroidModuleModel(): DataNode<*>? {
|
||||||
|
val modelClassName = "com.android.tools.idea.gradle.project.model.AndroidModuleModel"
|
||||||
|
val node = children.firstOrNull { it.key.dataType == modelClassName } ?: return null
|
||||||
|
return if (!hasClassInClasspath(modelClassName)) null else node
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun hasClassInClasspath(name: String): Boolean {
|
||||||
|
return try {
|
||||||
|
Class.forName(name) != null
|
||||||
|
} catch (thr: Throwable) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DataNode<ModuleData>.findGradleSourceSet(sourceSetName: String): DataNode<GradleSourceSetData>? {
|
||||||
|
val moduleName = data.id
|
||||||
|
for (child in children) {
|
||||||
|
val gradleSourceSetData = child.data as? GradleSourceSetData ?: continue
|
||||||
|
if (gradleSourceSetData.id == "$moduleName:$sourceSetName") {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return child as DataNode<GradleSourceSetData>?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class KaptModelBuilderService : AbstractKotlinGradleModelBuilder() {
|
||||||
|
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
|
||||||
|
return ErrorMessageBuilder.create(project, e, "Gradle import errors")
|
||||||
|
.withDescription("Unable to build kotlin-kapt plugin configuration")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun canBuild(modelName: String?): Boolean = modelName == KaptGradleModel::class.java.name
|
||||||
|
|
||||||
|
override fun buildAll(modelName: String?, project: Project): Any {
|
||||||
|
val kaptPlugin: Plugin<*>? = project.plugins.findPlugin("kotlin-kapt")
|
||||||
|
val kaptIsEnabled = kaptPlugin != null
|
||||||
|
|
||||||
|
val sourceSets = mutableListOf<KaptSourceSetModel>()
|
||||||
|
|
||||||
|
if (kaptIsEnabled) {
|
||||||
|
project.getAllTasks(false)[project]?.forEach { compileTask ->
|
||||||
|
if (compileTask.javaClass.name !in kotlinCompileTaskClasses) return@forEach
|
||||||
|
|
||||||
|
val sourceSetName = compileTask.getSourceSetName()
|
||||||
|
val isTest = sourceSetName.toLowerCase().endsWith("test")
|
||||||
|
|
||||||
|
val kaptGeneratedSourcesDir = getKaptDirectory("getKaptGeneratedSourcesDir", project, sourceSetName)
|
||||||
|
val kaptGeneratedClassesDir = getKaptDirectory("getKaptGeneratedClassesDir", project, sourceSetName)
|
||||||
|
val kaptGeneratedKotlinSourcesDir = getKaptDirectory("getKaptGeneratedKotlinSourcesDir", project, sourceSetName)
|
||||||
|
sourceSets += KaptSourceSetModelImpl(
|
||||||
|
sourceSetName, isTest, kaptGeneratedSourcesDir, kaptGeneratedClassesDir, kaptGeneratedKotlinSourcesDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return KaptGradleModelImpl(kaptIsEnabled, project.buildDir, sourceSets)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getKaptDirectory(funName: String, project: Project, sourceSetName: String): String {
|
||||||
|
val kotlinKaptPlugin = project.plugins.findPlugin("kotlin-kapt") ?: return ""
|
||||||
|
|
||||||
|
val targetMethod = kotlinKaptPlugin::class.java.methods.firstOrNull {
|
||||||
|
Modifier.isStatic(it.modifiers) && it.name == funName && it.parameterCount == 2
|
||||||
|
} ?: return ""
|
||||||
|
|
||||||
|
return (targetMethod(null, project, sourceSetName) as? File)?.absolutePath ?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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.samWithReceiver.ide
|
||||||
|
|
||||||
|
/*
|
||||||
|
import org.jetbrains.kotlin.annotation.plugin.ide.AbstractMavenImportHandler
|
||||||
|
import org.jetbrains.kotlin.annotation.plugin.ide.AnnotationBasedCompilerPluginSetup
|
||||||
|
import org.jetbrains.kotlin.annotation.plugin.ide.AnnotationBasedCompilerPluginSetup.PluginOption
|
||||||
|
import org.jetbrains.kotlin.samWithReceiver.SamWithReceiverCommandLineProcessor
|
||||||
|
import org.jetbrains.kotlin.utils.PathUtil
|
||||||
|
|
||||||
|
class SamWithReceiverMavenProjectImportHandler : AbstractMavenImportHandler() {
|
||||||
|
private companion object {
|
||||||
|
val ANNOTATION_PARAMETER_PREFIX = "sam-with-receiver:${SamWithReceiverCommandLineProcessor.ANNOTATION_OPTION.name}="
|
||||||
|
}
|
||||||
|
|
||||||
|
override val compilerPluginId = SamWithReceiverCommandLineProcessor.PLUGIN_ID
|
||||||
|
override val pluginName = "samWithReceiver"
|
||||||
|
override val mavenPluginArtifactName = "kotlin-maven-sam-with-receiver"
|
||||||
|
override val pluginJarFileFromIdea = PathUtil.kotlinPathsForIdeaPlugin.allOpenPluginJarPath
|
||||||
|
|
||||||
|
override fun getOptions(enabledCompilerPlugins: List<String>, compilerPluginOptions: List<String>): List<PluginOption>? {
|
||||||
|
if ("sam-with-receiver" !in enabledCompilerPlugins) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val annotations = mutableListOf<String>()
|
||||||
|
|
||||||
|
for ((presetName, presetAnnotations) in SamWithReceiverCommandLineProcessor.SUPPORTED_PRESETS) {
|
||||||
|
if (presetName in enabledCompilerPlugins) {
|
||||||
|
annotations.addAll(presetAnnotations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
annotations.addAll(compilerPluginOptions.mapNotNull { text ->
|
||||||
|
if (!text.startsWith(ANNOTATION_PARAMETER_PREFIX)) return@mapNotNull null
|
||||||
|
text.substring(ANNOTATION_PARAMETER_PREFIX.length)
|
||||||
|
})
|
||||||
|
|
||||||
|
return annotations.map { PluginOption(SamWithReceiverCommandLineProcessor.ANNOTATION_OPTION.name, it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||||
|
import org.gradle.jvm.tasks.Jar
|
||||||
|
|
||||||
|
description = "Kotlin IDEA Ultimate plugin"
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
val ideaProjectResources = project(":idea").the<JavaPluginConvention>().sourceSets["main"].output.resourcesDir
|
||||||
|
|
||||||
|
evaluationDependsOn(":prepare:idea-plugin")
|
||||||
|
|
||||||
|
val intellijUltimateEnabled : Boolean by rootProject.extra
|
||||||
|
|
||||||
|
val springClasspath by configurations.creating
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
if (intellijUltimateEnabled) {
|
||||||
|
testRuntime(intellijUltimateDep())
|
||||||
|
}
|
||||||
|
|
||||||
|
compileOnly(project(":kotlin-reflect-api"))
|
||||||
|
compile(projectDist(":kotlin-stdlib"))
|
||||||
|
compile(project(":core:descriptors")) { isTransitive = false }
|
||||||
|
compile(project(":compiler:psi")) { isTransitive = false }
|
||||||
|
compile(project(":core:descriptors.jvm")) { isTransitive = false }
|
||||||
|
compile(project(":core:util.runtime")) { isTransitive = false }
|
||||||
|
compile(project(":compiler:light-classes")) { isTransitive = false }
|
||||||
|
compile(project(":compiler:frontend")) { isTransitive = false }
|
||||||
|
compile(project(":compiler:frontend.java")) { isTransitive = false }
|
||||||
|
compile(project(":js:js.frontend")) { isTransitive = false }
|
||||||
|
compile(projectClasses(":idea"))
|
||||||
|
compile(project(":idea:idea-jvm")) { isTransitive = false }
|
||||||
|
compile(project(":idea:idea-core")) { isTransitive = false }
|
||||||
|
compile(project(":idea:ide-common")) { isTransitive = false }
|
||||||
|
compile(project(":idea:idea-gradle")) { isTransitive = false }
|
||||||
|
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
|
||||||
|
|
||||||
|
if (intellijUltimateEnabled) {
|
||||||
|
compileOnly(intellijUltimatePluginDep("NodeJS"))
|
||||||
|
compileOnly(intellijUltimateDep()) { includeJars("annotations", "trove4j", "openapi", "platform-api", "platform-impl", "java-api", "java-impl", "idea", "util", "jdom") }
|
||||||
|
compileOnly(intellijUltimatePluginDep("CSS"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("DatabaseTools"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("JavaEE"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("jsp"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("PersistenceSupport"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("Spring"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("properties"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("java-i18n"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("gradle"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("Groovy"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("junit"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("uml"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("JavaScriptLanguage"))
|
||||||
|
compileOnly(intellijUltimatePluginDep("JavaScriptDebugger"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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")) { isTransitive = false }
|
||||||
|
testCompile(projectTests(":compiler:tests-common"))
|
||||||
|
testCompile(projectTests(":idea")) { isTransitive = false }
|
||||||
|
testCompile(projectTests(":generators:test-generator"))
|
||||||
|
testCompile(commonDep("junit:junit"))
|
||||||
|
if (intellijUltimateEnabled) {
|
||||||
|
testCompileOnly(intellijUltimateDep()) { includeJars("platform-api", "platform-impl", "gson", "annotations", "trove4j", "openapi", "idea", "util", "jdom", rootProject = rootProject) }
|
||||||
|
}
|
||||||
|
testCompile(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false }
|
||||||
|
|
||||||
|
testRuntime(projectDist(":kotlin-reflect"))
|
||||||
|
testRuntime(project(":kotlin-script-runtime"))
|
||||||
|
testRuntime(projectRuntimeJar(":kotlin-compiler"))
|
||||||
|
testRuntime(project(":plugins:android-extensions-ide")) { isTransitive = false }
|
||||||
|
testRuntime(project(":plugins:android-extensions-compiler")) { isTransitive = false }
|
||||||
|
testRuntime(project(":plugins:annotation-based-compiler-plugins-ide-support")) { isTransitive = false }
|
||||||
|
testRuntime(project(":idea:idea-android")) { isTransitive = false }
|
||||||
|
testRuntime(project(":idea:idea-maven")) { isTransitive = false }
|
||||||
|
testRuntime(project(":idea:idea-jps-common")) { isTransitive = false }
|
||||||
|
testRuntime(project(":idea:formatter")) { isTransitive = false }
|
||||||
|
testRuntime(project(":sam-with-receiver-ide-plugin")) { isTransitive = false }
|
||||||
|
testRuntime(project(":kotlin-sam-with-receiver-compiler-plugin")) { isTransitive = false }
|
||||||
|
testRuntime(project(":noarg-ide-plugin")) { isTransitive = false }
|
||||||
|
testRuntime(project(":kotlin-noarg-compiler-plugin")) { isTransitive = false }
|
||||||
|
testRuntime(project(":allopen-ide-plugin")) { isTransitive = false }
|
||||||
|
testRuntime(project(":kotlin-allopen-compiler-plugin")) { isTransitive = false }
|
||||||
|
testRuntime(project(":plugins:kapt3-idea")) { isTransitive = false }
|
||||||
|
testRuntime(project(":plugins:uast-kotlin"))
|
||||||
|
testRuntime(project(":plugins:uast-kotlin-idea"))
|
||||||
|
testRuntime(intellijPluginDep("smali"))
|
||||||
|
|
||||||
|
if (intellijUltimateEnabled) {
|
||||||
|
testCompile(intellijUltimatePluginDep("CSS"))
|
||||||
|
testCompile(intellijUltimatePluginDep("DatabaseTools"))
|
||||||
|
testCompile(intellijUltimatePluginDep("JavaEE"))
|
||||||
|
testCompile(intellijUltimatePluginDep("jsp"))
|
||||||
|
testCompile(intellijUltimatePluginDep("PersistenceSupport"))
|
||||||
|
testCompile(intellijUltimatePluginDep("Spring"))
|
||||||
|
testCompile(intellijUltimatePluginDep("uml"))
|
||||||
|
testCompile(intellijUltimatePluginDep("JavaScriptLanguage"))
|
||||||
|
testCompile(intellijUltimatePluginDep("JavaScriptDebugger"))
|
||||||
|
testCompile(intellijUltimatePluginDep("NodeJS"))
|
||||||
|
testCompile(intellijUltimatePluginDep("properties"))
|
||||||
|
testCompile(intellijUltimatePluginDep("java-i18n"))
|
||||||
|
testCompile(intellijUltimatePluginDep("gradle"))
|
||||||
|
testCompile(intellijUltimatePluginDep("Groovy"))
|
||||||
|
testCompile(intellijUltimatePluginDep("junit"))
|
||||||
|
testRuntime(intellijUltimatePluginDep("coverage"))
|
||||||
|
testRuntime(intellijUltimatePluginDep("maven"))
|
||||||
|
testRuntime(intellijUltimatePluginDep("android"))
|
||||||
|
testRuntime(intellijUltimatePluginDep("testng"))
|
||||||
|
testRuntime(intellijUltimatePluginDep("IntelliLang"))
|
||||||
|
testRuntime(intellijUltimatePluginDep("copyright"))
|
||||||
|
testRuntime(intellijUltimatePluginDep("java-decompiler"))
|
||||||
|
}
|
||||||
|
|
||||||
|
testRuntime(files("${System.getProperty("java.home")}/../lib/tools.jar"))
|
||||||
|
|
||||||
|
springClasspath(commonDep("org.springframework", "spring-core"))
|
||||||
|
springClasspath(commonDep("org.springframework", "spring-beans"))
|
||||||
|
springClasspath(commonDep("org.springframework", "spring-context"))
|
||||||
|
springClasspath(commonDep("org.springframework", "spring-tx"))
|
||||||
|
springClasspath(commonDep("org.springframework", "spring-web"))
|
||||||
|
}
|
||||||
|
|
||||||
|
val preparedResources = File(buildDir, "prepResources")
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { projectDefault() }
|
||||||
|
"test" {
|
||||||
|
projectDefault()
|
||||||
|
resources.srcDir(preparedResources)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val ultimatePluginXmlContent: String by lazy {
|
||||||
|
val sectRex = Regex("""^\s*</?idea-plugin>\s*$""")
|
||||||
|
File(projectDir, "resources/META-INF/ultimate-plugin.xml")
|
||||||
|
.readLines()
|
||||||
|
.filterNot { it.matches(sectRex) }
|
||||||
|
.joinToString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
val prepareResources by task<Copy> {
|
||||||
|
dependsOn(":idea:assemble")
|
||||||
|
from(ideaProjectResources, {
|
||||||
|
exclude("META-INF/plugin.xml")
|
||||||
|
})
|
||||||
|
into(preparedResources)
|
||||||
|
}
|
||||||
|
|
||||||
|
val preparePluginXml by task<Copy> {
|
||||||
|
dependsOn(":idea:assemble")
|
||||||
|
from(ideaProjectResources, { include("META-INF/plugin.xml") })
|
||||||
|
into(preparedResources)
|
||||||
|
filter {
|
||||||
|
it?.replace("<!-- ULTIMATE-PLUGIN-PLACEHOLDER -->", ultimatePluginXmlContent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val communityPluginProject = ":prepare:idea-plugin"
|
||||||
|
|
||||||
|
val jar = runtimeJar(task<ShadowJar>("shadowJar")) {
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
dependsOn(preparePluginXml)
|
||||||
|
dependsOn("$communityPluginProject:shadowJar")
|
||||||
|
val communityPluginJar = project(communityPluginProject).configurations["runtimeJar"].artifacts.files.singleFile
|
||||||
|
from(zipTree(communityPluginJar), { exclude("META-INF/plugin.xml") })
|
||||||
|
from(preparedResources, { include("META-INF/plugin.xml") })
|
||||||
|
from(the<JavaPluginConvention>().sourceSets.getByName("main").output)
|
||||||
|
archiveName = "kotlin-plugin.jar"
|
||||||
|
}
|
||||||
|
|
||||||
|
val ideaPluginDir: File by rootProject.extra
|
||||||
|
val ideaUltimatePluginDir: File by rootProject.extra
|
||||||
|
|
||||||
|
task<Copy>("ideaUltimatePlugin") {
|
||||||
|
dependsOn(":ideaPlugin")
|
||||||
|
into(ideaUltimatePluginDir)
|
||||||
|
from(ideaPluginDir) { exclude("lib/kotlin-plugin.jar") }
|
||||||
|
from(jar, { into("lib") })
|
||||||
|
}
|
||||||
|
|
||||||
|
task("idea-ultimate-plugin") {
|
||||||
|
dependsOn("ideaUltimatePlugin")
|
||||||
|
doFirst { logger.warn("'$name' task is deprecated, use '${dependsOn.last()}' instead") }
|
||||||
|
}
|
||||||
|
|
||||||
|
task("ideaUltimatePluginTest") {
|
||||||
|
dependsOn("check")
|
||||||
|
}
|
||||||
|
|
||||||
|
projectTest {
|
||||||
|
dependsOn(prepareResources)
|
||||||
|
dependsOn(preparePluginXml)
|
||||||
|
workingDir = rootDir
|
||||||
|
doFirst {
|
||||||
|
if (intellijUltimateEnabled) {
|
||||||
|
systemProperty("idea.home.path", intellijUltimateRootDir().canonicalPath)
|
||||||
|
}
|
||||||
|
systemProperty("spring.classpath", springClasspath.asPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val generateTests by generator("org.jetbrains.kotlin.tests.GenerateUltimateTestsKt")
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly(project(":idea"))
|
||||||
|
compileOnly(project(":idea:idea-maven"))
|
||||||
|
compileOnly(project(":idea:idea-gradle"))
|
||||||
|
compileOnly(project(":idea:idea-jvm"))
|
||||||
|
|
||||||
|
compile(intellijDep())
|
||||||
|
runtimeOnly(files(toolsJar()))
|
||||||
|
}
|
||||||
|
|
||||||
|
val intellijUltimateEnabled : Boolean by rootProject.extra
|
||||||
|
|
||||||
|
val ideaUltimatePluginDir: File by rootProject.extra
|
||||||
|
val ideaUltimateSandboxDir: File by rootProject.extra
|
||||||
|
|
||||||
|
if (intellijUltimateEnabled) {
|
||||||
|
runIdeTask("runUltimate", ideaUltimatePluginDir, ideaUltimateSandboxDir) {
|
||||||
|
dependsOn(":dist", ":ideaPlugin", ":ultimate:ideaUltimatePlugin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
<project xmlns:if="ant:if" xmlns:unless="ant:unless" name="Update Dependencies" default="update">
|
<project xmlns:if="ant:if" xmlns:unless="ant:unless" name="Update Dependencies" default="update">
|
||||||
<!--as31 -> as32-->
|
|
||||||
<import file="common.xml" optional="false"/>
|
<import file="common.xml" optional="false"/>
|
||||||
|
|
||||||
<property name="automerge_dummy" value="This property is used to trick git merge. Do not delete empty lines around."/>
|
<property name="automerge_dummy" value="This property is used to trick git merge. Do not delete empty lines around."/>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
|
||||||
extra["versions.intellijSdk"] = "173.4548.28"
|
extra["versions.intellijSdk"] = "181.4203.6"
|
||||||
extra["versions.androidBuildTools"] = "r23.0.1"
|
extra["versions.androidBuildTools"] = "r23.0.1"
|
||||||
extra["versions.idea.NodeJS"] = "172.3757.32"
|
extra["versions.idea.NodeJS"] = "181.3494.12"
|
||||||
extra["versions.androidStudioRelease"] = "3.2.0.2"
|
//extra["versions.androidStudioRelease"] = "3.1.0.5"
|
||||||
extra["versions.androidStudioBuild"] = "173.4595177"
|
//extra["versions.androidStudioBuild"] = "173.4506631"
|
||||||
|
|
||||||
val gradleJars = listOf(
|
val gradleJars = listOf(
|
||||||
"gradle-api",
|
"gradle-api",
|
||||||
@@ -31,6 +31,7 @@ when (platform) {
|
|||||||
extra["versions.jar.kxml2"] = "2.3.0"
|
extra["versions.jar.kxml2"] = "2.3.0"
|
||||||
extra["versions.jar.streamex"] = "0.6.5"
|
extra["versions.jar.streamex"] = "0.6.5"
|
||||||
extra["versions.jar.gson"] = "2.8.2"
|
extra["versions.jar.gson"] = "2.8.2"
|
||||||
|
extra["versions.jar.oro"] = "2.0.8"
|
||||||
for (jar in gradleJars) {
|
for (jar in gradleJars) {
|
||||||
extra["versions.jar.$jar"] = "4.4"
|
extra["versions.jar.$jar"] = "4.4"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user