mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-20 00:21:29 +00:00
Compare commits
50 Commits
1.5.0-gith
...
build-1.2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0feab3e0d9 | ||
|
|
54c15bb330 | ||
|
|
dd6bebe340 | ||
|
|
344fdfe648 | ||
|
|
1986603404 | ||
|
|
6043c35ac1 | ||
|
|
64db423b8b | ||
|
|
7dc19af994 | ||
|
|
8165e4546f | ||
|
|
3cc01632a0 | ||
|
|
e4916a8f80 | ||
|
|
2e9182cefc | ||
|
|
098cfe7967 | ||
|
|
5f6b997894 | ||
|
|
d53a28de26 | ||
|
|
4949ff3e63 | ||
|
|
e062be9fb3 | ||
|
|
cfcecbd389 | ||
|
|
926e6ba1b5 | ||
|
|
1a6c860595 | ||
|
|
58f852ff3f | ||
|
|
a43ea8f7ca | ||
|
|
9a56ba49fc | ||
|
|
2a9ceef833 | ||
|
|
a443476918 | ||
|
|
e5a0d4e761 | ||
|
|
e71c868620 | ||
|
|
a69ca81c26 | ||
|
|
44e17f74a3 | ||
|
|
b024c997ca | ||
|
|
9f43922eb2 | ||
|
|
3a76611b95 | ||
|
|
aaad2d589c | ||
|
|
b98aeeb77c | ||
|
|
edeba28e84 | ||
|
|
b0757e3080 | ||
|
|
3ccdb9f2a9 | ||
|
|
e0126f9036 | ||
|
|
d0ea36b2ab | ||
|
|
fc5a56983d | ||
|
|
8c7db2a8d0 | ||
|
|
3857775684 | ||
|
|
cca12ac647 | ||
|
|
de1aada638 | ||
|
|
7b87d2bfc3 | ||
|
|
e238423425 | ||
|
|
f730f14d0d | ||
|
|
cf53922f1f | ||
|
|
b81c590e12 | ||
|
|
ed0a79e556 |
5836
ChangeLog.md
5836
ChangeLog.md
File diff suppressed because it is too large
Load Diff
@@ -64,6 +64,9 @@ abstract class BuildMetaInfoFactory<T : BuildMetaInfo>(private val metaInfoClass
|
||||
)
|
||||
}
|
||||
|
||||
fun serializeToString(args: CommonCompilerArguments): String =
|
||||
serializeToString(create(args))
|
||||
|
||||
fun serializeToString(info: T): String =
|
||||
serializeToPlainText(info, metaInfoClass)
|
||||
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* 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.incremental
|
||||
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.config.IncrementalCompilation
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmBytecodeBinaryVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
private val NORMAL_VERSION = 9
|
||||
private val DATA_CONTAINER_VERSION = 3
|
||||
|
||||
private val NORMAL_VERSION_FILE_NAME = "format-version.txt"
|
||||
private val DATA_CONTAINER_VERSION_FILE_NAME = "data-container-format-version.txt"
|
||||
|
||||
class CacheVersion(
|
||||
private val ownVersion: Int,
|
||||
private val versionFile: File,
|
||||
private val whenVersionChanged: CacheVersion.Action,
|
||||
private val whenTurnedOn: CacheVersion.Action,
|
||||
private val whenTurnedOff: CacheVersion.Action,
|
||||
private val isEnabled: Boolean
|
||||
) {
|
||||
|
||||
private val actualVersion: Int?
|
||||
get() = try {
|
||||
versionFile.readText().toInt()
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
null
|
||||
}
|
||||
catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
|
||||
private val expectedVersion: Int
|
||||
get() {
|
||||
val metadata = JvmMetadataVersion.INSTANCE
|
||||
val bytecode = JvmBytecodeBinaryVersion.INSTANCE
|
||||
return ownVersion * 1000000 +
|
||||
bytecode.major * 10000 + bytecode.minor * 100 +
|
||||
metadata.major * 1000 + metadata.minor
|
||||
}
|
||||
|
||||
fun checkVersion(): Action =
|
||||
when (versionFile.exists() to isEnabled) {
|
||||
true to true -> if (actualVersion != expectedVersion) whenVersionChanged else Action.DO_NOTHING
|
||||
false to true -> whenTurnedOn
|
||||
true to false -> whenTurnedOff
|
||||
else -> Action.DO_NOTHING
|
||||
}
|
||||
|
||||
fun saveIfNeeded() {
|
||||
if (!isEnabled) return
|
||||
|
||||
if (!versionFile.parentFile.exists()) {
|
||||
versionFile.parentFile.mkdirs()
|
||||
}
|
||||
|
||||
versionFile.writeText(expectedVersion.toString())
|
||||
}
|
||||
|
||||
fun clean() {
|
||||
versionFile.delete()
|
||||
}
|
||||
|
||||
@get:TestOnly
|
||||
val formatVersionFile: File
|
||||
get() = versionFile
|
||||
|
||||
// Order of entries is important, because actions are sorted in KotlinBuilder::checkVersions
|
||||
enum class Action {
|
||||
REBUILD_ALL_KOTLIN,
|
||||
REBUILD_CHUNK,
|
||||
CLEAN_NORMAL_CACHES,
|
||||
CLEAN_DATA_CONTAINER,
|
||||
DO_NOTHING
|
||||
}
|
||||
}
|
||||
|
||||
fun normalCacheVersion(dataRoot: File, enabled: Boolean): CacheVersion =
|
||||
CacheVersion(ownVersion = NORMAL_VERSION,
|
||||
versionFile = File(dataRoot, NORMAL_VERSION_FILE_NAME),
|
||||
whenVersionChanged = CacheVersion.Action.REBUILD_CHUNK,
|
||||
whenTurnedOn = CacheVersion.Action.REBUILD_CHUNK,
|
||||
whenTurnedOff = CacheVersion.Action.CLEAN_NORMAL_CACHES,
|
||||
isEnabled = enabled)
|
||||
|
||||
fun dataContainerCacheVersion(dataRoot: File, enabled: Boolean): CacheVersion =
|
||||
CacheVersion(ownVersion = DATA_CONTAINER_VERSION,
|
||||
versionFile = File(dataRoot, DATA_CONTAINER_VERSION_FILE_NAME),
|
||||
whenVersionChanged = CacheVersion.Action.REBUILD_ALL_KOTLIN,
|
||||
whenTurnedOn = CacheVersion.Action.REBUILD_ALL_KOTLIN,
|
||||
whenTurnedOff = CacheVersion.Action.CLEAN_DATA_CONTAINER,
|
||||
isEnabled = enabled)
|
||||
@@ -25,6 +25,8 @@ import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.build.GeneratedJvmClass
|
||||
import org.jetbrains.kotlin.config.IncrementalCompilation
|
||||
import org.jetbrains.kotlin.incremental.storage.*
|
||||
import org.jetbrains.kotlin.incremental.storage.version.clean
|
||||
import org.jetbrains.kotlin.incremental.storage.version.localCacheVersionManager
|
||||
import org.jetbrains.kotlin.inline.inlineFunctionsJvmNames
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
@@ -43,8 +45,8 @@ import java.util.*
|
||||
val KOTLIN_CACHE_DIRECTORY_NAME = "kotlin"
|
||||
|
||||
open class IncrementalJvmCache(
|
||||
private val targetDataRoot: File,
|
||||
targetOutputDir: File?
|
||||
private val targetDataRoot: File,
|
||||
targetOutputDir: File?
|
||||
) : AbstractIncrementalCache<JvmClassName>(File(targetDataRoot, KOTLIN_CACHE_DIRECTORY_NAME)), IncrementalCache {
|
||||
companion object {
|
||||
private val PROTO_MAP = "proto"
|
||||
@@ -81,16 +83,16 @@ open class IncrementalJvmCache(
|
||||
// used in gradle
|
||||
@Suppress("unused")
|
||||
fun classesBySources(sources: Iterable<File>): Iterable<JvmClassName> =
|
||||
sources.flatMap { sourceToClassesMap[it] }
|
||||
sources.flatMap { sourceToClassesMap[it] }
|
||||
|
||||
fun sourceInCache(file: File): Boolean =
|
||||
sourceToClassesMap.contains(file)
|
||||
|
||||
fun sourcesByInternalName(internalName: String): Collection<File> =
|
||||
internalNameToSource[internalName]
|
||||
internalNameToSource[internalName]
|
||||
|
||||
fun isMultifileFacade(className: JvmClassName): Boolean =
|
||||
className in multifileFacadeToParts
|
||||
className in multifileFacadeToParts
|
||||
|
||||
override fun getClassFilePath(internalClassName: String): String {
|
||||
return toSystemIndependentName(File(outputDir, "$internalClassName.class").canonicalPath)
|
||||
@@ -129,7 +131,7 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
KotlinClassHeader.Kind.MULTIFILE_CLASS -> {
|
||||
val partNames = kotlinClass.classHeader.data?.toList()
|
||||
?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}")
|
||||
?: throw AssertionError("Multifile class has no parts: ${kotlinClass.className}")
|
||||
multifileFacadeToParts[className] = partNames
|
||||
// When a class is replaced with a facade with the same name,
|
||||
// the class' proto wouldn't ever be deleted,
|
||||
@@ -177,15 +179,15 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
fun getObsoleteJavaClasses(): Collection<ClassId> =
|
||||
dirtyOutputClassesMap.getDirtyOutputClasses()
|
||||
.mapNotNull {
|
||||
javaSourcesProtoMap[it]?.classId
|
||||
}
|
||||
dirtyOutputClassesMap.getDirtyOutputClasses()
|
||||
.mapNotNull {
|
||||
javaSourcesProtoMap[it]?.classId
|
||||
}
|
||||
|
||||
fun isJavaClassToTrack(classId: ClassId): Boolean {
|
||||
val jvmClassName = JvmClassName.byClassId(classId)
|
||||
return dirtyOutputClassesMap.isDirty(jvmClassName) ||
|
||||
jvmClassName !in javaSourcesProtoMap
|
||||
jvmClassName !in javaSourcesProtoMap
|
||||
}
|
||||
|
||||
fun isJavaClassAlreadyInCache(classId: ClassId): Boolean {
|
||||
@@ -210,8 +212,7 @@ open class IncrementalJvmCache(
|
||||
|
||||
if (notRemovedParts.isEmpty()) {
|
||||
multifileFacadeToParts.remove(facade)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
multifileFacadeToParts[facade] = notRemovedParts
|
||||
}
|
||||
}
|
||||
@@ -265,7 +266,7 @@ open class IncrementalJvmCache(
|
||||
|
||||
override fun clean() {
|
||||
super.clean()
|
||||
normalCacheVersion(targetDataRoot, IncrementalCompilation.isEnabledForJvm()).clean()
|
||||
localCacheVersionManager(targetDataRoot, IncrementalCompilation.isEnabledForJvm()).clean()
|
||||
}
|
||||
|
||||
private inner class ProtoMap(storageFile: File) : BasicStringMap<ProtoMapValue>(storageFile, ProtoMapValueExternalizer) {
|
||||
@@ -290,9 +291,11 @@ open class IncrementalJvmCache(
|
||||
|
||||
val key = kotlinClass.className.internalName
|
||||
val oldData = storage[key]
|
||||
val newData = ProtoMapValue(header.kind != KotlinClassHeader.Kind.CLASS,
|
||||
BitEncoding.decodeBytes(header.data!!),
|
||||
header.strings!!)
|
||||
val newData = ProtoMapValue(
|
||||
header.kind != KotlinClassHeader.Kind.CLASS,
|
||||
BitEncoding.decodeBytes(header.data!!),
|
||||
header.strings!!
|
||||
)
|
||||
storage[key] = newData
|
||||
|
||||
val packageFqName = kotlinClass.className.packageFqName
|
||||
@@ -300,10 +303,10 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
operator fun contains(className: JvmClassName): Boolean =
|
||||
className.internalName in storage
|
||||
className.internalName in storage
|
||||
|
||||
operator fun get(className: JvmClassName): ProtoMapValue? =
|
||||
storage[className.internalName]
|
||||
storage[className.internalName]
|
||||
|
||||
fun remove(className: JvmClassName, changesCollector: ChangesCollector) {
|
||||
val key = className.internalName
|
||||
@@ -319,15 +322,16 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
}
|
||||
|
||||
private inner class JavaSourcesProtoMap(storageFile: File) : BasicStringMap<SerializedJavaClass>(storageFile, JavaClassProtoMapValueExternalizer) {
|
||||
private inner class JavaSourcesProtoMap(storageFile: File) :
|
||||
BasicStringMap<SerializedJavaClass>(storageFile, JavaClassProtoMapValueExternalizer) {
|
||||
fun process(jvmClassName: JvmClassName, newData: SerializedJavaClass, changesCollector: ChangesCollector) {
|
||||
val key = jvmClassName.internalName
|
||||
val oldData = storage[key]
|
||||
storage[key] = newData
|
||||
|
||||
changesCollector.collectProtoChanges(
|
||||
oldData?.toProtoData(), newData.toProtoData(),
|
||||
collectAllMembersForNewClass = true
|
||||
oldData?.toProtoData(), newData.toProtoData(),
|
||||
collectAllMembersForNewClass = true
|
||||
)
|
||||
}
|
||||
|
||||
@@ -340,13 +344,13 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
operator fun get(className: JvmClassName): SerializedJavaClass? =
|
||||
storage[className.internalName]
|
||||
storage[className.internalName]
|
||||
|
||||
operator fun contains(className: JvmClassName): Boolean =
|
||||
className.internalName in storage
|
||||
className.internalName in storage
|
||||
|
||||
override fun dumpValue(value: SerializedJavaClass): String =
|
||||
java.lang.Long.toHexString(value.proto.toByteArray().md5())
|
||||
java.lang.Long.toHexString(value.proto.toByteArray().md5())
|
||||
}
|
||||
|
||||
// todo: reuse code with InlineFunctionsMap?
|
||||
@@ -368,7 +372,7 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
operator fun contains(className: JvmClassName): Boolean =
|
||||
className.internalName in storage
|
||||
className.internalName in storage
|
||||
|
||||
fun process(kotlinClass: LocalFileKotlinClass, changesCollector: ChangesCollector) {
|
||||
val key = kotlinClass.className.internalName
|
||||
@@ -377,8 +381,7 @@ open class IncrementalJvmCache(
|
||||
val newMap = getConstantsMap(kotlinClass.fileContents)
|
||||
if (newMap.isNotEmpty()) {
|
||||
storage[key] = newMap
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
storage.remove(key)
|
||||
}
|
||||
|
||||
@@ -392,7 +395,7 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
override fun dumpValue(value: Map<String, Any>): String =
|
||||
value.dumpMap(Any::toString)
|
||||
value.dumpMap(Any::toString)
|
||||
}
|
||||
|
||||
private inner class PackagePartMap(storageFile: File) : BasicStringMap<Boolean>(storageFile, BooleanDataDescriptor.INSTANCE) {
|
||||
@@ -405,21 +408,22 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
fun isPackagePart(className: JvmClassName): Boolean =
|
||||
className.internalName in storage
|
||||
className.internalName in storage
|
||||
|
||||
override fun dumpValue(value: Boolean) = ""
|
||||
}
|
||||
|
||||
private inner class MultifileClassFacadeMap(storageFile: File) : BasicStringMap<Collection<String>>(storageFile, StringCollectionExternalizer) {
|
||||
private inner class MultifileClassFacadeMap(storageFile: File) :
|
||||
BasicStringMap<Collection<String>>(storageFile, StringCollectionExternalizer) {
|
||||
operator fun set(className: JvmClassName, partNames: Collection<String>) {
|
||||
storage[className.internalName] = partNames
|
||||
}
|
||||
|
||||
operator fun get(className: JvmClassName): Collection<String>? =
|
||||
storage[className.internalName]
|
||||
storage[className.internalName]
|
||||
|
||||
operator fun contains(className: JvmClassName): Boolean =
|
||||
className.internalName in storage
|
||||
className.internalName in storage
|
||||
|
||||
fun remove(className: JvmClassName) {
|
||||
storage.remove(className.internalName)
|
||||
@@ -428,13 +432,14 @@ open class IncrementalJvmCache(
|
||||
override fun dumpValue(value: Collection<String>): String = value.dumpCollection()
|
||||
}
|
||||
|
||||
private inner class MultifileClassPartMap(storageFile: File) : BasicStringMap<String>(storageFile, EnumeratorStringDescriptor.INSTANCE) {
|
||||
private inner class MultifileClassPartMap(storageFile: File) :
|
||||
BasicStringMap<String>(storageFile, EnumeratorStringDescriptor.INSTANCE) {
|
||||
fun set(partName: String, facadeName: String) {
|
||||
storage[partName] = facadeName
|
||||
}
|
||||
|
||||
fun get(partName: JvmClassName): String? =
|
||||
storage[partName.internalName]
|
||||
storage[partName.internalName]
|
||||
|
||||
fun remove(className: JvmClassName) {
|
||||
storage.remove(className.internalName)
|
||||
@@ -443,20 +448,21 @@ open class IncrementalJvmCache(
|
||||
override fun dumpValue(value: String): String = value
|
||||
}
|
||||
|
||||
inner class InternalNameToSourcesMap(storageFile: File) : BasicStringMap<Collection<String>>(storageFile, EnumeratorStringDescriptor(), PathCollectionExternalizer) {
|
||||
inner class InternalNameToSourcesMap(storageFile: File) :
|
||||
BasicStringMap<Collection<String>>(storageFile, EnumeratorStringDescriptor(), PathCollectionExternalizer) {
|
||||
operator fun set(internalName: String, sourceFiles: Iterable<File>) {
|
||||
storage[internalName] = sourceFiles.map { it.canonicalPath }
|
||||
}
|
||||
|
||||
operator fun get(internalName: String): Collection<File> =
|
||||
(storage[internalName] ?: emptyList()).map(::File)
|
||||
(storage[internalName] ?: emptyList()).map(::File)
|
||||
|
||||
fun remove(internalName: String) {
|
||||
storage.remove(internalName)
|
||||
}
|
||||
|
||||
override fun dumpValue(value: Collection<String>): String =
|
||||
value.dumpCollection()
|
||||
value.dumpCollection()
|
||||
}
|
||||
|
||||
private fun addToClassStorage(kotlinClass: LocalFileKotlinClass, srcFile: File) {
|
||||
@@ -464,7 +470,8 @@ open class IncrementalJvmCache(
|
||||
addToClassStorage(proto, nameResolver, srcFile)
|
||||
}
|
||||
|
||||
private inner class InlineFunctionsMap(storageFile: File) : BasicStringMap<Map<String, Long>>(storageFile, StringToLongMapExternalizer) {
|
||||
private inner class InlineFunctionsMap(storageFile: File) :
|
||||
BasicStringMap<Map<String, Long>>(storageFile, StringToLongMapExternalizer) {
|
||||
private fun getInlineFunctionsMap(header: KotlinClassHeader, bytes: ByteArray): Map<String, Long> {
|
||||
val inlineFunctions = inlineFunctionsJvmNames(header)
|
||||
if (inlineFunctions.isEmpty()) return emptyMap()
|
||||
@@ -472,7 +479,13 @@ open class IncrementalJvmCache(
|
||||
val result = HashMap<String, Long>()
|
||||
|
||||
ClassReader(bytes).accept(object : ClassVisitor(Opcodes.ASM5) {
|
||||
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
|
||||
override fun visitMethod(
|
||||
access: Int,
|
||||
name: String,
|
||||
desc: String,
|
||||
signature: String?,
|
||||
exceptions: Array<out String>?
|
||||
): MethodVisitor? {
|
||||
val dummyClassWriter = ClassWriter(Opcodes.ASM5)
|
||||
|
||||
return object : MethodVisitor(Opcodes.ASM5, dummyClassWriter.visitMethod(0, name, desc, null, exceptions)) {
|
||||
@@ -499,30 +512,35 @@ open class IncrementalJvmCache(
|
||||
val newMap = getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
|
||||
if (newMap.isNotEmpty()) {
|
||||
storage[key] = newMap
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
storage.remove(key)
|
||||
}
|
||||
|
||||
for (fn in oldMap.keys + newMap.keys) {
|
||||
changesCollector.collectMemberIfValueWasChanged(kotlinClass.scopeFqName(), functionNameBySignature(fn), oldMap[fn], newMap[fn])
|
||||
changesCollector.collectMemberIfValueWasChanged(
|
||||
kotlinClass.scopeFqName(),
|
||||
functionNameBySignature(fn),
|
||||
oldMap[fn],
|
||||
newMap[fn]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO get name in better way instead of using substringBefore
|
||||
private fun functionNameBySignature(signature: String): String =
|
||||
signature.substringBefore("(")
|
||||
signature.substringBefore("(")
|
||||
|
||||
fun remove(className: JvmClassName) {
|
||||
storage.remove(className.internalName)
|
||||
}
|
||||
|
||||
override fun dumpValue(value: Map<String, Long>): String =
|
||||
value.dumpMap { java.lang.Long.toHexString(it) }
|
||||
value.dumpMap { java.lang.Long.toHexString(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private object PathCollectionExternalizer : CollectionExternalizer<String>(PathStringDescriptor, { THashSet(FileUtil.PATH_HASHING_STRATEGY) })
|
||||
private object PathCollectionExternalizer :
|
||||
CollectionExternalizer<String>(PathStringDescriptor, { THashSet(FileUtil.PATH_HASHING_STRATEGY) })
|
||||
|
||||
sealed class ChangeInfo(val fqName: FqName) {
|
||||
open class MembersChanged(fqName: FqName, val names: Collection<String>) : ChangeInfo(fqName) {
|
||||
@@ -542,10 +560,10 @@ sealed class ChangeInfo(val fqName: FqName) {
|
||||
}
|
||||
|
||||
private fun LocalFileKotlinClass.scopeFqName() =
|
||||
when (classHeader.kind) {
|
||||
KotlinClassHeader.Kind.CLASS -> className.fqNameForClassNameWithoutDollars
|
||||
else -> className.packageFqName
|
||||
}
|
||||
when (classHeader.kind) {
|
||||
KotlinClassHeader.Kind.CLASS -> className.fqNameForClassNameWithoutDollars
|
||||
else -> className.packageFqName
|
||||
}
|
||||
|
||||
fun ByteArray.md5(): Long {
|
||||
val d = MessageDigest.getInstance("MD5").digest(this)!!
|
||||
@@ -557,23 +575,24 @@ fun ByteArray.md5(): Long {
|
||||
or ((d[5].toLong() and 0xFFL) shl 40)
|
||||
or ((d[6].toLong() and 0xFFL) shl 48)
|
||||
or ((d[7].toLong() and 0xFFL) shl 56)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun <K : Comparable<K>, V> Map<K, V>.dumpMap(dumpValue: (V)->String): String =
|
||||
buildString {
|
||||
append("{")
|
||||
for (key in keys.sorted()) {
|
||||
if (length != 1) {
|
||||
append(", ")
|
||||
}
|
||||
|
||||
val value = get(key)?.let(dumpValue) ?: "null"
|
||||
append("$key -> $value")
|
||||
fun <K : Comparable<K>, V> Map<K, V>.dumpMap(dumpValue: (V) -> String): String =
|
||||
buildString {
|
||||
append("{")
|
||||
for (key in keys.sorted()) {
|
||||
if (length != 1) {
|
||||
append(", ")
|
||||
}
|
||||
append("}")
|
||||
}
|
||||
|
||||
@TestOnly fun <T : Comparable<T>> Collection<T>.dumpCollection(): String =
|
||||
"[${sorted().joinToString(", ", transform = Any::toString)}]"
|
||||
val value = get(key)?.let(dumpValue) ?: "null"
|
||||
append("$key -> $value")
|
||||
}
|
||||
append("}")
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun <T : Comparable<T>> Collection<T>.dumpCollection(): String =
|
||||
"[${sorted().joinToString(", ", transform = Any::toString)}]"
|
||||
|
||||
@@ -34,11 +34,14 @@ import org.jetbrains.kotlin.synthetic.SAM_LOOKUP_NAME
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
const val DELETE_MODULE_FILE_PROPERTY = "kotlin.delete.module.file.after.build"
|
||||
|
||||
fun makeModuleFile(
|
||||
name: String,
|
||||
isTest: Boolean,
|
||||
outputDir: File,
|
||||
sourcesToCompile: Iterable<File>,
|
||||
commonSources: Iterable<File>,
|
||||
javaSourceRoots: Iterable<JvmSourceRoot>,
|
||||
classpath: Iterable<File>,
|
||||
friendDirs: Iterable<File>
|
||||
@@ -53,6 +56,7 @@ fun makeModuleFile(
|
||||
sourcesToCompile.map { it.absoluteFile },
|
||||
javaSourceRoots,
|
||||
classpath,
|
||||
commonSources.map { it.absoluteFile },
|
||||
null,
|
||||
"java-production",
|
||||
isTest,
|
||||
@@ -130,6 +134,7 @@ fun ChangesCollector.getDirtyData(
|
||||
|
||||
if (change is ChangeInfo.SignatureChanged) {
|
||||
val fqNames = if (!change.areSubclassesAffected) listOf(change.fqName) else withSubtypes(change.fqName, caches)
|
||||
dirtyClassesFqNames.addAll(fqNames)
|
||||
|
||||
for (classFqName in fqNames) {
|
||||
assert(!classFqName.isRoot) { "$classFqName is root when processing $change" }
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-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.incremental.storage.version
|
||||
|
||||
/**
|
||||
* Diff between actual and expected cache attributes.
|
||||
* [status] are calculated based on this diff (see [CacheStatus]).
|
||||
* Based on that [status] system may perform required actions (i.e. rebuild something, clearing caches, etc...).
|
||||
*
|
||||
* [CacheAttributesDiff] can be used to cache current attribute values and as facade for version operations.
|
||||
*/
|
||||
data class CacheAttributesDiff<Attrs: Any>(
|
||||
val manager: CacheAttributesManager<Attrs>,
|
||||
val actual: Attrs?,
|
||||
val expected: Attrs?
|
||||
) {
|
||||
val status: CacheStatus
|
||||
get() =
|
||||
if (expected != null) {
|
||||
if (actual != null && manager.isCompatible(actual, expected)) CacheStatus.VALID
|
||||
else CacheStatus.INVALID
|
||||
} else {
|
||||
if (actual != null) CacheStatus.SHOULD_BE_CLEARED
|
||||
else CacheStatus.CLEARED
|
||||
}
|
||||
|
||||
fun saveExpectedIfNeeded() {
|
||||
if (expected != actual) manager.writeActualVersion(expected)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "$status: actual=$actual -> expected=$expected"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2010-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.incremental.storage.version
|
||||
|
||||
/**
|
||||
* Manages cache attributes values.
|
||||
*
|
||||
* Attribute values can be loaded by calling [loadActual].
|
||||
* Based on loaded actual and fixed [expected] values [CacheAttributesDiff] can be constructed which can calculate [CacheStatus].
|
||||
* Build system may perform required actions based on that (i.e. rebuild something, clearing caches, etc...).
|
||||
*
|
||||
* [CacheAttributesDiff] can be used to cache current attribute values and then can be used as facade for cache version operations.
|
||||
*/
|
||||
interface CacheAttributesManager<Attrs : Any> {
|
||||
/**
|
||||
* Cache attribute values expected by the current version of build system and compiler.
|
||||
* `null` means that cache is not required (incremental compilation is disabled).
|
||||
*/
|
||||
val expected: Attrs?
|
||||
|
||||
/**
|
||||
* Load actual cache attribute values.
|
||||
* `null` means that cache is not yet created.
|
||||
*
|
||||
* This is internal operation that should be implemented by particular implementation of CacheAttributesManager.
|
||||
* Consider using `loadDiff().actual` for getting actual values.
|
||||
*/
|
||||
fun loadActual(): Attrs?
|
||||
|
||||
/**
|
||||
* Write [values] as cache attributes for next build execution.
|
||||
*
|
||||
* This is internal operation that should be implemented by particular implementation of CacheAttributesManager.
|
||||
* Consider using `loadDiff().saveExpectedIfNeeded()` for saving attributes values for next build.
|
||||
*/
|
||||
fun writeActualVersion(values: Attrs?)
|
||||
|
||||
/**
|
||||
* Check if cache with [actual] attributes values can be used when [expected] attributes are required.
|
||||
*/
|
||||
fun isCompatible(actual: Attrs, expected: Attrs): Boolean = actual == expected
|
||||
}
|
||||
|
||||
fun <Attrs : Any> CacheAttributesManager<Attrs>.loadDiff(
|
||||
actual: Attrs? = this.loadActual(),
|
||||
expected: Attrs? = this.expected
|
||||
) = CacheAttributesDiff(this, actual, expected)
|
||||
|
||||
fun <Attrs : Any> CacheAttributesManager<Attrs>.loadAndCheckStatus() =
|
||||
loadDiff().status
|
||||
|
||||
/**
|
||||
* This method is kept only for compatibility.
|
||||
* Save [expected] cache attributes values if it is enabled and not equals to [actual].
|
||||
*/
|
||||
@Deprecated(
|
||||
message = "Consider using `this.loadDiff().saveExpectedIfNeeded()` and cache `loadDiff()` result.",
|
||||
replaceWith = ReplaceWith("loadDiff().saveExpectedIfNeeded()")
|
||||
)
|
||||
fun <Attrs : Any> CacheAttributesManager<Attrs>.saveIfNeeded(
|
||||
actual: Attrs? = this.loadActual(),
|
||||
expected: Attrs = this.expected
|
||||
?: error("To save disabled cache status [delete] should be called (this behavior is kept for compatibility)")
|
||||
) = loadDiff(actual, expected).saveExpectedIfNeeded()
|
||||
|
||||
/**
|
||||
* This method is kept only for compatibility.
|
||||
* Delete actual cache attributes values if it existed.
|
||||
*/
|
||||
@Deprecated(
|
||||
message = "Consider using `this.loadDiff().saveExpectedIfNeeded()` and cache `loadDiff()` result.",
|
||||
replaceWith = ReplaceWith("writeActualVersion(null)")
|
||||
)
|
||||
fun CacheAttributesManager<*>.clean() {
|
||||
writeActualVersion(null)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-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.incremental.storage.version
|
||||
|
||||
/**
|
||||
* Status that is used by system to perform required actions (i.e. rebuild something, clearing caches, etc...).
|
||||
*/
|
||||
enum class CacheStatus {
|
||||
/**
|
||||
* Cache is valid and ready to use.
|
||||
*/
|
||||
VALID,
|
||||
|
||||
/**
|
||||
* Cache is not exists or have outdated versions and/or other attributes.
|
||||
*/
|
||||
INVALID,
|
||||
|
||||
/**
|
||||
* Cache is exists, but not required anymore.
|
||||
*/
|
||||
SHOULD_BE_CLEARED,
|
||||
|
||||
/**
|
||||
* Cache is not exists and not required.
|
||||
*/
|
||||
CLEARED
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-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.incremental.storage.version
|
||||
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmBytecodeBinaryVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* Manages files with actual version [loadActual] and provides expected version [expected].
|
||||
* Based on that actual and expected versions [CacheStatus] can be calculated.
|
||||
* This can be done by constructing [CacheAttributesDiff] and calling [CacheAttributesDiff.status].
|
||||
* Based on that status system may perform required actions (i.e. rebuild something, clearing caches, etc...).
|
||||
*/
|
||||
class CacheVersionManager(
|
||||
private val versionFile: File,
|
||||
expectedOwnVersion: Int?
|
||||
) : CacheAttributesManager<CacheVersion> {
|
||||
override val expected: CacheVersion? =
|
||||
if (expectedOwnVersion == null) null
|
||||
else {
|
||||
val metadata = JvmMetadataVersion.INSTANCE
|
||||
val bytecode = JvmBytecodeBinaryVersion.INSTANCE
|
||||
|
||||
CacheVersion(
|
||||
expectedOwnVersion * 1000000 +
|
||||
bytecode.major * 10000 + bytecode.minor * 100 +
|
||||
metadata.major * 1000 + metadata.minor
|
||||
)
|
||||
}
|
||||
|
||||
override fun loadActual(): CacheVersion? =
|
||||
if (!versionFile.exists()) null
|
||||
else try {
|
||||
CacheVersion(versionFile.readText().toInt())
|
||||
} catch (e: NumberFormatException) {
|
||||
null
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
|
||||
override fun writeActualVersion(values: CacheVersion?) {
|
||||
if (values == null) versionFile.delete()
|
||||
else {
|
||||
versionFile.parentFile.mkdirs()
|
||||
versionFile.writeText(values.version.toString())
|
||||
}
|
||||
}
|
||||
|
||||
@get:TestOnly
|
||||
val versionFileForTesting: File
|
||||
get() = versionFile
|
||||
}
|
||||
|
||||
data class CacheVersion(val version: Int)
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2010-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.incremental.storage.version
|
||||
|
||||
import java.io.File
|
||||
|
||||
private val NORMAL_VERSION = 9
|
||||
private val NORMAL_VERSION_FILE_NAME = "format-version.txt"
|
||||
|
||||
fun localCacheVersionManager(dataRoot: File, isCachesEnabled: Boolean) =
|
||||
CacheVersionManager(
|
||||
File(dataRoot, NORMAL_VERSION_FILE_NAME),
|
||||
if (isCachesEnabled) NORMAL_VERSION else null
|
||||
)
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-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.incremental.storage.version
|
||||
|
||||
import java.io.File
|
||||
|
||||
private val DATA_CONTAINER_VERSION_FILE_NAME = "data-container-format-version.txt"
|
||||
private val DATA_CONTAINER_VERSION = 3
|
||||
|
||||
fun lookupsCacheVersionManager(dataRoot: File, isEnabled: Boolean) =
|
||||
CacheVersionManager(
|
||||
File(dataRoot, DATA_CONTAINER_VERSION_FILE_NAME),
|
||||
if (isEnabled) DATA_CONTAINER_VERSION else null
|
||||
)
|
||||
|
||||
fun readLookupsCacheStatus(dataRoot: File, isEnabled: Boolean): CacheStatus =
|
||||
lookupsCacheVersionManager(dataRoot, isEnabled).loadAndCheckStatus()
|
||||
@@ -34,16 +34,18 @@ class KotlinModuleXmlBuilder {
|
||||
}
|
||||
|
||||
fun addModule(
|
||||
moduleName: String,
|
||||
outputDir: String,
|
||||
sourceFiles: Iterable<File>,
|
||||
javaSourceRoots: Iterable<JvmSourceRoot>,
|
||||
classpathRoots: Iterable<File>,
|
||||
modularJdkRoot: File?,
|
||||
targetTypeId: String,
|
||||
isTests: Boolean,
|
||||
directoriesToFilterOut: Set<File>,
|
||||
friendDirs: Iterable<File>): KotlinModuleXmlBuilder {
|
||||
moduleName: String,
|
||||
outputDir: String,
|
||||
sourceFiles: Iterable<File>,
|
||||
javaSourceRoots: Iterable<JvmSourceRoot>,
|
||||
classpathRoots: Iterable<File>,
|
||||
commonSourceFiles: Iterable<File>,
|
||||
modularJdkRoot: File?,
|
||||
targetTypeId: String,
|
||||
isTests: Boolean,
|
||||
directoriesToFilterOut: Set<File>,
|
||||
friendDirs: Iterable<File>
|
||||
): KotlinModuleXmlBuilder {
|
||||
assert(!done) { "Already done" }
|
||||
|
||||
p.println("<!-- Module script for ${if (isTests) "tests" else "production"} -->")
|
||||
@@ -62,6 +64,10 @@ class KotlinModuleXmlBuilder {
|
||||
p.println("<", SOURCES, " ", PATH, "=\"", getEscapedPath(sourceFile), "\"/>")
|
||||
}
|
||||
|
||||
for (commonSourceFile in commonSourceFiles) {
|
||||
p.println("<", COMMON_SOURCES, " ", PATH, "=\"", getEscapedPath(commonSourceFile), "\"/>")
|
||||
}
|
||||
|
||||
processJavaSourceRoots(javaSourceRoots)
|
||||
processClasspath(classpathRoots, directoriesToFilterOut)
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import org.gradle.api.*
|
||||
import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.kotlin.dsl.*
|
||||
import org.gradle.language.jvm.tasks.ProcessResources
|
||||
|
||||
//import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
|
||||
inline fun Project.sourceSets(crossinline body: SourceSetsBuilder.() -> Unit) =
|
||||
@@ -25,18 +27,20 @@ fun SourceSet.none() {
|
||||
resources.setSrcDirs(emptyList<String>())
|
||||
}
|
||||
|
||||
fun SourceSet.projectDefault() {
|
||||
when (name) {
|
||||
"main" -> {
|
||||
java.srcDirs("src")
|
||||
resources.srcDir("resources").apply { include("**") }
|
||||
resources.srcDir("src").apply { include("META-INF/**", "**/*.properties") }
|
||||
}
|
||||
"test" -> {
|
||||
java.srcDirs("test", "tests")
|
||||
val SourceSet.projectDefault: Project.() -> Unit
|
||||
get() = {
|
||||
when (this@projectDefault.name) {
|
||||
"main" -> {
|
||||
java.srcDirs("src")
|
||||
val processResources = tasks.getByName(processResourcesTaskName) as ProcessResources
|
||||
processResources.from("resources") { include("**") }
|
||||
processResources.from("src") { include("META-INF/**", "**/*.properties") }
|
||||
}
|
||||
"test" -> {
|
||||
java.srcDirs("test", "tests")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: adding KotlinSourceSet dep to the plugin breaks the build unexpectedly, resolve and uncomment
|
||||
//val SourceSet.kotlin: SourceDirectorySet
|
||||
|
||||
@@ -201,7 +201,9 @@ public class ClassFileFactory implements OutputFileCollection {
|
||||
case "kotlin_module": {
|
||||
ModuleMapping mapping = ModuleMappingUtilKt.loadModuleMapping(
|
||||
ModuleMapping.Companion, file.asByteArray(), relativePath.getPath(),
|
||||
CompilerDeserializationConfiguration.Default.INSTANCE
|
||||
CompilerDeserializationConfiguration.Default.INSTANCE, version -> {
|
||||
throw new IllegalStateException("Version of the generated module cannot be incompatible: " + version);
|
||||
}
|
||||
);
|
||||
for (Map.Entry<String, PackageParts> entry : mapping.getPackageFqName2Parts().entrySet()) {
|
||||
FqName packageFqName = new FqName(entry.getKey());
|
||||
|
||||
@@ -38,7 +38,9 @@ private fun Iterable<PackageParts>.addCompiledParts(state: GenerationState): Lis
|
||||
val incrementalCache = state.incrementalCacheForThisTarget ?: return this.toList()
|
||||
val moduleMappingData = incrementalCache.getModuleMappingData() ?: return this.toList()
|
||||
|
||||
val mapping = ModuleMapping.loadModuleMapping(moduleMappingData, "<incremental>", state.deserializationConfiguration)
|
||||
val mapping = ModuleMapping.loadModuleMapping(moduleMappingData, "<incremental>", state.deserializationConfiguration) { version ->
|
||||
throw IllegalStateException("Version of the generated module cannot be incompatible: $version")
|
||||
}
|
||||
|
||||
incrementalCache.getObsoletePackageParts().forEach { internalName ->
|
||||
val qualifier = JvmClassName.byInternalName(internalName).packageFqName.asString()
|
||||
|
||||
@@ -180,6 +180,14 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
|
||||
)
|
||||
var metadataVersion: String? by FreezableVar(null)
|
||||
|
||||
@Argument(
|
||||
value = "-Xcommon-sources",
|
||||
valueDescription = "<path>",
|
||||
description = "Sources of the common module that need to be compiled together with this module in the multi-platform mode.\n" +
|
||||
"Should be a subset of sources passed as free arguments"
|
||||
)
|
||||
var commonSources: Array<String>? by FreezableVar(null)
|
||||
|
||||
open fun configureAnalysisFlags(collector: MessageCollector): MutableMap<AnalysisFlag<*>, Any> {
|
||||
return HashMap<AnalysisFlag<*>, Any>().apply {
|
||||
put(AnalysisFlag.skipMetadataVersionCheck, skipMetadataVersionCheck)
|
||||
|
||||
@@ -21,11 +21,12 @@ import org.jetbrains.kotlin.modules.Module
|
||||
import java.util.*
|
||||
|
||||
class ModuleBuilder(
|
||||
private val name: String,
|
||||
private val outputDir: String,
|
||||
private val type: String
|
||||
private val name: String,
|
||||
private val outputDir: String,
|
||||
private val type: String
|
||||
) : Module {
|
||||
private val sourceFiles = ArrayList<String>()
|
||||
private val commonSourceFiles = ArrayList<String>()
|
||||
private val classpathRoots = ArrayList<String>()
|
||||
private val javaSourceRoots = ArrayList<JavaRootPath>()
|
||||
private val friendDirs = ArrayList<String>()
|
||||
@@ -35,6 +36,10 @@ class ModuleBuilder(
|
||||
sourceFiles.add(path)
|
||||
}
|
||||
|
||||
fun addCommonSourceFiles(path: String) {
|
||||
commonSourceFiles.add(path)
|
||||
}
|
||||
|
||||
fun addClasspathEntry(path: String) {
|
||||
classpathRoots.add(path)
|
||||
}
|
||||
@@ -51,6 +56,7 @@ class ModuleBuilder(
|
||||
override fun getFriendPaths(): List<String> = friendDirs
|
||||
override fun getJavaSourceRoots(): List<JavaRootPath> = javaSourceRoots
|
||||
override fun getSourceFiles(): List<String> = sourceFiles
|
||||
override fun getCommonSourceFiles(): List<String> = commonSourceFiles
|
||||
override fun getClasspathRoots(): List<String> = classpathRoots
|
||||
override fun getModuleName(): String = name
|
||||
override fun getModuleType(): String = type
|
||||
|
||||
@@ -47,6 +47,7 @@ public class ModuleXmlParser {
|
||||
public static final String OUTPUT_DIR = "outputDir";
|
||||
public static final String FRIEND_DIR = "friendDir";
|
||||
public static final String SOURCES = "sources";
|
||||
public static final String COMMON_SOURCES = "commonSources";
|
||||
public static final String JAVA_SOURCE_ROOTS = "javaSourceRoots";
|
||||
public static final String JAVA_SOURCE_PACKAGE_PREFIX = "packagePrefix";
|
||||
public static final String PATH = "path";
|
||||
@@ -159,6 +160,10 @@ public class ModuleXmlParser {
|
||||
String path = getAttribute(attributes, PATH, qName);
|
||||
moduleBuilder.addSourceFiles(path);
|
||||
}
|
||||
else if (COMMON_SOURCES.equalsIgnoreCase(qName)) {
|
||||
String path = getAttribute(attributes, PATH, qName);
|
||||
moduleBuilder.addCommonSourceFiles(path);
|
||||
}
|
||||
else if (FRIEND_DIR.equalsIgnoreCase(qName)) {
|
||||
String path = getAttribute(attributes, PATH, qName);
|
||||
moduleBuilder.addFriendDir(path);
|
||||
|
||||
@@ -10,14 +10,18 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
|
||||
interface ContentRoot
|
||||
|
||||
data class KotlinSourceRoot(val path: String): ContentRoot
|
||||
/**
|
||||
* @param isCommon whether this source root contains sources of a common module in a multi-platform project
|
||||
*/
|
||||
data class KotlinSourceRoot(val path: String, val isCommon: Boolean): ContentRoot
|
||||
|
||||
fun CompilerConfiguration.addKotlinSourceRoot(source: String) {
|
||||
add(CLIConfigurationKeys.CONTENT_ROOTS, KotlinSourceRoot(source))
|
||||
@JvmOverloads
|
||||
fun CompilerConfiguration.addKotlinSourceRoot(path: String, isCommon: Boolean = false) {
|
||||
add(CLIConfigurationKeys.CONTENT_ROOTS, KotlinSourceRoot(path, isCommon))
|
||||
}
|
||||
|
||||
fun CompilerConfiguration.addKotlinSourceRoots(sources: List<String>): Unit =
|
||||
sources.forEach(this::addKotlinSourceRoot)
|
||||
sources.forEach { addKotlinSourceRoot(it) }
|
||||
|
||||
val CompilerConfiguration.kotlinSourceRoots: List<String>
|
||||
get() = get(CLIConfigurationKeys.CONTENT_ROOTS)?.filterIsInstance<KotlinSourceRoot>()?.map { it.path }.orEmpty()
|
||||
val CompilerConfiguration.kotlinSourceRoots: List<KotlinSourceRoot>
|
||||
get() = get(CLIConfigurationKeys.CONTENT_ROOTS)?.filterIsInstance<KotlinSourceRoot>().orEmpty()
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.intellij.util.ExceptionUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import kotlin.collections.ArraysKt;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import kotlin.collections.SetsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.analyzer.AnalysisResult;
|
||||
@@ -175,7 +176,12 @@ public class K2JSCompiler extends CLICompiler<K2JSCompilerArguments> {
|
||||
|
||||
configuration.put(JSConfigurationKeys.LIBRARIES, configureLibraries(arguments, paths, messageCollector));
|
||||
|
||||
ContentRootsKt.addKotlinSourceRoots(configuration, arguments.getFreeArgs());
|
||||
String[] commonSourcesArray = arguments.getCommonSources();
|
||||
Set<String> commonSources = commonSourcesArray == null ? Collections.emptySet() : SetsKt.setOf(commonSourcesArray);
|
||||
for (String arg : arguments.getFreeArgs()) {
|
||||
ContentRootsKt.addKotlinSourceRoot(configuration, arg, commonSources.contains(arg));
|
||||
}
|
||||
|
||||
KotlinCoreEnvironment environmentForJS =
|
||||
KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JS_CONFIG_FILES);
|
||||
|
||||
|
||||
@@ -77,13 +77,14 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
val pluginLoadResult = loadPlugins(arguments, configuration)
|
||||
if (pluginLoadResult != ExitCode.OK) return pluginLoadResult
|
||||
|
||||
val commonSources = arguments.commonSources?.toSet().orEmpty()
|
||||
if (!arguments.script && arguments.buildFile == null) {
|
||||
for (arg in arguments.freeArgs) {
|
||||
val file = File(arg)
|
||||
if (file.extension == JavaFileType.DEFAULT_EXTENSION) {
|
||||
configuration.addJavaSourceRoot(file)
|
||||
} else {
|
||||
configuration.addKotlinSourceRoot(arg)
|
||||
configuration.addKotlinSourceRoot(arg, isCommon = arg in commonSources)
|
||||
if (file.isDirectory) {
|
||||
configuration.addJavaSourceRoot(file)
|
||||
}
|
||||
|
||||
@@ -19,16 +19,23 @@ package org.jetbrains.kotlin.cli.jvm.compiler
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.LOGGING
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
|
||||
import org.jetbrains.kotlin.load.kotlin.loadModuleMapping
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.PackageParts
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.EOFException
|
||||
import java.io.PrintStream
|
||||
|
||||
class JvmPackagePartProvider(
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
@@ -77,7 +84,7 @@ class JvmPackagePartProvider(
|
||||
}.flatten()
|
||||
}
|
||||
|
||||
fun addRoots(roots: List<JavaRoot>) {
|
||||
fun addRoots(roots: List<JavaRoot>, messageCollector: MessageCollector) {
|
||||
for ((root, type) in roots) {
|
||||
if (type != JavaRoot.RootType.BINARY) continue
|
||||
if (root !in scope) continue
|
||||
@@ -86,12 +93,28 @@ class JvmPackagePartProvider(
|
||||
for (moduleFile in metaInf.children) {
|
||||
if (!moduleFile.name.endsWith(ModuleMapping.MAPPING_FILE_EXT)) continue
|
||||
|
||||
val mapping = try {
|
||||
ModuleMapping.loadModuleMapping(moduleFile.contentsToByteArray(), moduleFile.toString(), deserializationConfiguration)
|
||||
try {
|
||||
val mapping = ModuleMapping.loadModuleMapping(
|
||||
moduleFile.contentsToByteArray(), moduleFile.toString(), deserializationConfiguration
|
||||
) { incompatibleVersion ->
|
||||
messageCollector.report(
|
||||
ERROR,
|
||||
"Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is " +
|
||||
"$incompatibleVersion, expected version is ${JvmMetadataVersion.INSTANCE}.",
|
||||
CompilerMessageLocation.create(moduleFile.path)
|
||||
)
|
||||
}
|
||||
loadedModules.add(ModuleMappingInfo(root, mapping, moduleFile.nameWithoutExtension))
|
||||
} catch (e: EOFException) {
|
||||
throw RuntimeException("Error on reading package parts from $moduleFile in $root", e)
|
||||
messageCollector.report(
|
||||
ERROR, "Error occurred when reading the module: ${e.message}", CompilerMessageLocation.create(moduleFile.path)
|
||||
)
|
||||
messageCollector.report(
|
||||
LOGGING,
|
||||
String(ByteArrayOutputStream().also { e.printStackTrace(PrintStream(it)) }.toByteArray()),
|
||||
CompilerMessageLocation.create(moduleFile.path)
|
||||
)
|
||||
}
|
||||
loadedModules.add(ModuleMappingInfo(root, mapping, moduleFile.nameWithoutExtension))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.CliModuleVisibilityManagerImpl
|
||||
import org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY
|
||||
import org.jetbrains.kotlin.cli.common.config.ContentRoot
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
||||
@@ -110,6 +111,7 @@ import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtens
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.script.ScriptReportSink
|
||||
@@ -305,7 +307,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
fun createPackagePartProvider(scope: GlobalSearchScope): JvmPackagePartProvider {
|
||||
return JvmPackagePartProvider(configuration.languageVersionSettings, scope).apply {
|
||||
addRoots(initialRoots)
|
||||
addRoots(initialRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
|
||||
packagePartProviders += this
|
||||
(ModuleAnnotationsResolver.getInstance(project) as CliModuleAnnotationsResolver).addPackagePartProvider(this)
|
||||
}
|
||||
@@ -363,7 +365,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
val newRoots = classpathRootsResolver.convertClasspathRoots(contentRoots).roots
|
||||
|
||||
for (packagePartProvider in packagePartProviders) {
|
||||
packagePartProvider.addRoots(newRoots)
|
||||
packagePartProvider.addRoots(newRoots, configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY))
|
||||
}
|
||||
|
||||
return rootsIndex.addNewIndexForRoots(newRoots)?.let { newIndex ->
|
||||
@@ -400,16 +402,18 @@ class KotlinCoreEnvironment private constructor(
|
||||
private fun findJarRoot(file: File): VirtualFile? =
|
||||
applicationEnvironment.jarFileSystem.findFileByPath("$file${URLUtil.JAR_SEPARATOR}")
|
||||
|
||||
private fun getSourceRootsCheckingForDuplicates(): Collection<String> {
|
||||
val uniqueSourceRoots = linkedSetOf<String>()
|
||||
private fun getSourceRootsCheckingForDuplicates(): List<KotlinSourceRoot> {
|
||||
val uniqueSourceRoots = hashSetOf<String>()
|
||||
val result = mutableListOf<KotlinSourceRoot>()
|
||||
|
||||
configuration.kotlinSourceRoots.forEach { path ->
|
||||
if (!uniqueSourceRoots.add(path)) {
|
||||
report(STRONG_WARNING, "Duplicate source root: $path")
|
||||
for (root in configuration.kotlinSourceRoots) {
|
||||
if (!uniqueSourceRoots.add(root.path)) {
|
||||
report(STRONG_WARNING, "Duplicate source root: ${root.path}")
|
||||
}
|
||||
result.add(root)
|
||||
}
|
||||
|
||||
return uniqueSourceRoots
|
||||
return result
|
||||
}
|
||||
|
||||
fun getSourceFiles(): List<KtFile> = sourceFiles
|
||||
@@ -425,7 +429,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
val virtualFileCreator = PreprocessedFileCreator(project)
|
||||
|
||||
for (sourceRootPath in sourceRoots) {
|
||||
for ((sourceRootPath, isCommon) in sourceRoots) {
|
||||
val vFile = localFileSystem.findFileByPath(sourceRootPath)
|
||||
if (vFile == null) {
|
||||
val message = "Source file or directory not found: $sourceRootPath"
|
||||
@@ -452,6 +456,9 @@ class KotlinCoreEnvironment private constructor(
|
||||
val psiFile = psiManager.findFile(virtualFile)
|
||||
if (psiFile is KtFile) {
|
||||
result.add(psiFile)
|
||||
if (isCommon) {
|
||||
psiFile.isCommonSource = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ 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.config.addKotlinSourceRoots
|
||||
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
|
||||
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
|
||||
@@ -65,18 +65,6 @@ import java.lang.reflect.InvocationTargetException
|
||||
import java.net.URLClassLoader
|
||||
|
||||
object KotlinToJVMBytecodeCompiler {
|
||||
|
||||
private fun getAbsoluteFiles(buildFile: File, module: Module): List<File> {
|
||||
return module.getSourceFiles().map { sourceFile ->
|
||||
val source = File(sourceFile)
|
||||
if (!source.isAbsolute) {
|
||||
File(buildFile.absoluteFile.parentFile, sourceFile)
|
||||
} else {
|
||||
source
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeOutput(
|
||||
configuration: CompilerConfiguration,
|
||||
outputFiles: OutputFileCollection,
|
||||
@@ -142,7 +130,7 @@ object KotlinToJVMBytecodeCompiler {
|
||||
|
||||
for (module in chunk) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
val moduleSourceFiles = getAbsoluteFiles(buildFile, module).map { file -> localFileSystem.findFileByPath(file.path) }
|
||||
val moduleSourceFiles = getAbsolutePaths(buildFile, module.getSourceFiles()).map(localFileSystem::findFileByPath)
|
||||
val ktFiles = environment.getSourceFiles().filter { file -> file.virtualFile in moduleSourceFiles }
|
||||
|
||||
if (!checkKotlinPackageUsage(environment, ktFiles)) return false
|
||||
@@ -184,7 +172,11 @@ object KotlinToJVMBytecodeCompiler {
|
||||
|
||||
internal fun configureSourceRoots(configuration: CompilerConfiguration, chunk: List<Module>, buildFile: File) {
|
||||
for (module in chunk) {
|
||||
configuration.addKotlinSourceRoots(getAbsoluteFiles(buildFile, module).map(File::getPath))
|
||||
val commonSources = getAbsolutePaths(buildFile, module.getCommonSourceFiles()).toSet()
|
||||
|
||||
for (path in getAbsolutePaths(buildFile, module.getSourceFiles())) {
|
||||
configuration.addKotlinSourceRoot(path, isCommon = path in commonSources)
|
||||
}
|
||||
}
|
||||
|
||||
for (module in chunk) {
|
||||
@@ -224,6 +216,11 @@ object KotlinToJVMBytecodeCompiler {
|
||||
configuration.addAll(JVMConfigurationKeys.MODULES, chunk)
|
||||
}
|
||||
|
||||
private fun getAbsolutePaths(buildFile: File, sourceFilePaths: List<String>): List<String> =
|
||||
sourceFilePaths.map { path ->
|
||||
(File(path).takeIf(File::isAbsolute) ?: buildFile.resolveSibling(path)).absolutePath
|
||||
}
|
||||
|
||||
private fun findMainClass(generationState: GenerationState, files: List<KtFile>): FqName? {
|
||||
val mainFunctionDetector = MainFunctionDetector(generationState.bindingContext)
|
||||
return files.asSequence()
|
||||
|
||||
@@ -60,7 +60,7 @@ class K2MetadataCompiler : CLICompiler<K2MetadataCompilerArguments>() {
|
||||
if (pluginLoadResult != ExitCode.OK) return pluginLoadResult
|
||||
|
||||
for (arg in arguments.freeArgs) {
|
||||
configuration.addKotlinSourceRoot(arg)
|
||||
configuration.addKotlinSourceRoot(arg, isCommon = true)
|
||||
}
|
||||
if (arguments.classpath != null) {
|
||||
configuration.addJvmClasspathRoots(arguments.classpath!!.split(File.pathSeparatorChar).map(::File))
|
||||
|
||||
@@ -23,7 +23,9 @@ class IncrementalModuleInfo(
|
||||
val projectRoot: File,
|
||||
val dirToModule: Map<File, IncrementalModuleEntry>,
|
||||
val nameToModules: Map<String, Set<IncrementalModuleEntry>>,
|
||||
val jarToClassListFile: Map<File, File>
|
||||
val jarToClassListFile: Map<File, File>,
|
||||
// only for js
|
||||
val jarToModule: Map<File, IncrementalModuleEntry>
|
||||
) : Serializable {
|
||||
companion object {
|
||||
private const val serialVersionUID = 0L
|
||||
|
||||
@@ -38,7 +38,6 @@ import org.jetbrains.kotlin.cli.js.K2JSCompiler
|
||||
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.cli.metadata.K2MetadataCompiler
|
||||
import org.jetbrains.kotlin.config.IncrementalCompilation
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.daemon.common.*
|
||||
import org.jetbrains.kotlin.daemon.report.CompileServicesFacadeMessageCollector
|
||||
@@ -50,9 +49,10 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider
|
||||
import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer
|
||||
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
|
||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryAndroid
|
||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJs
|
||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJvm
|
||||
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||
import org.jetbrains.kotlin.modules.Module
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||
@@ -83,7 +83,7 @@ interface CompilerSelector {
|
||||
}
|
||||
|
||||
interface EventManager {
|
||||
fun onCompilationFinished(f : () -> Unit)
|
||||
fun onCompilationFinished(f: () -> Unit)
|
||||
}
|
||||
|
||||
private class EventManagerImpl : EventManager {
|
||||
@@ -99,14 +99,14 @@ private class EventManagerImpl : EventManager {
|
||||
}
|
||||
|
||||
class CompileServiceImpl(
|
||||
val registry: Registry,
|
||||
val compiler: CompilerSelector,
|
||||
val compilerId: CompilerId,
|
||||
val daemonOptions: DaemonOptions,
|
||||
val daemonJVMOptions: DaemonJVMOptions,
|
||||
val port: Int,
|
||||
val timer: Timer,
|
||||
val onShutdown: () -> Unit
|
||||
val registry: Registry,
|
||||
val compiler: CompilerSelector,
|
||||
val compilerId: CompilerId,
|
||||
val daemonOptions: DaemonOptions,
|
||||
val daemonJVMOptions: DaemonJVMOptions,
|
||||
val port: Int,
|
||||
val timer: Timer,
|
||||
val onShutdown: () -> Unit
|
||||
) : CompileService {
|
||||
|
||||
private val log by lazy { Logger.getLogger("compiler") }
|
||||
@@ -116,8 +116,14 @@ class CompileServiceImpl(
|
||||
}
|
||||
|
||||
// wrapped in a class to encapsulate alive check logic
|
||||
private class ClientOrSessionProxy<out T: Any>(val aliveFlagPath: String?, val data: T? = null, private var disposable: Disposable? = null) {
|
||||
val isAlive: Boolean get() = aliveFlagPath?.let { File(it).exists() } ?: true // assuming that if no file was given, the client is alive
|
||||
private class ClientOrSessionProxy<out T : Any>(
|
||||
val aliveFlagPath: String?,
|
||||
val data: T? = null,
|
||||
private var disposable: Disposable? = null
|
||||
) {
|
||||
val isAlive: Boolean
|
||||
get() = aliveFlagPath?.let { File(it).exists() } ?: true // assuming that if no file was given, the client is alive
|
||||
|
||||
fun dispose() {
|
||||
disposable?.let {
|
||||
Disposer.dispose(it)
|
||||
@@ -132,7 +138,8 @@ class CompileServiceImpl(
|
||||
|
||||
enum class Aliveness {
|
||||
// !!! ordering of values is used in state comparison
|
||||
Dying, LastSession, Alive
|
||||
Dying,
|
||||
LastSession, Alive
|
||||
}
|
||||
|
||||
private class SessionsContainer {
|
||||
@@ -143,7 +150,7 @@ class CompileServiceImpl(
|
||||
|
||||
val lastSessionId get() = sessionsIdCounter.get()
|
||||
|
||||
fun<T: Any> leaseSession(session: ClientOrSessionProxy<T>): Int = lock.write {
|
||||
fun <T : Any> leaseSession(session: ClientOrSessionProxy<T>): Int = lock.write {
|
||||
val newId = getValidId(sessionsIdCounter) {
|
||||
it != CompileService.NO_SESSION && !sessions.containsKey(it)
|
||||
}
|
||||
@@ -203,18 +210,22 @@ class CompileServiceImpl(
|
||||
clientProxies.mapNotNull { it.aliveFlagPath }
|
||||
}
|
||||
|
||||
fun cleanDeadClients(): Boolean = clientProxies.cleanMatching(clientsLock, { !it.isAlive }, { if (clientProxies.remove(it)) it.dispose() })
|
||||
fun cleanDeadClients(): Boolean =
|
||||
clientProxies.cleanMatching(clientsLock, { !it.isAlive }, { if (clientProxies.remove(it)) it.dispose() })
|
||||
}
|
||||
|
||||
private fun Int.toAlivenessName(): String =
|
||||
try {
|
||||
Aliveness.values()[this].name
|
||||
}
|
||||
catch (_: Throwable) {
|
||||
"invalid($this)"
|
||||
}
|
||||
try {
|
||||
Aliveness.values()[this].name
|
||||
} catch (_: Throwable) {
|
||||
"invalid($this)"
|
||||
}
|
||||
|
||||
private inline fun<T> Iterable<T>.cleanMatching(lock: ReentrantReadWriteLock, crossinline pred: (T) -> Boolean, crossinline clean: (T) -> Unit): Boolean {
|
||||
private inline fun <T> Iterable<T>.cleanMatching(
|
||||
lock: ReentrantReadWriteLock,
|
||||
crossinline pred: (T) -> Boolean,
|
||||
crossinline clean: (T) -> Unit
|
||||
): Boolean {
|
||||
var anyDead = false
|
||||
lock.read {
|
||||
val toRemove = filter(pred)
|
||||
@@ -228,7 +239,8 @@ class CompileServiceImpl(
|
||||
return anyDead
|
||||
}
|
||||
|
||||
@Volatile private var _lastUsedSeconds = nowSeconds()
|
||||
@Volatile
|
||||
private var _lastUsedSeconds = nowSeconds()
|
||||
val lastUsedSeconds: Long get() = if (rwlock.isWriteLocked || rwlock.readLockCount - rwlock.readHoldCount > 0) nowSeconds() else _lastUsedSeconds
|
||||
|
||||
private val rwlock = ReentrantReadWriteLock()
|
||||
@@ -238,10 +250,14 @@ class CompileServiceImpl(
|
||||
init {
|
||||
val runFileDir = File(daemonOptions.runFilesPathOrDefault)
|
||||
runFileDir.mkdirs()
|
||||
runFile = File(runFileDir,
|
||||
makeRunFilenameString(timestamp = "%tFT%<tH-%<tM-%<tS.%<tLZ".format(Calendar.getInstance(TimeZone.getTimeZone("Z"))),
|
||||
digest = compilerId.compilerClasspath.map { File(it).absolutePath }.distinctStringsDigest().toHexString(),
|
||||
port = port.toString()))
|
||||
runFile = File(
|
||||
runFileDir,
|
||||
makeRunFilenameString(
|
||||
timestamp = "%tFT%<tH-%<tM-%<tS.%<tLZ".format(Calendar.getInstance(TimeZone.getTimeZone("Z"))),
|
||||
digest = compilerId.compilerClasspath.map { File(it).absolutePath }.distinctStringsDigest().toHexString(),
|
||||
port = port.toString()
|
||||
)
|
||||
)
|
||||
try {
|
||||
if (!runFile.createNewFile()) throw Exception("createNewFile returned false")
|
||||
} catch (e: Throwable) {
|
||||
@@ -279,9 +295,9 @@ class CompileServiceImpl(
|
||||
// TODO: consider tying a session to a client and use this info to cleanup
|
||||
override fun leaseCompileSession(aliveFlagPath: String?): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
|
||||
CompileService.CallResult.Good(
|
||||
state.sessions.leaseSession(ClientOrSessionProxy<Any>(aliveFlagPath)).apply {
|
||||
log.info("leased a new session $this, session alive file: $aliveFlagPath")
|
||||
})
|
||||
state.sessions.leaseSession(ClientOrSessionProxy<Any>(aliveFlagPath)).apply {
|
||||
log.info("leased a new session $this, session alive file: $aliveFlagPath")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -301,12 +317,12 @@ class CompileServiceImpl(
|
||||
}
|
||||
|
||||
override fun checkCompilerId(expectedCompilerId: CompilerId): Boolean =
|
||||
(compilerId.compilerVersion.isEmpty() || compilerId.compilerVersion == expectedCompilerId.compilerVersion) &&
|
||||
(compilerId.compilerClasspath.all { expectedCompilerId.compilerClasspath.contains(it) }) &&
|
||||
!classpathWatcher.isChanged
|
||||
(compilerId.compilerVersion.isEmpty() || compilerId.compilerVersion == expectedCompilerId.compilerVersion) &&
|
||||
(compilerId.compilerClasspath.all { expectedCompilerId.compilerClasspath.contains(it) }) &&
|
||||
!classpathWatcher.isChanged
|
||||
|
||||
override fun getUsedMemory(): CompileService.CallResult<Long> =
|
||||
ifAlive { CompileService.CallResult.Good(usedMemory(withGC = true)) }
|
||||
ifAlive { CompileService.CallResult.Good(usedMemory(withGC = true)) }
|
||||
|
||||
override fun shutdown(): CompileService.CallResult<Nothing> = ifAliveExclusive(minAliveness = Aliveness.LastSession) {
|
||||
shutdownWithDelay()
|
||||
@@ -324,37 +340,55 @@ class CompileServiceImpl(
|
||||
CompileService.CallResult.Good(res)
|
||||
}
|
||||
|
||||
override fun remoteCompile(sessionId: Int,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
args: Array<out String>,
|
||||
servicesFacade: CompilerCallbackServicesFacade,
|
||||
compilerOutputStream: RemoteOutputStream,
|
||||
outputFormat: CompileService.OutputFormat,
|
||||
serviceOutputStream: RemoteOutputStream,
|
||||
operationsTracer: RemoteOperationsTracer?
|
||||
override fun remoteCompile(
|
||||
sessionId: Int,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
args: Array<out String>,
|
||||
servicesFacade: CompilerCallbackServicesFacade,
|
||||
compilerOutputStream: RemoteOutputStream,
|
||||
outputFormat: CompileService.OutputFormat,
|
||||
serviceOutputStream: RemoteOutputStream,
|
||||
operationsTracer: RemoteOperationsTracer?
|
||||
): CompileService.CallResult<Int> =
|
||||
doCompile(sessionId, args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, eventManager, profiler ->
|
||||
when (outputFormat) {
|
||||
CompileService.OutputFormat.PLAIN -> compiler[targetPlatform].exec(printStream, *args)
|
||||
CompileService.OutputFormat.XML -> compiler[targetPlatform].execAndOutputXml(printStream, createCompileServices(servicesFacade, eventManager, profiler), *args)
|
||||
}
|
||||
doCompile(sessionId, args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, eventManager, profiler ->
|
||||
when (outputFormat) {
|
||||
CompileService.OutputFormat.PLAIN -> compiler[targetPlatform].exec(printStream, *args)
|
||||
CompileService.OutputFormat.XML -> compiler[targetPlatform].execAndOutputXml(
|
||||
printStream,
|
||||
createCompileServices(
|
||||
servicesFacade,
|
||||
eventManager,
|
||||
profiler
|
||||
),
|
||||
*args
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun remoteIncrementalCompile(sessionId: Int,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
args: Array<out String>,
|
||||
servicesFacade: CompilerCallbackServicesFacade,
|
||||
compilerOutputStream: RemoteOutputStream,
|
||||
compilerOutputFormat: CompileService.OutputFormat,
|
||||
serviceOutputStream: RemoteOutputStream,
|
||||
operationsTracer: RemoteOperationsTracer?
|
||||
override fun remoteIncrementalCompile(
|
||||
sessionId: Int,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
args: Array<out String>,
|
||||
servicesFacade: CompilerCallbackServicesFacade,
|
||||
compilerOutputStream: RemoteOutputStream,
|
||||
compilerOutputFormat: CompileService.OutputFormat,
|
||||
serviceOutputStream: RemoteOutputStream,
|
||||
operationsTracer: RemoteOperationsTracer?
|
||||
): CompileService.CallResult<Int> =
|
||||
doCompile(sessionId, args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, eventManager, profiler ->
|
||||
when (compilerOutputFormat) {
|
||||
CompileService.OutputFormat.PLAIN -> throw NotImplementedError("Only XML output is supported in remote incremental compilation")
|
||||
CompileService.OutputFormat.XML -> compiler[targetPlatform].execAndOutputXml(printStream, createCompileServices(servicesFacade, eventManager, profiler), *args)
|
||||
}
|
||||
doCompile(sessionId, args, compilerOutputStream, serviceOutputStream, operationsTracer) { printStream, eventManager, profiler ->
|
||||
when (compilerOutputFormat) {
|
||||
CompileService.OutputFormat.PLAIN -> throw NotImplementedError("Only XML output is supported in remote incremental compilation")
|
||||
CompileService.OutputFormat.XML -> compiler[targetPlatform].execAndOutputXml(
|
||||
printStream,
|
||||
createCompileServices(
|
||||
servicesFacade,
|
||||
eventManager,
|
||||
profiler
|
||||
),
|
||||
*args
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun classesFqNamesByFiles(
|
||||
sessionId: Int, sourceFiles: Set<File>
|
||||
@@ -366,11 +400,11 @@ class CompileServiceImpl(
|
||||
}
|
||||
|
||||
override fun compile(
|
||||
sessionId: Int,
|
||||
compilerArguments: Array<out String>,
|
||||
compilationOptions: CompilationOptions,
|
||||
servicesFacade: CompilerServicesFacadeBase,
|
||||
compilationResults: CompilationResults?
|
||||
sessionId: Int,
|
||||
compilerArguments: Array<out String>,
|
||||
compilationOptions: CompilationOptions,
|
||||
servicesFacade: CompilerServicesFacadeBase,
|
||||
compilationResults: CompilationResults?
|
||||
): CompileService.CallResult<Int> = ifAlive {
|
||||
withValidClientOrSessionProxy(sessionId) {
|
||||
val messageCollector = CompileServicesFacadeMessageCollector(servicesFacade, compilationOptions)
|
||||
@@ -391,8 +425,7 @@ class CompileServiceImpl(
|
||||
if (argumentParseError != null) {
|
||||
messageCollector.report(CompilerMessageSeverity.ERROR, argumentParseError)
|
||||
CompileService.CallResult.Good(ExitCode.COMPILATION_ERROR.code)
|
||||
}
|
||||
else when (compilationOptions.compilerMode) {
|
||||
} else when (compilationOptions.compilerMode) {
|
||||
CompilerMode.JPS_COMPILER -> {
|
||||
val jpsServicesFacade = servicesFacade as JpsCompilerServicesFacade
|
||||
|
||||
@@ -418,8 +451,10 @@ class CompileServiceImpl(
|
||||
|
||||
withIC {
|
||||
doCompile(sessionId, daemonReporter, tracer = null) { _, _ ->
|
||||
execIncrementalCompiler(k2jvmArgs, gradleIncrementalArgs, gradleIncrementalServicesFacade, compilationResults!!,
|
||||
messageCollector, daemonReporter)
|
||||
execIncrementalCompiler(
|
||||
k2jvmArgs, gradleIncrementalArgs, gradleIncrementalServicesFacade, compilationResults!!,
|
||||
messageCollector, daemonReporter
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -428,7 +463,13 @@ class CompileServiceImpl(
|
||||
|
||||
withJsIC {
|
||||
doCompile(sessionId, daemonReporter, tracer = null) { _, _ ->
|
||||
execJsIncrementalCompiler(k2jsArgs, gradleIncrementalArgs, gradleIncrementalServicesFacade, compilationResults!!, messageCollector)
|
||||
execJsIncrementalCompiler(
|
||||
k2jsArgs,
|
||||
gradleIncrementalArgs,
|
||||
gradleIncrementalServicesFacade,
|
||||
compilationResults!!,
|
||||
messageCollector
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -451,10 +492,9 @@ class CompileServiceImpl(
|
||||
val allKotlinFiles = arrayListOf<File>()
|
||||
val freeArgsWithoutKotlinFiles = arrayListOf<String>()
|
||||
args.freeArgs.forEach {
|
||||
if (it.endsWith(".kt") && File(it).exists()) {
|
||||
if (it.endsWith(".kt") && File(it).exists()) {
|
||||
allKotlinFiles.add(File(it))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
freeArgsWithoutKotlinFiles.add(it)
|
||||
}
|
||||
}
|
||||
@@ -464,29 +504,36 @@ class CompileServiceImpl(
|
||||
|
||||
val changedFiles = if (incrementalCompilationOptions.areFileChangesKnown) {
|
||||
ChangedFiles.Known(incrementalCompilationOptions.modifiedFiles!!, incrementalCompilationOptions.deletedFiles!!)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ChangedFiles.Unknown()
|
||||
}
|
||||
|
||||
val workingDir = incrementalCompilationOptions.workingDir
|
||||
val versions = commonCacheVersions(workingDir, enabled = true) +
|
||||
customCacheVersion(incrementalCompilationOptions.customCacheVersion,
|
||||
incrementalCompilationOptions.customCacheVersionFileName,
|
||||
workingDir,
|
||||
enabled = true)
|
||||
|
||||
val compiler = IncrementalJsCompilerRunner(workingDir, versions, reporter)
|
||||
val versionManagers = commonCacheVersionsManagers(workingDir, enabled = true) +
|
||||
customCacheVersionManager(
|
||||
incrementalCompilationOptions.customCacheVersion,
|
||||
incrementalCompilationOptions.customCacheVersionFileName,
|
||||
workingDir,
|
||||
enabled = true
|
||||
)
|
||||
val modulesApiHistory = ModulesApiHistoryJs(incrementalCompilationOptions.modulesInfo)
|
||||
val compiler = IncrementalJsCompilerRunner(
|
||||
workingDir = workingDir,
|
||||
cachesVersionManagers = versionManagers,
|
||||
reporter = reporter,
|
||||
buildHistoryFile = incrementalCompilationOptions.multiModuleICSettings.buildHistoryFile,
|
||||
modulesApiHistory = modulesApiHistory
|
||||
)
|
||||
return compiler.compile(allKotlinFiles, args, compilerMessageCollector, changedFiles)
|
||||
}
|
||||
|
||||
private fun execIncrementalCompiler(
|
||||
k2jvmArgs: K2JVMCompilerArguments,
|
||||
incrementalCompilationOptions: IncrementalCompilationOptions,
|
||||
servicesFacade: IncrementalCompilerServicesFacade,
|
||||
compilationResults: CompilationResults,
|
||||
compilerMessageCollector: MessageCollector,
|
||||
daemonMessageReporter: DaemonMessageReporter
|
||||
k2jvmArgs: K2JVMCompilerArguments,
|
||||
incrementalCompilationOptions: IncrementalCompilationOptions,
|
||||
servicesFacade: IncrementalCompilerServicesFacade,
|
||||
compilationResults: CompilationResults,
|
||||
compilerMessageCollector: MessageCollector,
|
||||
daemonMessageReporter: DaemonMessageReporter
|
||||
): ExitCode {
|
||||
val reporter = RemoteICReporter(servicesFacade, compilationResults, incrementalCompilationOptions)
|
||||
|
||||
@@ -509,22 +556,25 @@ class CompileServiceImpl(
|
||||
it.getJavaSourceRoots().map { JvmSourceRoot(File(it.path), it.packagePrefix) }
|
||||
}
|
||||
|
||||
k2jvmArgs.commonSources = parsedModule.modules.flatMap { it.getCommonSourceFiles() }.toTypedArray().takeUnless { it.isEmpty() }
|
||||
|
||||
val allKotlinFiles = parsedModule.modules.flatMap { it.getSourceFiles().map(::File) }
|
||||
k2jvmArgs.friendPaths = parsedModule.modules.flatMap(Module::getFriendPaths).toTypedArray()
|
||||
|
||||
val changedFiles = if (incrementalCompilationOptions.areFileChangesKnown) {
|
||||
ChangedFiles.Known(incrementalCompilationOptions.modifiedFiles!!, incrementalCompilationOptions.deletedFiles!!)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
ChangedFiles.Unknown()
|
||||
}
|
||||
|
||||
val workingDir = incrementalCompilationOptions.workingDir
|
||||
val versions = commonCacheVersions(workingDir, enabled = true) +
|
||||
customCacheVersion(incrementalCompilationOptions.customCacheVersion,
|
||||
incrementalCompilationOptions.customCacheVersionFileName,
|
||||
workingDir,
|
||||
enabled = true)
|
||||
val versions = commonCacheVersionsManagers(workingDir, enabled = true) +
|
||||
customCacheVersionManager(
|
||||
incrementalCompilationOptions.customCacheVersion,
|
||||
incrementalCompilationOptions.customCacheVersionFileName,
|
||||
workingDir,
|
||||
enabled = true
|
||||
)
|
||||
|
||||
val modulesApiHistory = incrementalCompilationOptions.run {
|
||||
if (!multiModuleICSettings.useModuleDetection) {
|
||||
@@ -548,27 +598,34 @@ class CompileServiceImpl(
|
||||
}
|
||||
|
||||
override fun leaseReplSession(
|
||||
aliveFlagPath: String?,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
servicesFacade: CompilerCallbackServicesFacade,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String,
|
||||
scriptArgs: Array<out Any?>?,
|
||||
scriptArgsTypes: Array<out Class<out Any>>?,
|
||||
compilerMessagesOutputStream: RemoteOutputStream,
|
||||
evalOutputStream: RemoteOutputStream?,
|
||||
evalErrorStream: RemoteOutputStream?,
|
||||
evalInputStream: RemoteInputStream?,
|
||||
operationsTracer: RemoteOperationsTracer?
|
||||
aliveFlagPath: String?,
|
||||
targetPlatform: CompileService.TargetPlatform,
|
||||
servicesFacade: CompilerCallbackServicesFacade,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String,
|
||||
scriptArgs: Array<out Any?>?,
|
||||
scriptArgsTypes: Array<out Class<out Any>>?,
|
||||
compilerMessagesOutputStream: RemoteOutputStream,
|
||||
evalOutputStream: RemoteOutputStream?,
|
||||
evalErrorStream: RemoteOutputStream?,
|
||||
evalInputStream: RemoteInputStream?,
|
||||
operationsTracer: RemoteOperationsTracer?
|
||||
): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
|
||||
if (targetPlatform != CompileService.TargetPlatform.JVM)
|
||||
CompileService.CallResult.Error("Sorry, only JVM target platform is supported now")
|
||||
else {
|
||||
val disposable = Disposer.newDisposable()
|
||||
val compilerMessagesStream = PrintStream(BufferedOutputStream(RemoteOutputStreamClient(compilerMessagesOutputStream, DummyProfiler()), REMOTE_STREAM_BUFFER_SIZE))
|
||||
val compilerMessagesStream = PrintStream(
|
||||
BufferedOutputStream(
|
||||
RemoteOutputStreamClient(compilerMessagesOutputStream, DummyProfiler()),
|
||||
REMOTE_STREAM_BUFFER_SIZE
|
||||
)
|
||||
)
|
||||
val messageCollector = KeepFirstErrorMessageCollector(compilerMessagesStream)
|
||||
val repl = KotlinJvmReplService(disposable, port, templateClasspath, templateClassName,
|
||||
messageCollector, operationsTracer)
|
||||
val repl = KotlinJvmReplService(
|
||||
disposable, port, templateClasspath, templateClassName,
|
||||
messageCollector, operationsTracer
|
||||
)
|
||||
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
|
||||
|
||||
CompileService.CallResult.Good(sessionId)
|
||||
@@ -579,42 +636,49 @@ class CompileServiceImpl(
|
||||
override fun releaseReplSession(sessionId: Int): CompileService.CallResult<Nothing> = releaseCompileSession(sessionId)
|
||||
|
||||
override fun remoteReplLineCheck(sessionId: Int, codeLine: ReplCodeLine): CompileService.CallResult<ReplCheckResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
CompileService.CallResult.Good(check(codeLine))
|
||||
}
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
CompileService.CallResult.Good(check(codeLine))
|
||||
}
|
||||
}
|
||||
|
||||
override fun remoteReplLineCompile(sessionId: Int, codeLine: ReplCodeLine, history: List<ReplCodeLine>?): CompileService.CallResult<ReplCompileResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
CompileService.CallResult.Good(compile(codeLine, history))
|
||||
}
|
||||
override fun remoteReplLineCompile(
|
||||
sessionId: Int,
|
||||
codeLine: ReplCodeLine,
|
||||
history: List<ReplCodeLine>?
|
||||
): CompileService.CallResult<ReplCompileResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
CompileService.CallResult.Good(compile(codeLine, history))
|
||||
}
|
||||
}
|
||||
|
||||
override fun remoteReplLineEval(
|
||||
sessionId: Int,
|
||||
codeLine: ReplCodeLine,
|
||||
history: List<ReplCodeLine>?
|
||||
sessionId: Int,
|
||||
codeLine: ReplCodeLine,
|
||||
history: List<ReplCodeLine>?
|
||||
): CompileService.CallResult<ReplEvalResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
CompileService.CallResult.Error("Eval on daemon is not supported")
|
||||
}
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
CompileService.CallResult.Error("Eval on daemon is not supported")
|
||||
}
|
||||
|
||||
override fun leaseReplSession(aliveFlagPath: String?,
|
||||
compilerArguments: Array<out String>,
|
||||
compilationOptions: CompilationOptions,
|
||||
servicesFacade: CompilerServicesFacadeBase,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String
|
||||
): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
|
||||
override fun leaseReplSession(
|
||||
aliveFlagPath: String?,
|
||||
compilerArguments: Array<out String>,
|
||||
compilationOptions: CompilationOptions,
|
||||
servicesFacade: CompilerServicesFacadeBase,
|
||||
templateClasspath: List<File>,
|
||||
templateClassName: String
|
||||
): CompileService.CallResult<Int> = ifAlive(minAliveness = Aliveness.Alive) {
|
||||
if (compilationOptions.targetPlatform != CompileService.TargetPlatform.JVM)
|
||||
CompileService.CallResult.Error("Sorry, only JVM target platform is supported now")
|
||||
else {
|
||||
val disposable = Disposer.newDisposable()
|
||||
val messageCollector = CompileServicesFacadeMessageCollector(servicesFacade, compilationOptions)
|
||||
val repl = KotlinJvmReplService(disposable, port, templateClasspath, templateClassName,
|
||||
messageCollector, null)
|
||||
val repl = KotlinJvmReplService(
|
||||
disposable, port, templateClasspath, templateClassName,
|
||||
messageCollector, null
|
||||
)
|
||||
val sessionId = state.sessions.leaseSession(ClientOrSessionProxy(aliveFlagPath, repl, disposable))
|
||||
|
||||
CompileService.CallResult.Good(sessionId)
|
||||
@@ -622,29 +686,29 @@ class CompileServiceImpl(
|
||||
}
|
||||
|
||||
override fun replCreateState(sessionId: Int): CompileService.CallResult<ReplStateFacade> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
CompileService.CallResult.Good(createRemoteState(port))
|
||||
}
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
CompileService.CallResult.Good(createRemoteState(port))
|
||||
}
|
||||
}
|
||||
|
||||
override fun replCheck(sessionId: Int, replStateId: Int, codeLine: ReplCodeLine): CompileService.CallResult<ReplCheckResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
withValidReplState(replStateId) { state ->
|
||||
check(state, codeLine)
|
||||
}
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
withValidReplState(replStateId) { state ->
|
||||
check(state, codeLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun replCompile(sessionId: Int, replStateId: Int, codeLine: ReplCodeLine): CompileService.CallResult<ReplCompileResult> =
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
withValidReplState(replStateId) { state ->
|
||||
compile(state, codeLine)
|
||||
}
|
||||
ifAlive(minAliveness = Aliveness.Alive) {
|
||||
withValidRepl(sessionId) {
|
||||
withValidReplState(replStateId) { state ->
|
||||
compile(state, codeLine)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// internal implementation stuff
|
||||
@@ -667,13 +731,17 @@ class CompileServiceImpl(
|
||||
try {
|
||||
// cleanup for the case of incorrect restart and many other situations
|
||||
UnicastRemoteObject.unexportObject(this, false)
|
||||
}
|
||||
catch (e: NoSuchObjectException) {
|
||||
} catch (e: NoSuchObjectException) {
|
||||
// ignoring if object already exported
|
||||
}
|
||||
|
||||
val stub = UnicastRemoteObject.exportObject(this, port, LoopbackNetworkInterface.clientLoopbackSocketFactory, LoopbackNetworkInterface.serverLoopbackSocketFactory) as CompileService
|
||||
registry.rebind (COMPILER_SERVICE_RMI_NAME, stub)
|
||||
val stub = UnicastRemoteObject.exportObject(
|
||||
this,
|
||||
port,
|
||||
LoopbackNetworkInterface.clientLoopbackSocketFactory,
|
||||
LoopbackNetworkInterface.serverLoopbackSocketFactory
|
||||
) as CompileService
|
||||
registry.rebind(COMPILER_SERVICE_RMI_NAME, stub)
|
||||
|
||||
timer.schedule(10) {
|
||||
exceptionLoggingTimerThread { initiateElections() }
|
||||
@@ -689,8 +757,7 @@ class CompileServiceImpl(
|
||||
private inline fun exceptionLoggingTimerThread(body: () -> Unit) {
|
||||
try {
|
||||
body()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
} catch (e: Throwable) {
|
||||
System.err.println("Exception in timer thread: " + e.message)
|
||||
e.printStackTrace(System.err)
|
||||
log.log(Level.SEVERE, "Exception in timer thread", e)
|
||||
@@ -760,12 +827,22 @@ class CompileServiceImpl(
|
||||
ifAliveUnit {
|
||||
|
||||
log.info("initiate elections")
|
||||
val aliveWithOpts = walkDaemons(File(daemonOptions.runFilesPathOrDefault), compilerId, runFile, filter = { _, p -> p != port }, report = { _, msg -> log.info(msg) }).toList()
|
||||
val comparator = compareByDescending<DaemonWithMetadata, DaemonJVMOptions>(DaemonJVMOptionsMemoryComparator(), { it.jvmOptions })
|
||||
val aliveWithOpts = walkDaemons(
|
||||
File(daemonOptions.runFilesPathOrDefault),
|
||||
compilerId,
|
||||
runFile,
|
||||
filter = { _, p -> p != port },
|
||||
report = { _, msg -> log.info(msg) }).toList()
|
||||
val comparator =
|
||||
compareByDescending<DaemonWithMetadata, DaemonJVMOptions>(DaemonJVMOptionsMemoryComparator(), { it.jvmOptions })
|
||||
.thenBy(FileAgeComparator()) { it.runFile }
|
||||
aliveWithOpts.maxWith(comparator)?.let { bestDaemonWithMetadata ->
|
||||
val fattestOpts = bestDaemonWithMetadata.jvmOptions
|
||||
if (fattestOpts memorywiseFitsInto daemonJVMOptions && FileAgeComparator().compare(bestDaemonWithMetadata.runFile, runFile) < 0 ) {
|
||||
if (fattestOpts memorywiseFitsInto daemonJVMOptions && FileAgeComparator().compare(
|
||||
bestDaemonWithMetadata.runFile,
|
||||
runFile
|
||||
) < 0
|
||||
) {
|
||||
// all others are smaller that me, take overs' clients and shut them down
|
||||
log.info("$LOG_PREFIX_ASSUMING_OTHER_DAEMONS_HAVE lower prio, taking clients from them and schedule them to shutdown: my runfile: ${runFile.name} (${runFile.lastModified()}) vs best other runfile: ${bestDaemonWithMetadata.runFile.name} (${bestDaemonWithMetadata.runFile.lastModified()})")
|
||||
aliveWithOpts.forEach { (daemon, runFile, _) ->
|
||||
@@ -774,8 +851,7 @@ class CompileServiceImpl(
|
||||
it.get().forEach { clientAliveFile -> registerClient(clientAliveFile) }
|
||||
}
|
||||
daemon.scheduleShutdown(true)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
} catch (e: Throwable) {
|
||||
log.info("Cannot connect to a daemon, assuming dying ('${runFile.canonicalPath}'): ${e.message}")
|
||||
}
|
||||
}
|
||||
@@ -795,15 +871,18 @@ class CompileServiceImpl(
|
||||
// B performs election: (1) is false because neither A nor C does not fit into B, (2) is false because B does not fit into neither A nor C.
|
||||
// C performs election: (1) is false because B is better than A and B does not fit into C, (2) is false C does not fit into neither A nor B.
|
||||
// Result: all daemons are alive and well.
|
||||
else if (daemonJVMOptions memorywiseFitsInto fattestOpts && FileAgeComparator().compare(bestDaemonWithMetadata.runFile, runFile) > 0) {
|
||||
else if (daemonJVMOptions memorywiseFitsInto fattestOpts && FileAgeComparator().compare(
|
||||
bestDaemonWithMetadata.runFile,
|
||||
runFile
|
||||
) > 0
|
||||
) {
|
||||
// there is at least one bigger, handover my clients to it and shutdown
|
||||
log.info("$LOG_PREFIX_ASSUMING_OTHER_DAEMONS_HAVE higher prio, handover clients to it and schedule shutdown: my runfile: ${runFile.name} (${runFile.lastModified()}) vs best other runfile: ${bestDaemonWithMetadata.runFile.name} (${bestDaemonWithMetadata.runFile.lastModified()})")
|
||||
getClients().takeIf { it.isGood }?.let {
|
||||
it.get().forEach { bestDaemonWithMetadata.daemon.registerClient(it) }
|
||||
}
|
||||
scheduleShutdown(true)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// undecided, do nothing
|
||||
log.info("$LOG_PREFIX_ASSUMING_OTHER_DAEMONS_HAVE equal prio, continue: ${runFile.name} (${runFile.lastModified()}) vs best other runfile: ${bestDaemonWithMetadata.runFile.name} (${bestDaemonWithMetadata.runFile.lastModified()})")
|
||||
// TODO: implement some behaviour here, e.g.:
|
||||
@@ -817,7 +896,7 @@ class CompileServiceImpl(
|
||||
private fun shutdownNow() {
|
||||
log.info("Shutdown started")
|
||||
fun Long.mb() = this / (1024 * 1024)
|
||||
with (Runtime.getRuntime()) {
|
||||
with(Runtime.getRuntime()) {
|
||||
log.info("Memory stats: total: ${totalMemory().mb()}mb, free: ${freeMemory().mb()}mb, max: ${maxMemory().mb()}mb")
|
||||
}
|
||||
state.alive.set(Aliveness.Dying.ordinal)
|
||||
@@ -838,14 +917,13 @@ class CompileServiceImpl(
|
||||
state.delayedShutdownQueued.set(false)
|
||||
if (currentClientsCount == state.clientsCounter &&
|
||||
currentCompilationsCount == compilationsCounter.get() &&
|
||||
currentSessionId == state.sessions.lastSessionId)
|
||||
{
|
||||
currentSessionId == state.sessions.lastSessionId
|
||||
) {
|
||||
ifAliveExclusiveUnit(minAliveness = Aliveness.LastSession) {
|
||||
log.fine("Execute delayed shutdown")
|
||||
shutdownNow()
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
log.info("Cancel delayed shutdown due to a new activity")
|
||||
}
|
||||
}
|
||||
@@ -856,7 +934,8 @@ class CompileServiceImpl(
|
||||
fun shutdownIfIdle() = when {
|
||||
state.sessions.isEmpty() -> shutdownWithDelay()
|
||||
else -> {
|
||||
daemonOptions.autoshutdownIdleSeconds = TimeUnit.MILLISECONDS.toSeconds(daemonOptions.forceShutdownTimeoutMilliseconds).toInt()
|
||||
daemonOptions.autoshutdownIdleSeconds =
|
||||
TimeUnit.MILLISECONDS.toSeconds(daemonOptions.forceShutdownTimeoutMilliseconds).toInt()
|
||||
daemonOptions.autoshutdownUnusedSeconds = daemonOptions.autoshutdownIdleSeconds
|
||||
log.info("Some sessions are active, waiting for them to finish")
|
||||
log.info("Unused/idle timeouts are set to ${daemonOptions.autoshutdownUnusedSeconds}/${daemonOptions.autoshutdownIdleSeconds}s")
|
||||
@@ -871,8 +950,7 @@ class CompileServiceImpl(
|
||||
|
||||
if (!onAnotherThread) {
|
||||
shutdownIfIdle()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
timer.schedule(1) {
|
||||
ifAliveExclusiveUnit(minAliveness = Aliveness.LastSession) {
|
||||
shutdownIfIdle()
|
||||
@@ -883,64 +961,79 @@ class CompileServiceImpl(
|
||||
}
|
||||
|
||||
// todo: remove after remoteIncrementalCompile is removed
|
||||
private fun doCompile(sessionId: Int,
|
||||
args: Array<out String>,
|
||||
compilerMessagesStreamProxy: RemoteOutputStream,
|
||||
serviceOutputStreamProxy: RemoteOutputStream,
|
||||
operationsTracer: RemoteOperationsTracer?,
|
||||
body: (PrintStream, EventManager, Profiler) -> ExitCode): CompileService.CallResult<Int> =
|
||||
ifAlive {
|
||||
withValidClientOrSessionProxy(sessionId) {
|
||||
operationsTracer?.before("compile")
|
||||
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
|
||||
val eventManger = EventManagerImpl()
|
||||
val compilerMessagesStream = PrintStream(BufferedOutputStream(RemoteOutputStreamClient(compilerMessagesStreamProxy, rpcProfiler), REMOTE_STREAM_BUFFER_SIZE))
|
||||
val serviceOutputStream = PrintStream(BufferedOutputStream(RemoteOutputStreamClient(serviceOutputStreamProxy, rpcProfiler), REMOTE_STREAM_BUFFER_SIZE))
|
||||
try {
|
||||
val compileServiceReporter = DaemonMessageReporterPrintStreamAdapter(serviceOutputStream)
|
||||
if (args.none())
|
||||
throw IllegalArgumentException("Error: empty arguments list.")
|
||||
log.info("Starting compilation with args: " + args.joinToString(" "))
|
||||
val exitCode = checkedCompile(compileServiceReporter, rpcProfiler) {
|
||||
body(compilerMessagesStream, eventManger, rpcProfiler).code
|
||||
}
|
||||
CompileService.CallResult.Good(exitCode)
|
||||
}
|
||||
finally {
|
||||
serviceOutputStream.flush()
|
||||
compilerMessagesStream.flush()
|
||||
eventManger.fireCompilationFinished()
|
||||
operationsTracer?.after("compile")
|
||||
private fun doCompile(
|
||||
sessionId: Int,
|
||||
args: Array<out String>,
|
||||
compilerMessagesStreamProxy: RemoteOutputStream,
|
||||
serviceOutputStreamProxy: RemoteOutputStream,
|
||||
operationsTracer: RemoteOperationsTracer?,
|
||||
body: (PrintStream, EventManager, Profiler) -> ExitCode
|
||||
): CompileService.CallResult<Int> =
|
||||
ifAlive {
|
||||
withValidClientOrSessionProxy(sessionId) {
|
||||
operationsTracer?.before("compile")
|
||||
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
|
||||
val eventManger = EventManagerImpl()
|
||||
val compilerMessagesStream = PrintStream(
|
||||
BufferedOutputStream(
|
||||
RemoteOutputStreamClient(compilerMessagesStreamProxy, rpcProfiler),
|
||||
REMOTE_STREAM_BUFFER_SIZE
|
||||
)
|
||||
)
|
||||
val serviceOutputStream = PrintStream(
|
||||
BufferedOutputStream(
|
||||
RemoteOutputStreamClient(serviceOutputStreamProxy, rpcProfiler),
|
||||
REMOTE_STREAM_BUFFER_SIZE
|
||||
)
|
||||
)
|
||||
try {
|
||||
val compileServiceReporter = DaemonMessageReporterPrintStreamAdapter(serviceOutputStream)
|
||||
if (args.none())
|
||||
throw IllegalArgumentException("Error: empty arguments list.")
|
||||
log.info("Starting compilation with args: " + args.joinToString(" "))
|
||||
val exitCode = checkedCompile(compileServiceReporter, rpcProfiler) {
|
||||
body(compilerMessagesStream, eventManger, rpcProfiler).code
|
||||
}
|
||||
CompileService.CallResult.Good(exitCode)
|
||||
} finally {
|
||||
serviceOutputStream.flush()
|
||||
compilerMessagesStream.flush()
|
||||
eventManger.fireCompilationFinished()
|
||||
operationsTracer?.after("compile")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doCompile(sessionId: Int,
|
||||
daemonMessageReporter: DaemonMessageReporter,
|
||||
tracer: RemoteOperationsTracer?,
|
||||
body: (EventManager, Profiler) -> ExitCode): CompileService.CallResult<Int> =
|
||||
ifAlive {
|
||||
withValidClientOrSessionProxy(sessionId) {
|
||||
tracer?.before("compile")
|
||||
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
|
||||
val eventManger = EventManagerImpl()
|
||||
try {
|
||||
val exitCode = checkedCompile(daemonMessageReporter, rpcProfiler) {
|
||||
body(eventManger, rpcProfiler).code
|
||||
}
|
||||
CompileService.CallResult.Good(exitCode)
|
||||
}
|
||||
finally {
|
||||
eventManger.fireCompilationFinished()
|
||||
tracer?.after("compile")
|
||||
private fun doCompile(
|
||||
sessionId: Int,
|
||||
daemonMessageReporter: DaemonMessageReporter,
|
||||
tracer: RemoteOperationsTracer?,
|
||||
body: (EventManager, Profiler) -> ExitCode
|
||||
): CompileService.CallResult<Int> =
|
||||
ifAlive {
|
||||
withValidClientOrSessionProxy(sessionId) {
|
||||
tracer?.before("compile")
|
||||
val rpcProfiler = if (daemonOptions.reportPerf) WallAndThreadTotalProfiler() else DummyProfiler()
|
||||
val eventManger = EventManagerImpl()
|
||||
try {
|
||||
val exitCode = checkedCompile(daemonMessageReporter, rpcProfiler) {
|
||||
body(eventManger, rpcProfiler).code
|
||||
}
|
||||
CompileService.CallResult.Good(exitCode)
|
||||
} finally {
|
||||
eventManger.fireCompilationFinished()
|
||||
tracer?.after("compile")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createCompileServices(facade: CompilerCallbackServicesFacade, eventManager: EventManager, rpcProfiler: Profiler): Services {
|
||||
val builder = Services.Builder()
|
||||
if (facade.hasIncrementalCaches()) {
|
||||
builder.register(IncrementalCompilationComponents::class.java, RemoteIncrementalCompilationComponentsClient(facade, eventManager, rpcProfiler))
|
||||
builder.register(
|
||||
IncrementalCompilationComponents::class.java,
|
||||
RemoteIncrementalCompilationComponentsClient(facade, eventManager, rpcProfiler)
|
||||
)
|
||||
}
|
||||
if (facade.hasLookupTracker()) {
|
||||
builder.register(LookupTracker::class.java, RemoteLookupTrackerClient(facade, eventManager, rpcProfiler))
|
||||
@@ -962,7 +1055,7 @@ class CompileServiceImpl(
|
||||
}
|
||||
|
||||
|
||||
private fun<R> checkedCompile(daemonMessageReporter: DaemonMessageReporter, rpcProfiler: Profiler, body: () -> R): R {
|
||||
private fun <R> checkedCompile(daemonMessageReporter: DaemonMessageReporter, rpcProfiler: Profiler, body: () -> R): R {
|
||||
try {
|
||||
val profiler = if (daemonOptions.reportPerf) WallAndThreadAndMemoryTotalProfiler(withGC = false) else DummyProfiler()
|
||||
|
||||
@@ -978,7 +1071,9 @@ class CompileServiceImpl(
|
||||
val pc = profiler.getTotalCounters()
|
||||
val rpc = rpcProfiler.getTotalCounters()
|
||||
|
||||
"PERF: Compile on daemon: ${pc.time.ms()} ms; thread: user ${pc.threadUserTime.ms()} ms, sys ${(pc.threadTime - pc.threadUserTime).ms()} ms; rpc: ${rpc.count} calls, ${rpc.time.ms()} ms, thread ${rpc.threadTime.ms()} ms; memory: ${endMem.kb()} kb (${"%+d".format(pc.memory.kb())} kb)".let {
|
||||
"PERF: Compile on daemon: ${pc.time.ms()} ms; thread: user ${pc.threadUserTime.ms()} ms, sys ${(pc.threadTime - pc.threadUserTime).ms()} ms; rpc: ${rpc.count} calls, ${rpc.time.ms()} ms, thread ${rpc.threadTime.ms()} ms; memory: ${endMem.kb()} kb (${"%+d".format(
|
||||
pc.memory.kb()
|
||||
)} kb)".let {
|
||||
daemonMessageReporter.report(ReportSeverity.INFO, it)
|
||||
log.info(it)
|
||||
}
|
||||
@@ -1001,7 +1096,8 @@ class CompileServiceImpl(
|
||||
if (e.cause != null && e.cause != e) {
|
||||
"\nCaused by: ${e.cause}\n ${e.cause!!.stackTrace.joinToString("\n ")}"
|
||||
} else ""
|
||||
}")
|
||||
}"
|
||||
)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -1011,7 +1107,10 @@ class CompileServiceImpl(
|
||||
(KotlinCoreEnvironment.applicationEnvironment?.jarFileSystem as? CoreJarFileSystem)?.clearHandlersCache()
|
||||
}
|
||||
|
||||
private inline fun<R> ifAlive(minAliveness: Aliveness = Aliveness.LastSession, body: () -> CompileService.CallResult<R>): CompileService.CallResult<R> = rwlock.read {
|
||||
private inline fun <R> ifAlive(
|
||||
minAliveness: Aliveness = Aliveness.LastSession,
|
||||
body: () -> CompileService.CallResult<R>
|
||||
): CompileService.CallResult<R> = rwlock.read {
|
||||
ifAliveChecksImpl(minAliveness, body)
|
||||
}
|
||||
|
||||
@@ -1022,7 +1121,10 @@ class CompileServiceImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun<R> ifAliveExclusive(minAliveness: Aliveness = Aliveness.LastSession, body: () -> CompileService.CallResult<R>): CompileService.CallResult<R> = rwlock.write {
|
||||
private inline fun <R> ifAliveExclusive(
|
||||
minAliveness: Aliveness = Aliveness.LastSession,
|
||||
body: () -> CompileService.CallResult<R>
|
||||
): CompileService.CallResult<R> = rwlock.write {
|
||||
ifAliveChecksImpl(minAliveness, body)
|
||||
}
|
||||
|
||||
@@ -1033,7 +1135,10 @@ class CompileServiceImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun<R> ifAliveChecksImpl(minAliveness: Aliveness = Aliveness.LastSession, body: () -> CompileService.CallResult<R>): CompileService.CallResult<R> {
|
||||
private inline fun <R> ifAliveChecksImpl(
|
||||
minAliveness: Aliveness = Aliveness.LastSession,
|
||||
body: () -> CompileService.CallResult<R>
|
||||
): CompileService.CallResult<R> {
|
||||
val curState = state.alive.get()
|
||||
return when {
|
||||
curState < minAliveness.ordinal -> {
|
||||
@@ -1043,8 +1148,7 @@ class CompileServiceImpl(
|
||||
else -> {
|
||||
try {
|
||||
body()
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
} catch (e: Throwable) {
|
||||
log.log(Level.SEVERE, "Exception", e)
|
||||
CompileService.CallResult.Error(e.message ?: "unknown")
|
||||
}
|
||||
@@ -1052,31 +1156,34 @@ class CompileServiceImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun<R> withValidClientOrSessionProxy(sessionId: Int,
|
||||
body: (ClientOrSessionProxy<Any>?) -> CompileService.CallResult<R>
|
||||
private inline fun <R> withValidClientOrSessionProxy(
|
||||
sessionId: Int,
|
||||
body: (ClientOrSessionProxy<Any>?) -> CompileService.CallResult<R>
|
||||
): CompileService.CallResult<R> {
|
||||
val session: ClientOrSessionProxy<Any>? =
|
||||
if (sessionId == CompileService.NO_SESSION) null
|
||||
else state.sessions[sessionId] ?: return CompileService.CallResult.Error("Unknown or invalid session $sessionId")
|
||||
if (sessionId == CompileService.NO_SESSION) null
|
||||
else state.sessions[sessionId] ?: return CompileService.CallResult.Error("Unknown or invalid session $sessionId")
|
||||
try {
|
||||
compilationsCounter.incrementAndGet()
|
||||
return body(session)
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
_lastUsedSeconds = nowSeconds()
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun<R> withValidRepl(sessionId: Int, body: KotlinJvmReplService.() -> R): CompileService.CallResult<R> =
|
||||
withValidClientOrSessionProxy(sessionId) { session ->
|
||||
(session?.data as? KotlinJvmReplService?)?.let {
|
||||
CompileService.CallResult.Good(it.body())
|
||||
} ?: CompileService.CallResult.Error("Not a REPL session $sessionId")
|
||||
}
|
||||
private inline fun <R> withValidRepl(sessionId: Int, body: KotlinJvmReplService.() -> R): CompileService.CallResult<R> =
|
||||
withValidClientOrSessionProxy(sessionId) { session ->
|
||||
(session?.data as? KotlinJvmReplService?)?.let {
|
||||
CompileService.CallResult.Good(it.body())
|
||||
} ?: CompileService.CallResult.Error("Not a REPL session $sessionId")
|
||||
}
|
||||
|
||||
@JvmName("withValidRepl1")
|
||||
private inline fun<R> withValidRepl(sessionId: Int, body: KotlinJvmReplService.() -> CompileService.CallResult<R>): CompileService.CallResult<R> =
|
||||
withValidClientOrSessionProxy(sessionId) { session ->
|
||||
(session?.data as? KotlinJvmReplService?)?.body() ?: CompileService.CallResult.Error("Not a REPL session $sessionId")
|
||||
}
|
||||
private inline fun <R> withValidRepl(
|
||||
sessionId: Int,
|
||||
body: KotlinJvmReplService.() -> CompileService.CallResult<R>
|
||||
): CompileService.CallResult<R> =
|
||||
withValidClientOrSessionProxy(sessionId) { session ->
|
||||
(session?.data as? KotlinJvmReplService?)?.body() ?: CompileService.CallResult.Error("Not a REPL session $sessionId")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,10 @@ class IncrementalPackagePartProvider(
|
||||
|
||||
private val moduleMappings = storageManager.createLazyValue {
|
||||
incrementalCaches.map { cache ->
|
||||
ModuleMapping.loadModuleMapping(cache.getModuleMappingData(), "<incremental>", deserializationConfiguration)
|
||||
ModuleMapping.loadModuleMapping(cache.getModuleMappingData(), "<incremental>", deserializationConfiguration) { version ->
|
||||
// Incremental compilation should fall back to full rebuild if the minor component of the metadata version has changed
|
||||
throw IllegalStateException("Version of the generated module should not be incompatible: $version")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -632,6 +632,7 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory0<PsiElement> OPTIONAL_EXPECTATION_NOT_ON_EXPECTED = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -289,6 +289,7 @@ public class DefaultErrorMessages {
|
||||
|
||||
MAP.put(OPTIONAL_EXPECTATION_NOT_ON_EXPECTED, "'@OptionalExpectation' can only be used on an expected annotation class");
|
||||
MAP.put(OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY, "Declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry");
|
||||
MAP.put(OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE, "Declaration annotated with '@OptionalExpectation' can only be used in common module sources");
|
||||
|
||||
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
|
||||
MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here");
|
||||
|
||||
@@ -247,7 +247,11 @@ class PSICallResolver(
|
||||
tracingStrategy: TracingStrategy,
|
||||
trace: BindingTrace
|
||||
): ManyCandidates<D> {
|
||||
val resolvedCalls = diagnostic.candidates.map { kotlinToResolvedCallTransformer.onlyTransform<D>(it.resolvedCall, emptyList()) }
|
||||
val resolvedCalls = diagnostic.candidates.map {
|
||||
kotlinToResolvedCallTransformer.onlyTransform<D>(
|
||||
it.resolvedCall, it.diagnosticsFromResolutionParts + it.getSystem().diagnostics
|
||||
)
|
||||
}
|
||||
|
||||
if (diagnostic.candidates.areAllFailed()) {
|
||||
if (diagnostic.candidates.areAllFailedWithInapplicableWrongReceiver()) {
|
||||
|
||||
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.resolve.checkers
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
|
||||
|
||||
class OptionalExpectationUsageChecker : ClassifierUsageChecker {
|
||||
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
|
||||
@@ -16,5 +18,10 @@ class OptionalExpectationUsageChecker : ClassifierUsageChecker {
|
||||
if (!element.isUsageAsAnnotationOrImport()) {
|
||||
context.trace.report(Errors.OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY.on(element))
|
||||
}
|
||||
|
||||
val ktFile = element.containingFile as KtFile
|
||||
if (ktFile.isCommonSource != true) {
|
||||
context.trace.report(Errors.OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE.on(element))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-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.resolve.multiplatform
|
||||
|
||||
import com.intellij.openapi.util.Key
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||
|
||||
/**
|
||||
* Returns true if this file is a part of the common module in a multi-platform project.
|
||||
* This setting only makes sense in the compiler, not in the IDE where sources from common modules are analyzed as common
|
||||
*/
|
||||
var KtFile.isCommonSource: Boolean? by UserDataProperty(Key.create("IS_COMMON_SOURCE"))
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2010-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.incremental
|
||||
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import java.io.File
|
||||
|
||||
class DirtyFilesContainer(
|
||||
private val caches: IncrementalCachesManager<*>,
|
||||
private val reporter: ICReporter
|
||||
) {
|
||||
private val myDirtyFiles = HashSet<File>()
|
||||
|
||||
fun toMutableList(): MutableList<File> =
|
||||
ArrayList(myDirtyFiles)
|
||||
|
||||
fun add(files: Iterable<File>) {
|
||||
val existingKotlinFiles = files.filter { it.isKotlinFile() }
|
||||
if (existingKotlinFiles.isNotEmpty()) {
|
||||
myDirtyFiles.addAll(existingKotlinFiles)
|
||||
}
|
||||
}
|
||||
|
||||
fun addByDirtySymbols(lookupSymbols: Collection<LookupSymbol>) {
|
||||
if (lookupSymbols.isEmpty()) return
|
||||
|
||||
val dirtyFilesFromLookups = mapLookupSymbolsToFiles(caches.lookupCache, lookupSymbols, reporter)
|
||||
add(dirtyFilesFromLookups)
|
||||
}
|
||||
|
||||
fun addByDirtyClasses(dirtyClassesFqNames: Collection<FqName>) {
|
||||
if (dirtyClassesFqNames.isEmpty()) return
|
||||
|
||||
val fqNamesWithSubtypes = dirtyClassesFqNames.flatMap {
|
||||
withSubtypes(
|
||||
it,
|
||||
listOf(caches.platformCache)
|
||||
)
|
||||
}
|
||||
val dirtyFilesFromFqNames =
|
||||
mapClassesFqNamesToFiles(listOf(caches.platformCache), fqNamesWithSubtypes, reporter)
|
||||
add(dirtyFilesFromFqNames)
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@ import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
|
||||
import org.jetbrains.kotlin.incremental.storage.version.CacheVersionManager
|
||||
import org.jetbrains.kotlin.incremental.storage.version.saveIfNeeded
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||
import java.io.File
|
||||
@@ -37,10 +39,11 @@ abstract class IncrementalCompilerRunner<
|
||||
Args : CommonCompilerArguments,
|
||||
CacheManager : IncrementalCachesManager<*>
|
||||
>(
|
||||
workingDir: File,
|
||||
cacheDirName: String,
|
||||
protected val cacheVersions: List<CacheVersion>,
|
||||
protected val reporter: ICReporter,
|
||||
workingDir: File,
|
||||
cacheDirName: String,
|
||||
protected val cachesVersionManagers: List<CacheVersionManager>,
|
||||
protected val reporter: ICReporter,
|
||||
private val buildHistoryFile: File,
|
||||
private val localStateDirs: Collection<File> = emptyList()
|
||||
) {
|
||||
|
||||
@@ -117,11 +120,9 @@ abstract class IncrementalCompilerRunner<
|
||||
|
||||
protected abstract fun calculateSourcesToCompile(caches: CacheManager, changedFiles: ChangedFiles.Known, args: Args): CompilationMode
|
||||
|
||||
protected fun getDirtyFiles(changedFiles: ChangedFiles.Known): HashSet<File> {
|
||||
val dirtyFiles = HashSet<File>(with(changedFiles) { modified.size + removed.size })
|
||||
with(changedFiles) {
|
||||
modified.asSequence() + removed.asSequence()
|
||||
}.filterTo(dirtyFiles, File::isKotlinFile)
|
||||
protected fun initDirtyFiles(dirtyFiles: DirtyFilesContainer, changedFiles: ChangedFiles.Known) {
|
||||
dirtyFiles.add(changedFiles.modified)
|
||||
dirtyFiles.add(changedFiles.removed)
|
||||
|
||||
if (dirtySourcesSinceLastTimeFile.exists()) {
|
||||
val files = dirtySourcesSinceLastTimeFile.readLines().map(::File)
|
||||
@@ -129,14 +130,12 @@ abstract class IncrementalCompilerRunner<
|
||||
reporter.report { "Source files added since last compilation: ${reporter.pathsAsString(files)}" }
|
||||
}
|
||||
|
||||
dirtyFiles.addAll(files)
|
||||
dirtyFiles.add(files)
|
||||
}
|
||||
|
||||
return dirtyFiles
|
||||
}
|
||||
|
||||
protected sealed class CompilationMode {
|
||||
class Incremental(val dirtyFiles: Set<File>) : CompilationMode()
|
||||
class Incremental(val dirtyFiles: DirtyFilesContainer) : CompilationMode()
|
||||
class Rebuild(getReason: () -> String = { "" }) : CompilationMode() {
|
||||
val reason: String by lazy(getReason)
|
||||
}
|
||||
@@ -188,7 +187,7 @@ abstract class IncrementalCompilerRunner<
|
||||
preBuildHook(args, compilationMode)
|
||||
|
||||
val dirtySources = when (compilationMode) {
|
||||
is CompilationMode.Incremental -> ArrayList(compilationMode.dirtyFiles)
|
||||
is CompilationMode.Incremental -> compilationMode.dirtyFiles.toMutableList()
|
||||
is CompilationMode.Rebuild -> allKotlinSources.toMutableList()
|
||||
}
|
||||
|
||||
@@ -271,7 +270,7 @@ abstract class IncrementalCompilerRunner<
|
||||
processChangesAfterBuild(compilationMode, currentBuildInfo, dirtyData)
|
||||
|
||||
if (exitCode == ExitCode.OK) {
|
||||
cacheVersions.forEach { it.saveIfNeeded() }
|
||||
cachesVersionManagers.forEach { it.saveIfNeeded() }
|
||||
}
|
||||
|
||||
return exitCode
|
||||
@@ -303,11 +302,20 @@ abstract class IncrementalCompilerRunner<
|
||||
|
||||
open fun runWithNoDirtyKotlinSources(caches: CacheManager): Boolean = false
|
||||
|
||||
protected open fun processChangesAfterBuild(
|
||||
private fun processChangesAfterBuild(
|
||||
compilationMode: CompilationMode,
|
||||
currentBuildInfo: BuildInfo,
|
||||
dirtyData: DirtyData
|
||||
) {
|
||||
val prevDiffs = BuildDiffsStorage.readFromFile(buildHistoryFile, reporter)?.buildDiffs ?: emptyList()
|
||||
val newDiff = if (compilationMode is CompilationMode.Incremental) {
|
||||
BuildDifference(currentBuildInfo.startTS, true, dirtyData)
|
||||
} else {
|
||||
val emptyDirtyData = DirtyData()
|
||||
BuildDifference(currentBuildInfo.startTS, false, emptyDirtyData)
|
||||
}
|
||||
|
||||
BuildDiffsStorage.writeToFile(buildHistoryFile, BuildDiffsStorage(prevDiffs + newDiff), reporter)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.incremental
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.kotlin.build.GeneratedFile
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||
@@ -27,7 +26,9 @@ import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.js.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.incremental.storage.version.CacheVersionManager
|
||||
import org.jetbrains.kotlin.incremental.multiproject.EmptyModulesApiHistory
|
||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
|
||||
import java.io.File
|
||||
|
||||
fun makeJsIncrementally(
|
||||
@@ -38,12 +39,16 @@ fun makeJsIncrementally(
|
||||
reporter: ICReporter = EmptyICReporter
|
||||
) {
|
||||
val isIncremental = IncrementalCompilation.isEnabledForJs()
|
||||
val versions = commonCacheVersions(cachesDir, isIncremental) + standaloneCacheVersion(cachesDir, isIncremental)
|
||||
val versions = commonCacheVersionsManagers(cachesDir, isIncremental) + standaloneCacheVersionManager(cachesDir, isIncremental)
|
||||
val allKotlinFiles = sourceRoots.asSequence().flatMap { it.walk() }
|
||||
.filter { it.isFile && it.extension.equals("kt", ignoreCase = true) }.toList()
|
||||
val buildHistoryFile = File(cachesDir, "build-history.bin")
|
||||
|
||||
withJsIC {
|
||||
val compiler = IncrementalJsCompilerRunner(cachesDir, versions, reporter)
|
||||
val compiler = IncrementalJsCompilerRunner(
|
||||
cachesDir, versions, reporter,
|
||||
buildHistoryFile = buildHistoryFile,
|
||||
modulesApiHistory = EmptyModulesApiHistory)
|
||||
compiler.compile(allKotlinFiles, args, messageCollector, providedChangedFiles = null)
|
||||
}
|
||||
}
|
||||
@@ -60,14 +65,17 @@ inline fun <R> withJsIC(fn: () -> R): R {
|
||||
}
|
||||
|
||||
class IncrementalJsCompilerRunner(
|
||||
workingDir: File,
|
||||
cacheVersions: List<CacheVersion>,
|
||||
reporter: ICReporter
|
||||
workingDir: File,
|
||||
cachesVersionManagers: List<CacheVersionManager>,
|
||||
reporter: ICReporter,
|
||||
buildHistoryFile: File,
|
||||
private val modulesApiHistory: ModulesApiHistory
|
||||
) : IncrementalCompilerRunner<K2JSCompilerArguments, IncrementalJsCachesManager>(
|
||||
workingDir,
|
||||
"caches-js",
|
||||
cacheVersions,
|
||||
reporter
|
||||
workingDir,
|
||||
"caches-js",
|
||||
cachesVersionManagers,
|
||||
reporter,
|
||||
buildHistoryFile = buildHistoryFile
|
||||
) {
|
||||
override fun isICEnabled(): Boolean =
|
||||
IncrementalCompilation.isEnabledForJs()
|
||||
@@ -79,39 +87,31 @@ class IncrementalJsCompilerRunner(
|
||||
File(args.outputFile).parentFile
|
||||
|
||||
override fun calculateSourcesToCompile(caches: IncrementalJsCachesManager, changedFiles: ChangedFiles.Known, args: K2JSCompilerArguments): CompilationMode {
|
||||
if (BuildInfo.read(lastBuildInfoFile) == null) return CompilationMode.Rebuild { "No information on previous build" }
|
||||
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile)
|
||||
?: return CompilationMode.Rebuild { "No information on previous build" }
|
||||
|
||||
val libs = (args.libraries ?: "").split(File.pathSeparator).mapTo(HashSet()) { File(it) }
|
||||
val libsDirs = libs.filter { it.isDirectory }
|
||||
val dirtyFiles = DirtyFilesContainer(caches, reporter)
|
||||
initDirtyFiles(dirtyFiles, changedFiles)
|
||||
|
||||
val changedLib = changedFiles.allAsSequence.find { it in libs }
|
||||
?: changedFiles.allAsSequence.find { changedFile ->
|
||||
libsDirs.any { libDir -> FileUtil.isAncestor(libDir, changedFile, true) }
|
||||
}
|
||||
val libs = (args.libraries ?: "").split(File.pathSeparator).map { File(it) }
|
||||
val classpathChanges = getClasspathChanges(libs, changedFiles, lastBuildInfo, modulesApiHistory, reporter)
|
||||
|
||||
if (changedLib != null) return CompilationMode.Rebuild { "Library has been changed: $changedLib" }
|
||||
|
||||
val dirtyFiles = getDirtyFiles(changedFiles)
|
||||
|
||||
// todo: unify with JVM calculateSourcesToCompile
|
||||
fun markDirtyBy(lookupSymbols: Collection<LookupSymbol>) {
|
||||
if (lookupSymbols.isEmpty()) return
|
||||
|
||||
val dirtyFilesFromLookups = mapLookupSymbolsToFiles(caches.lookupCache, lookupSymbols, reporter)
|
||||
dirtyFiles.addAll(dirtyFilesFromLookups)
|
||||
@Suppress("UNUSED_VARIABLE") // for sealed when
|
||||
val unused = when (classpathChanges) {
|
||||
is ChangesEither.Unknown -> return CompilationMode.Rebuild {
|
||||
// todo: we can recompile all files incrementally (not cleaning caches), so rebuild won't propagate
|
||||
"Could not get classpath's changes${classpathChanges.reason?.let { ": $it" }}"
|
||||
}
|
||||
is ChangesEither.Known -> {
|
||||
dirtyFiles.addByDirtySymbols(classpathChanges.lookupSymbols)
|
||||
dirtyFiles.addByDirtyClasses(classpathChanges.fqNames)
|
||||
}
|
||||
}
|
||||
|
||||
fun markDirtyBy(dirtyClassesFqNames: Collection<FqName>) {
|
||||
if (dirtyClassesFqNames.isEmpty()) return
|
||||
|
||||
val fqNamesWithSubtypes = dirtyClassesFqNames.flatMap { withSubtypes(it, listOf(caches.platformCache)) }
|
||||
val dirtyFilesFromFqNames = mapClassesFqNamesToFiles(listOf(caches.platformCache), fqNamesWithSubtypes, reporter)
|
||||
dirtyFiles.addAll(dirtyFilesFromFqNames)
|
||||
}
|
||||
|
||||
val removedClassesChanges = getRemovedClassesChanges(caches, changedFiles)
|
||||
markDirtyBy(removedClassesChanges.dirtyLookupSymbols)
|
||||
markDirtyBy(removedClassesChanges.dirtyClassesFqNames)
|
||||
dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols)
|
||||
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames)
|
||||
|
||||
return CompilationMode.Incremental(dirtyFiles)
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.incremental.multiproject.EmptyModulesApiHistory
|
||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
|
||||
import org.jetbrains.kotlin.incremental.storage.version.CacheVersionManager
|
||||
import org.jetbrains.kotlin.incremental.util.Either
|
||||
import org.jetbrains.kotlin.load.java.JavaClassesTracker
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
@@ -57,7 +58,7 @@ fun makeIncrementally(
|
||||
reporter: ICReporter = EmptyICReporter
|
||||
) {
|
||||
val isIncremental = IncrementalCompilation.isEnabledForJvm()
|
||||
val versions = commonCacheVersions(cachesDir, isIncremental) + standaloneCacheVersion(cachesDir, isIncremental)
|
||||
val versions = commonCacheVersionsManagers(cachesDir, isIncremental) + standaloneCacheVersionManager(cachesDir, isIncremental)
|
||||
|
||||
val kotlinExtensions = listOf("kt", "kts")
|
||||
val allExtensions = kotlinExtensions + listOf("java")
|
||||
@@ -99,20 +100,21 @@ inline fun <R> withIC(enabled: Boolean = true, fn: ()->R): R {
|
||||
}
|
||||
|
||||
class IncrementalJvmCompilerRunner(
|
||||
workingDir: File,
|
||||
private val javaSourceRoots: Set<JvmSourceRoot>,
|
||||
cacheVersions: List<CacheVersion>,
|
||||
reporter: ICReporter,
|
||||
private val usePreciseJavaTracking: Boolean,
|
||||
private val buildHistoryFile: File,
|
||||
localStateDirs: Collection<File>,
|
||||
private val modulesApiHistory: ModulesApiHistory
|
||||
workingDir: File,
|
||||
private val javaSourceRoots: Set<JvmSourceRoot>,
|
||||
cachesVersionManagers: List<CacheVersionManager>,
|
||||
reporter: ICReporter,
|
||||
private val usePreciseJavaTracking: Boolean,
|
||||
buildHistoryFile: File,
|
||||
localStateDirs: Collection<File>,
|
||||
private val modulesApiHistory: ModulesApiHistory
|
||||
) : IncrementalCompilerRunner<K2JVMCompilerArguments, IncrementalJvmCachesManager>(
|
||||
workingDir,
|
||||
"caches-jvm",
|
||||
cacheVersions,
|
||||
reporter,
|
||||
localStateDirs = localStateDirs
|
||||
workingDir,
|
||||
"caches-jvm",
|
||||
cachesVersionManagers,
|
||||
reporter,
|
||||
localStateDirs = localStateDirs,
|
||||
buildHistoryFile = buildHistoryFile
|
||||
) {
|
||||
override fun isICEnabled(): Boolean =
|
||||
IncrementalCompilation.isEnabledForJvm()
|
||||
@@ -144,27 +146,13 @@ class IncrementalJvmCompilerRunner(
|
||||
changedFiles: ChangedFiles.Known,
|
||||
args: K2JVMCompilerArguments
|
||||
): CompilationMode {
|
||||
val dirtyFiles = getDirtyFiles(changedFiles)
|
||||
|
||||
fun markDirtyBy(lookupSymbols: Collection<LookupSymbol>) {
|
||||
if (lookupSymbols.isEmpty()) return
|
||||
|
||||
val dirtyFilesFromLookups = mapLookupSymbolsToFiles(caches.lookupCache, lookupSymbols, reporter)
|
||||
dirtyFiles.addAll(dirtyFilesFromLookups)
|
||||
}
|
||||
|
||||
fun markDirtyBy(dirtyClassesFqNames: Collection<FqName>) {
|
||||
if (dirtyClassesFqNames.isEmpty()) return
|
||||
|
||||
val fqNamesWithSubtypes = dirtyClassesFqNames.flatMap { withSubtypes(it, listOf(caches.platformCache)) }
|
||||
val dirtyFilesFromFqNames = mapClassesFqNamesToFiles(listOf(caches.platformCache), fqNamesWithSubtypes, reporter)
|
||||
dirtyFiles.addAll(dirtyFilesFromFqNames)
|
||||
}
|
||||
val dirtyFiles = DirtyFilesContainer(caches, reporter)
|
||||
initDirtyFiles(dirtyFiles, changedFiles)
|
||||
|
||||
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile) ?: return CompilationMode.Rebuild { "No information on previous build" }
|
||||
reporter.report { "Last Kotlin Build info -- $lastBuildInfo" }
|
||||
|
||||
val classpathChanges = getClasspathChanges(args.classpathAsList, changedFiles, lastBuildInfo)
|
||||
val classpathChanges = getClasspathChanges(args.classpathAsList, changedFiles, lastBuildInfo, modulesApiHistory, reporter)
|
||||
|
||||
@Suppress("UNUSED_VARIABLE") // for sealed when
|
||||
val unused = when (classpathChanges) {
|
||||
@@ -173,8 +161,8 @@ class IncrementalJvmCompilerRunner(
|
||||
"Could not get classpath's changes${classpathChanges.reason?.let { ": $it" }}"
|
||||
}
|
||||
is ChangesEither.Known -> {
|
||||
markDirtyBy(classpathChanges.lookupSymbols)
|
||||
markDirtyBy(classpathChanges.fqNames)
|
||||
dirtyFiles.addByDirtySymbols(classpathChanges.lookupSymbols)
|
||||
dirtyFiles.addByDirtyClasses(classpathChanges.fqNames)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,9 +172,8 @@ class IncrementalJvmCompilerRunner(
|
||||
is ChangesEither.Known -> javaFilesChanges.lookupSymbols
|
||||
is ChangesEither.Unknown -> return CompilationMode.Rebuild { "Could not get changes for java files" }
|
||||
}
|
||||
markDirtyBy(affectedJavaSymbols)
|
||||
}
|
||||
else {
|
||||
dirtyFiles.addByDirtySymbols(affectedJavaSymbols)
|
||||
} else {
|
||||
if (!processChangedJava(changedFiles, caches)) {
|
||||
return CompilationMode.Rebuild { "Could not get changes for java files" }
|
||||
}
|
||||
@@ -195,9 +182,9 @@ class IncrementalJvmCompilerRunner(
|
||||
val androidLayoutChanges = processLookupSymbolsForAndroidLayouts(changedFiles)
|
||||
val removedClassesChanges = getRemovedClassesChanges(caches, changedFiles)
|
||||
|
||||
markDirtyBy(androidLayoutChanges)
|
||||
markDirtyBy(removedClassesChanges.dirtyLookupSymbols)
|
||||
markDirtyBy(removedClassesChanges.dirtyClassesFqNames)
|
||||
dirtyFiles.addByDirtySymbols(androidLayoutChanges)
|
||||
dirtyFiles.addByDirtySymbols(removedClassesChanges.dirtyLookupSymbols)
|
||||
dirtyFiles.addByDirtyClasses(removedClassesChanges.dirtyClassesFqNames)
|
||||
|
||||
return CompilationMode.Incremental(dirtyFiles)
|
||||
}
|
||||
@@ -257,58 +244,6 @@ class IncrementalJvmCompilerRunner(
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getClasspathChanges(
|
||||
classpath: List<File>,
|
||||
changedFiles: ChangedFiles.Known,
|
||||
lastBuildInfo: BuildInfo
|
||||
): ChangesEither {
|
||||
val classpathSet = HashSet<File>()
|
||||
for (file in classpath) {
|
||||
when {
|
||||
file.isFile -> classpathSet.add(file)
|
||||
file.isDirectory -> file.walk().filterTo(classpathSet) { it.isFile }
|
||||
}
|
||||
}
|
||||
|
||||
val modifiedClasspath = changedFiles.modified.filterTo(HashSet()) { it in classpathSet }
|
||||
val removedClasspath = changedFiles.removed.filterTo(HashSet()) { it in classpathSet }
|
||||
|
||||
// todo: removed classes could be processed normally
|
||||
if (removedClasspath.isNotEmpty()) return ChangesEither.Unknown("Some files are removed from classpath $removedClasspath")
|
||||
|
||||
if (modifiedClasspath.isEmpty()) return ChangesEither.Known()
|
||||
|
||||
val lastBuildTS = lastBuildInfo.startTS
|
||||
|
||||
val symbols = HashSet<LookupSymbol>()
|
||||
val fqNames = HashSet<FqName>()
|
||||
|
||||
val historyFilesEither = modulesApiHistory.historyFilesForChangedFiles(modifiedClasspath)
|
||||
val historyFiles = when (historyFilesEither) {
|
||||
is Either.Success<Set<File>> -> historyFilesEither.value
|
||||
is Either.Error -> return ChangesEither.Unknown(historyFilesEither.reason)
|
||||
}
|
||||
|
||||
for (historyFile in historyFiles) {
|
||||
val allBuilds = BuildDiffsStorage.readDiffsFromFile(historyFile, reporter = reporter)
|
||||
?: return ChangesEither.Unknown("Could not read diffs from $historyFile")
|
||||
val (knownBuilds, newBuilds) = allBuilds.partition { it.ts <= lastBuildTS }
|
||||
if (knownBuilds.isEmpty()) {
|
||||
return ChangesEither.Unknown("No previously known builds for $historyFile")
|
||||
}
|
||||
|
||||
for (buildDiff in newBuilds) {
|
||||
if (!buildDiff.isIncremental) return ChangesEither.Unknown("Non-incremental build from dependency $historyFile")
|
||||
|
||||
val dirtyData = buildDiff.dirtyData
|
||||
symbols.addAll(dirtyData.dirtyLookupSymbols)
|
||||
fqNames.addAll(dirtyData.dirtyClassesFqNames)
|
||||
}
|
||||
}
|
||||
|
||||
return ChangesEither.Known(symbols, fqNames)
|
||||
}
|
||||
|
||||
override fun preBuildHook(args: K2JVMCompilerArguments, compilationMode: CompilationMode) {
|
||||
if (compilationMode is CompilationMode.Incremental) {
|
||||
val destinationDir = args.destinationAsFile
|
||||
@@ -377,22 +312,6 @@ class IncrementalJvmCompilerRunner(
|
||||
override fun additionalDirtyLookupSymbols(): Iterable<LookupSymbol> =
|
||||
javaFilesProcessor?.allChangedSymbols ?: emptyList()
|
||||
|
||||
override fun processChangesAfterBuild(
|
||||
compilationMode: CompilationMode,
|
||||
currentBuildInfo: BuildInfo,
|
||||
dirtyData: DirtyData
|
||||
) {
|
||||
val prevDiffs = BuildDiffsStorage.readFromFile(buildHistoryFile, reporter)?.buildDiffs ?: emptyList()
|
||||
val newDiff = if (compilationMode is CompilationMode.Incremental) {
|
||||
BuildDifference(currentBuildInfo.startTS, true, dirtyData)
|
||||
} else {
|
||||
val emptyDirtyData = DirtyData()
|
||||
BuildDifference(currentBuildInfo.startTS, false, emptyDirtyData)
|
||||
}
|
||||
|
||||
BuildDiffsStorage.writeToFile(buildHistoryFile, BuildDiffsStorage(prevDiffs + newDiff), reporter)
|
||||
}
|
||||
|
||||
override fun makeServices(
|
||||
args: K2JVMCompilerArguments,
|
||||
lookupTracker: LookupTracker,
|
||||
@@ -422,13 +341,16 @@ class IncrementalJvmCompilerRunner(
|
||||
val compiler = K2JVMCompiler()
|
||||
val outputDir = args.destinationAsFile
|
||||
val classpath = args.classpathAsList
|
||||
val moduleFile = makeModuleFile(args.moduleName!!,
|
||||
isTest = false,
|
||||
outputDir = outputDir,
|
||||
sourcesToCompile = sourcesToCompile,
|
||||
javaSourceRoots = javaSourceRoots,
|
||||
classpath = classpath,
|
||||
friendDirs = listOf())
|
||||
val moduleFile = makeModuleFile(
|
||||
args.moduleName!!,
|
||||
isTest = false,
|
||||
outputDir = outputDir,
|
||||
sourcesToCompile = sourcesToCompile,
|
||||
commonSources = args.commonSources?.map(::File).orEmpty(),
|
||||
javaSourceRoots = javaSourceRoots,
|
||||
classpath = classpath,
|
||||
friendDirs = listOf()
|
||||
)
|
||||
val destination = args.destination
|
||||
args.destination = null
|
||||
args.buildFile = moduleFile.absolutePath
|
||||
|
||||
@@ -16,21 +16,25 @@
|
||||
|
||||
package org.jetbrains.kotlin.incremental
|
||||
|
||||
import org.jetbrains.kotlin.incremental.storage.version.CacheVersionManager
|
||||
import org.jetbrains.kotlin.incremental.storage.version.localCacheVersionManager
|
||||
import org.jetbrains.kotlin.incremental.storage.version.lookupsCacheVersionManager
|
||||
import java.io.File
|
||||
|
||||
internal const val STANDALONE_CACHE_VERSION = 2
|
||||
internal const val STANDALONE_VERSION_FILE_NAME = "standalone-ic-format-version.txt"
|
||||
|
||||
fun standaloneCacheVersion(dataRoot: File, enabled: Boolean): CacheVersion =
|
||||
customCacheVersion(STANDALONE_CACHE_VERSION, STANDALONE_VERSION_FILE_NAME, dataRoot, enabled)
|
||||
fun standaloneCacheVersionManager(dataRoot: File, enabled: Boolean): CacheVersionManager =
|
||||
customCacheVersionManager(STANDALONE_CACHE_VERSION, STANDALONE_VERSION_FILE_NAME, dataRoot, enabled)
|
||||
|
||||
fun customCacheVersion(version: Int, fileName: String, dataRoot: File, enabled: Boolean): CacheVersion =
|
||||
CacheVersion(ownVersion = version,
|
||||
versionFile = File(dataRoot, fileName),
|
||||
whenVersionChanged = CacheVersion.Action.REBUILD_ALL_KOTLIN,
|
||||
whenTurnedOn = CacheVersion.Action.REBUILD_ALL_KOTLIN,
|
||||
whenTurnedOff = CacheVersion.Action.REBUILD_ALL_KOTLIN,
|
||||
isEnabled = enabled)
|
||||
fun customCacheVersionManager(version: Int, fileName: String, dataRoot: File, enabled: Boolean): CacheVersionManager =
|
||||
CacheVersionManager(
|
||||
File(dataRoot, fileName),
|
||||
if (enabled) version else null
|
||||
)
|
||||
|
||||
fun commonCacheVersions(cachesDir: File, enabled: Boolean): List<CacheVersion> =
|
||||
listOf(normalCacheVersion(cachesDir, enabled), dataContainerCacheVersion(cachesDir, enabled))
|
||||
fun commonCacheVersionsManagers(cachesDir: File, enabled: Boolean): List<CacheVersionManager> =
|
||||
listOf(
|
||||
localCacheVersionManager(cachesDir, enabled),
|
||||
lookupsCacheVersionManager(cachesDir, enabled)
|
||||
)
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2010-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.incremental
|
||||
|
||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistory
|
||||
import org.jetbrains.kotlin.incremental.util.Either
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import java.io.File
|
||||
|
||||
internal fun getClasspathChanges(
|
||||
classpath: List<File>,
|
||||
changedFiles: ChangedFiles.Known,
|
||||
lastBuildInfo: BuildInfo,
|
||||
modulesApiHistory: ModulesApiHistory,
|
||||
reporter: ICReporter?
|
||||
): ChangesEither {
|
||||
val classpathSet = HashSet<File>()
|
||||
for (file in classpath) {
|
||||
when {
|
||||
file.isFile -> classpathSet.add(file)
|
||||
file.isDirectory -> file.walk().filterTo(classpathSet) { it.isFile }
|
||||
}
|
||||
}
|
||||
|
||||
val modifiedClasspath = changedFiles.modified.filterTo(HashSet()) { it in classpathSet }
|
||||
val removedClasspath = changedFiles.removed.filterTo(HashSet()) { it in classpathSet }
|
||||
|
||||
// todo: removed classes could be processed normally
|
||||
if (removedClasspath.isNotEmpty()) return ChangesEither.Unknown("Some files are removed from classpath $removedClasspath")
|
||||
|
||||
if (modifiedClasspath.isEmpty()) return ChangesEither.Known()
|
||||
|
||||
val lastBuildTS = lastBuildInfo.startTS
|
||||
|
||||
val symbols = HashSet<LookupSymbol>()
|
||||
val fqNames = HashSet<FqName>()
|
||||
|
||||
val historyFilesEither = modulesApiHistory.historyFilesForChangedFiles(modifiedClasspath)
|
||||
val historyFiles = when (historyFilesEither) {
|
||||
is Either.Success<Set<File>> -> historyFilesEither.value
|
||||
is Either.Error -> return ChangesEither.Unknown(historyFilesEither.reason)
|
||||
}
|
||||
|
||||
for (historyFile in historyFiles) {
|
||||
val allBuilds = BuildDiffsStorage.readDiffsFromFile(historyFile, reporter = reporter)
|
||||
?: return ChangesEither.Unknown("Could not read diffs from $historyFile")
|
||||
val (knownBuilds, newBuilds) = allBuilds.partition { it.ts <= lastBuildTS }
|
||||
if (knownBuilds.isEmpty()) {
|
||||
return ChangesEither.Unknown("No previously known builds for $historyFile")
|
||||
}
|
||||
|
||||
for (buildDiff in newBuilds) {
|
||||
if (!buildDiff.isIncremental) return ChangesEither.Unknown("Non-incremental build from dependency $historyFile")
|
||||
|
||||
val dirtyData = buildDiff.dirtyData
|
||||
symbols.addAll(dirtyData.dirtyLookupSymbols)
|
||||
fqNames.addAll(dirtyData.dirtyClassesFqNames)
|
||||
}
|
||||
}
|
||||
|
||||
return ChangesEither.Known(symbols, fqNames)
|
||||
}
|
||||
@@ -22,7 +22,7 @@ object EmptyModulesApiHistory : ModulesApiHistory {
|
||||
Either.Error("Multi-module IC is not configured")
|
||||
}
|
||||
|
||||
open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo) : ModulesApiHistory {
|
||||
abstract class ModulesApiHistoryBase(protected val modulesInfo: IncrementalModuleInfo) : ModulesApiHistory {
|
||||
protected val projectRootPath: Path = Paths.get(modulesInfo.projectRoot.absolutePath)
|
||||
private val dirToHistoryFileCache = HashMap<File, Set<File>>()
|
||||
|
||||
@@ -86,7 +86,11 @@ open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo
|
||||
return Either.Success(history)
|
||||
}
|
||||
|
||||
protected open fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
|
||||
protected abstract fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>>
|
||||
}
|
||||
|
||||
class ModulesApiHistoryJvm(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryBase(modulesInfo) {
|
||||
override fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
|
||||
val classListFile = modulesInfo.jarToClassListFile[jar] ?: return Either.Error("Unknown jar: $jar")
|
||||
if (!classListFile.isFile) return Either.Error("Class list file does not exist $classListFile")
|
||||
|
||||
@@ -109,7 +113,18 @@ open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo
|
||||
}
|
||||
}
|
||||
|
||||
class ModulesApiHistoryAndroid(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryJvm(modulesInfo) {
|
||||
class ModulesApiHistoryJs(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryBase(modulesInfo) {
|
||||
override fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
|
||||
val moduleEntry = modulesInfo.jarToModule[jar]
|
||||
|
||||
return when {
|
||||
moduleEntry != null -> Either.Success(setOf(moduleEntry.buildHistoryFile))
|
||||
else -> Either.Error("No module is found for jar $jar")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ModulesApiHistoryAndroid(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryBase(modulesInfo) {
|
||||
private val delegate = ModulesApiHistoryJvm(modulesInfo)
|
||||
|
||||
override fun historyFilesForChangedFiles(changedFiles: Set<File>): Either<Set<File>> {
|
||||
|
||||
@@ -361,6 +361,11 @@ public class IncrementalJsCompilerRunnerTestGenerated extends AbstractIncrementa
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/ourClassReferenced/");
|
||||
}
|
||||
|
||||
@TestMetadata("overloadInlined")
|
||||
public void testOverloadInlined() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/overloadInlined/");
|
||||
}
|
||||
|
||||
@TestMetadata("packageConstantChanged")
|
||||
public void testPackageConstantChanged() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/packageConstantChanged/");
|
||||
@@ -551,6 +556,11 @@ public class IncrementalJsCompilerRunnerTestGenerated extends AbstractIncrementa
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/returnTypeChanged/");
|
||||
}
|
||||
|
||||
@TestMetadata("secondaryConstructorInlined")
|
||||
public void testSecondaryConstructorInlined() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/secondaryConstructorInlined/");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleClassDependency")
|
||||
public void testSimpleClassDependency() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/simpleClassDependency/");
|
||||
|
||||
@@ -361,6 +361,11 @@ public class IncrementalJvmCompilerRunnerTestGenerated extends AbstractIncrement
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/ourClassReferenced/");
|
||||
}
|
||||
|
||||
@TestMetadata("overloadInlined")
|
||||
public void testOverloadInlined() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/overloadInlined/");
|
||||
}
|
||||
|
||||
@TestMetadata("packageConstantChanged")
|
||||
public void testPackageConstantChanged() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/packageConstantChanged/");
|
||||
@@ -551,6 +556,11 @@ public class IncrementalJvmCompilerRunnerTestGenerated extends AbstractIncrement
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/returnTypeChanged/");
|
||||
}
|
||||
|
||||
@TestMetadata("secondaryConstructorInlined")
|
||||
public void testSecondaryConstructorInlined() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/secondaryConstructorInlined/");
|
||||
}
|
||||
|
||||
@TestMetadata("simpleClassDependency")
|
||||
public void testSimpleClassDependency() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/pureKotlin/simpleClassDependency/");
|
||||
|
||||
@@ -58,7 +58,8 @@ class ModulesApiHistoryAndroidTest {
|
||||
projectRoot = projectRoot,
|
||||
dirToModule = mapOf(appKotlinDestination to appEntry, libKotlinDestination to libEntry),
|
||||
nameToModules = mapOf("app" to setOf(appEntry), "lib" to setOf(libEntry)),
|
||||
jarToClassListFile = mapOf()
|
||||
jarToClassListFile = mapOf(),
|
||||
jarToModule = mapOf()
|
||||
)
|
||||
|
||||
androidHistory = ModulesApiHistoryAndroid(info)
|
||||
|
||||
@@ -716,6 +716,9 @@ public final class String : kotlin.Comparable<kotlin.String>, kotlin.CharSequenc
|
||||
public open override /*1*/ fun compareTo(/*0*/ other: kotlin.String): kotlin.Int
|
||||
public open override /*1*/ fun get(/*0*/ index: kotlin.Int): kotlin.Char
|
||||
public final operator fun plus(/*0*/ other: kotlin.Any?): kotlin.String
|
||||
@kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public open fun strip(): kotlin.String!
|
||||
@kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public open fun stripLeading(): kotlin.String!
|
||||
@kotlin.Deprecated(level = DeprecationLevel.WARNING, message = "This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version", replaceWith = kotlin.ReplaceWith(expression = "", imports = {})) public open fun stripTrailing(): kotlin.String!
|
||||
public open override /*1*/ fun subSequence(/*0*/ startIndex: kotlin.Int, /*1*/ endIndex: kotlin.Int): kotlin.CharSequence
|
||||
|
||||
public companion object Companion {
|
||||
|
||||
2
compiler/testData/cli/js/jsExtraHelp.out
vendored
2
compiler/testData/cli/js/jsExtraHelp.out
vendored
@@ -4,6 +4,8 @@ where advanced options include:
|
||||
-Xfriend-modules-disabled Disable internal declaration export
|
||||
-Xtyped-arrays Translate primitive arrays to JS typed arrays
|
||||
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
|
||||
-Xcommon-sources=<path> Sources of the common module that need to be compiled together with this module in the multi-platform mode.
|
||||
Should be a subset of sources passed as free arguments
|
||||
-Xcoroutines={enable|warn|error}
|
||||
Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
|
||||
-Xdump-perf=<path> Dump detailed performance statistics to the specified file
|
||||
|
||||
2
compiler/testData/cli/jvm/extraHelp.out
vendored
2
compiler/testData/cli/jvm/extraHelp.out
vendored
@@ -60,6 +60,8 @@ where advanced options include:
|
||||
-Xuse-old-class-files-reading Use old class files reading implementation (may slow down the build and should be used in case of problems with the new implementation)
|
||||
-Xuse-type-table Use type table in metadata serialization
|
||||
-Xallow-kotlin-package Allow compiling code in package 'kotlin' and allow not requiring kotlin.stdlib in module-info
|
||||
-Xcommon-sources=<path> Sources of the common module that need to be compiled together with this module in the multi-platform mode.
|
||||
Should be a subset of sources passed as free arguments
|
||||
-Xcoroutines={enable|warn|error}
|
||||
Enable coroutines or report warnings or errors on declarations and use sites of 'suspend' modifier
|
||||
-Xdump-perf=<path> Dump detailed performance statistics to the specified file
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
error: incompatible classes were found in dependencies. Remove them from the classpath or use '-Xskip-metadata-version-check' to suppress errors
|
||||
compiler/testData/cli/jvm/wrongAbiVersionLib/bin/META-INF/main.kotlin_module: error: module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 0.30.0, expected version is $ABI_VERSION$.
|
||||
compiler/testData/cli/jvm/wrongAbiVersion.kt:3:12: error: class 'ClassWithWrongAbiVersion' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 0.30.0, expected version is $ABI_VERSION$.
|
||||
The class is loaded from $TESTDATA_DIR$/wrongAbiVersionLib/bin/ClassWithWrongAbiVersion.class
|
||||
fun foo(x: ClassWithWrongAbiVersion) {
|
||||
@@ -10,4 +11,4 @@ compiler/testData/cli/jvm/wrongAbiVersion.kt:6:7: error: unresolved reference. N
|
||||
public fun String.replaceIndent(newIndent: String = ...): String defined in kotlin.text
|
||||
1.replaceIndent(2, 3)
|
||||
^
|
||||
COMPILATION_ERROR
|
||||
COMPILATION_ERROR
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
$TESTDATA_DIR$/wrongAbiVersionNoErrors.kt
|
||||
-classpath
|
||||
$TESTDATA_DIR$/wrongAbiVersionLib/bin
|
||||
-d
|
||||
$TEMP_DIR$
|
||||
@@ -1,7 +0,0 @@
|
||||
// This should not compile because there are usages of symbols with the wrong ABI version!
|
||||
|
||||
import wrong.ClassWithInnerLambda
|
||||
|
||||
fun happy(): Int {
|
||||
return 2 + 2
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
error: incompatible classes were found in dependencies. Remove them from the classpath or use '-Xskip-metadata-version-check' to suppress errors
|
||||
compiler/testData/cli/jvm/wrongAbiVersionNoErrors.kt:3:14: error: class 'wrong.ClassWithInnerLambda' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 0.30.0, expected version is $ABI_VERSION$.
|
||||
The class is loaded from $TESTDATA_DIR$/wrongAbiVersionLib/bin/wrong/ClassWithInnerLambda.class
|
||||
import wrong.ClassWithInnerLambda
|
||||
^
|
||||
COMPILATION_ERROR
|
||||
@@ -23,6 +23,8 @@ actual annotation class A(actual val x: Int)
|
||||
// MODULE: main(library)
|
||||
// FILE: main.kt
|
||||
|
||||
@file:Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE") // TODO: support common sources in the test infrastructure
|
||||
|
||||
package usage
|
||||
|
||||
import a.A
|
||||
|
||||
@@ -9,6 +9,8 @@ expect annotation class Anno(val s: String)
|
||||
|
||||
// FILE: jvm.kt
|
||||
|
||||
@file:Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE") // TODO: support common sources in the test infrastructure
|
||||
|
||||
import java.lang.reflect.AnnotatedElement
|
||||
|
||||
@Anno("Foo")
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_RUNTIME
|
||||
|
||||
@file:Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE") // TODO: support common sources in the test infrastructure
|
||||
|
||||
@OptionalExpectation
|
||||
expect annotation class Anno(val s: String)
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
error: incompatible classes were found in dependencies. Remove them from the classpath or use '-Xskip-metadata-version-check' to suppress errors
|
||||
$TMP_DIR$/library-after.jar!/META-INF/main.kotlin_module: error: module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersion/source.kt:5:16: error: class 'a.A' was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
|
||||
The class is loaded from $TMP_DIR$/library-after.jar!/a/A.class
|
||||
fun baz(param: A, nested: A.Nested) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
$TMP_DIR$/library-after.jar!/META-INF/main.kotlin_module: error: module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMetadata/source.kt:12:13: error: unresolved reference: foo
|
||||
val x = foo()
|
||||
^
|
||||
@@ -10,4 +11,4 @@ compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMeta
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMetadata/source.kt:15:12: error: unresolved reference: TA
|
||||
val z: TA = ""
|
||||
^
|
||||
COMPILATION_ERROR
|
||||
COMPILATION_ERROR
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
$TMP_DIR$/library-after.jar!/META-INF/main.kotlin_module: error: module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 42.0.0, expected version is $ABI_VERSION$.
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMetadata2/source.kt:12:13: error: unresolved reference: foo
|
||||
val x = foo()
|
||||
^
|
||||
@@ -10,4 +11,4 @@ compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMeta
|
||||
compiler/testData/compileKotlinAgainstCustomBinaries/wrongMetadataVersionBadMetadata2/source.kt:15:12: error: unresolved reference: TA
|
||||
val z: TA = ""
|
||||
^
|
||||
COMPILATION_ERROR
|
||||
COMPILATION_ERROR
|
||||
|
||||
@@ -14,6 +14,9 @@ expect annotation class B(val s: String)
|
||||
actual annotation class A(actual val x: Int)
|
||||
|
||||
// FILE: B.kt
|
||||
|
||||
@file:Suppress("OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE") // TODO: support common sources in the test infrastructure
|
||||
|
||||
import a.A
|
||||
import a.B
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
11
compiler/testData/diagnostics/testWithModifiedMockJdk/newStringMethods.kt
vendored
Normal file
11
compiler/testData/diagnostics/testWithModifiedMockJdk/newStringMethods.kt
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// !CHECK_TYPE
|
||||
// SKIP_TXT
|
||||
|
||||
fun foo(s: String) {
|
||||
s.isBlank()
|
||||
s.lines().checkType { _<List<String>>() }
|
||||
s.repeat(1)
|
||||
|
||||
// We don't have `strip` extension, so leave it for a while in gray list
|
||||
s.<!DEPRECATION!>strip<!>()
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
object Foo
|
||||
object Bar
|
||||
object Baz
|
||||
|
||||
operator fun Foo.provideDelegate(receiver: Any?, property: KProperty<*>) = this
|
||||
operator fun Bar.provideDelegate(receiver: Any?, property: KProperty<*>) = this
|
||||
|
||||
operator fun Foo.getValue(nothing: Any?, property: KProperty<*>): Any = TODO()
|
||||
operator fun Bar.getValue(nothing: Any?, property: KProperty<*>): Any = TODO()
|
||||
operator fun Baz.getValue(nothing: Any?, property: KProperty<*>): Any = TODO()
|
||||
|
||||
fun test() {
|
||||
val bar by Baz
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package
|
||||
|
||||
public fun test(): kotlin.Unit
|
||||
public operator fun Bar.getValue(/*0*/ nothing: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): kotlin.Any
|
||||
public operator fun Baz.getValue(/*0*/ nothing: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): kotlin.Any
|
||||
public operator fun Foo.getValue(/*0*/ nothing: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): kotlin.Any
|
||||
public operator fun Bar.provideDelegate(/*0*/ receiver: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): Bar
|
||||
public operator fun Foo.provideDelegate(/*0*/ receiver: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): Foo
|
||||
|
||||
public object Bar {
|
||||
private constructor Bar()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object Baz {
|
||||
private constructor Baz()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public object Foo {
|
||||
private constructor Foo()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
// !WITH_NEW_INFERENCE
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class A {
|
||||
val c: Int by <!NI;DELEGATE_SPECIAL_FUNCTION_AMBIGUITY, OI;DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>Delegate()<!>
|
||||
val c: Int by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!>Delegate()<!>
|
||||
}
|
||||
|
||||
class Delegate {
|
||||
|
||||
BIN
compiler/testData/mockJDKModified/rt.jar
vendored
BIN
compiler/testData/mockJDKModified/rt.jar
vendored
Binary file not shown.
@@ -39,11 +39,20 @@ compiler/testData/multiplatform/optionalExpectationIncorrectUse/common.kt:19:20:
|
||||
@InOtherAnnotation(A())
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:1:24: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
fun useInReturnType(): A? = null
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:1:24: error: declaration annotated with '@OptionalExpectation' can only be used in common module sources
|
||||
fun useInReturnType(): A? = null
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:3:43: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
annotation class AnotherAnnotation(val a: A)
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:3:43: error: declaration annotated with '@OptionalExpectation' can only be used in common module sources
|
||||
annotation class AnotherAnnotation(val a: A)
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:5:20: error: declaration annotated with '@OptionalExpectation' can only be used inside an annotation entry
|
||||
@AnotherAnnotation(A())
|
||||
^
|
||||
compiler/testData/multiplatform/optionalExpectationIncorrectUse/jvm.kt:5:20: error: declaration annotated with '@OptionalExpectation' can only be used in common module sources
|
||||
@AnotherAnnotation(A())
|
||||
^
|
||||
|
||||
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
|
||||
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation;
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity;
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
|
||||
@@ -610,11 +611,11 @@ public class KotlinTestUtils {
|
||||
}
|
||||
|
||||
public static void resolveAllKotlinFiles(KotlinCoreEnvironment environment) throws IOException {
|
||||
List<String> paths = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
|
||||
if (paths.isEmpty()) return;
|
||||
List<KotlinSourceRoot> roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
|
||||
if (roots.isEmpty()) return;
|
||||
List<KtFile> ktFiles = new ArrayList<>();
|
||||
for (String path : paths) {
|
||||
File file = new File(path);
|
||||
for (KotlinSourceRoot root : roots) {
|
||||
File file = new File(root.getPath());
|
||||
if (file.isFile()) {
|
||||
ktFiles.add(loadJetFile(environment.getProject(), file));
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
|
||||
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation;
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity;
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
|
||||
@@ -609,11 +610,11 @@ public class KotlinTestUtils {
|
||||
}
|
||||
|
||||
public static void resolveAllKotlinFiles(KotlinCoreEnvironment environment) throws IOException {
|
||||
List<String> paths = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
|
||||
if (paths.isEmpty()) return;
|
||||
List<KotlinSourceRoot> roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
|
||||
if (roots.isEmpty()) return;
|
||||
List<KtFile> ktFiles = new ArrayList<>();
|
||||
for (String path : paths) {
|
||||
File file = new File(path);
|
||||
for (KotlinSourceRoot root : roots) {
|
||||
File file = new File(root.getPath());
|
||||
if (file.isFile()) {
|
||||
ktFiles.add(loadJetFile(environment.getProject(), file));
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
|
||||
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation;
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity;
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
|
||||
@@ -609,11 +610,11 @@ public class KotlinTestUtils {
|
||||
}
|
||||
|
||||
public static void resolveAllKotlinFiles(KotlinCoreEnvironment environment) throws IOException {
|
||||
List<String> paths = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
|
||||
if (paths.isEmpty()) return;
|
||||
List<KotlinSourceRoot> roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
|
||||
if (roots.isEmpty()) return;
|
||||
List<KtFile> ktFiles = new ArrayList<>();
|
||||
for (String path : paths) {
|
||||
File file = new File(path);
|
||||
for (KotlinSourceRoot root : roots) {
|
||||
File file = new File(root.getPath());
|
||||
if (file.isFile()) {
|
||||
ktFiles.add(loadJetFile(environment.getProject(), file));
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.checkers.CompilerTestLanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys;
|
||||
import org.jetbrains.kotlin.cli.common.config.ContentRootsKt;
|
||||
import org.jetbrains.kotlin.cli.common.config.KotlinSourceRoot;
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation;
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity;
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector;
|
||||
@@ -609,11 +610,11 @@ public class KotlinTestUtils {
|
||||
}
|
||||
|
||||
public static void resolveAllKotlinFiles(KotlinCoreEnvironment environment) throws IOException {
|
||||
List<String> paths = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
|
||||
if (paths.isEmpty()) return;
|
||||
List<KotlinSourceRoot> roots = ContentRootsKt.getKotlinSourceRoots(environment.getConfiguration());
|
||||
if (roots.isEmpty()) return;
|
||||
List<KtFile> ktFiles = new ArrayList<>();
|
||||
for (String path : paths) {
|
||||
File file = new File(path);
|
||||
for (KotlinSourceRoot root : roots) {
|
||||
File file = new File(root.getPath());
|
||||
if (file.isFile()) {
|
||||
ktFiles.add(loadJetFile(environment.getProject(), file));
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ public enum TestJdkKind {
|
||||
MOCK_JDK,
|
||||
// Differs from common mock JDK only by one additional 'nonExistingMethod' in Collection and constructor from Double in Throwable
|
||||
// It's needed to test the way we load additional built-ins members that neither in black nor white lists
|
||||
// Also, now it contains new methods in java.lang.String introduced in JDK 11
|
||||
MODIFIED_MOCK_JDK,
|
||||
// JDK found at $JDK_16
|
||||
FULL_JDK_6,
|
||||
|
||||
@@ -57,8 +57,13 @@ class AdditionalBuiltInsMembersSignatureListsTest : KotlinTestWithEnvironment()
|
||||
|
||||
val scope = classDescriptor.unsubstitutedMemberScope
|
||||
|
||||
val lateJdkSignatures = LATE_JDK_SIGNATURES[internalName] ?: emptySet()
|
||||
|
||||
jvmDescriptors.forEach {
|
||||
jvmDescriptor ->
|
||||
|
||||
if (jvmDescriptor in lateJdkSignatures) return@forEach
|
||||
|
||||
val stringName = jvmDescriptor.split("(")[0]
|
||||
val functions =
|
||||
if (stringName == "<init>")
|
||||
@@ -72,4 +77,8 @@ class AdditionalBuiltInsMembersSignatureListsTest : KotlinTestWithEnvironment()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val LATE_JDK_SIGNATURES = mapOf(
|
||||
"java/lang/String" to setOf("isBlank()Z", "lines()Ljava/util/stream/Stream;", "repeat(I)Ljava/lang/String;")
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,11 @@ public class DiagnosticsWithModifiedMockJdkTestGenerated extends AbstractDiagnos
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/testWithModifiedMockJdk"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("newStringMethods.kt")
|
||||
public void testNewStringMethods() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testWithModifiedMockJdk/newStringMethods.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("notConsideredMethod.kt")
|
||||
public void testNotConsideredMethod() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testWithModifiedMockJdk/notConsideredMethod.kt");
|
||||
|
||||
@@ -5683,6 +5683,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/noOperatorModifierOnProvideDelegate.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("overloadResolutionForSeveralProvideDelegates.kt")
|
||||
public void testOverloadResolutionForSeveralProvideDelegates() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/overloadResolutionForSeveralProvideDelegates.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("provideDelegateOperatorDeclaration.kt")
|
||||
public void testProvideDelegateOperatorDeclaration() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateOperatorDeclaration.kt");
|
||||
|
||||
@@ -5683,6 +5683,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/noOperatorModifierOnProvideDelegate.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("overloadResolutionForSeveralProvideDelegates.kt")
|
||||
public void testOverloadResolutionForSeveralProvideDelegates() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/overloadResolutionForSeveralProvideDelegates.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("provideDelegateOperatorDeclaration.kt")
|
||||
public void testProvideDelegateOperatorDeclaration() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateOperatorDeclaration.kt");
|
||||
|
||||
@@ -586,11 +586,6 @@ public class CliTestGenerated extends AbstractCliTest {
|
||||
runTest("compiler/testData/cli/jvm/wrongAbiVersion.args");
|
||||
}
|
||||
|
||||
@TestMetadata("wrongAbiVersionNoErrors.args")
|
||||
public void testWrongAbiVersionNoErrors() throws Exception {
|
||||
runTest("compiler/testData/cli/jvm/wrongAbiVersionNoErrors.args");
|
||||
}
|
||||
|
||||
@TestMetadata("wrongArgument.args")
|
||||
public void testWrongArgument() throws Exception {
|
||||
runTest("compiler/testData/cli/jvm/wrongArgument.args");
|
||||
|
||||
@@ -50,7 +50,8 @@ class JvmModuleProtoBufTest : KtUsefulTestCase() {
|
||||
File(tmpdir, "META-INF/$moduleName.${ModuleMapping.MAPPING_FILE_EXT}").readBytes(), "test",
|
||||
CompilerDeserializationConfiguration(
|
||||
LanguageVersionSettingsImpl(loadWith, ApiVersion.createByLanguageVersion(loadWith))
|
||||
)
|
||||
),
|
||||
::error
|
||||
)
|
||||
val result = buildString {
|
||||
for (annotationClassId in mapping.moduleData.annotations) {
|
||||
|
||||
@@ -55,24 +55,24 @@ abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
|
||||
|
||||
val result = buildString {
|
||||
appendln("-- Common --")
|
||||
appendln(K2MetadataCompiler().compile(listOf(commonSrc), "-d", commonDest, *optionalStdlibCommon))
|
||||
appendln(K2MetadataCompiler().compile(commonSrc, null, "-d", commonDest, *optionalStdlibCommon))
|
||||
|
||||
if (jvmSrc != null) {
|
||||
appendln()
|
||||
appendln("-- JVM --")
|
||||
appendln(K2JVMCompiler().compileBothWays(commonSrc, jvmSrc, "-d", jvmDest!!))
|
||||
appendln(K2JVMCompiler().compile(jvmSrc, commonSrc, "-d", jvmDest!!))
|
||||
}
|
||||
|
||||
if (jsSrc != null) {
|
||||
appendln()
|
||||
appendln("-- JS --")
|
||||
appendln(K2JSCompiler().compileBothWays(commonSrc, jsSrc, "-output", jsDest!!))
|
||||
appendln(K2JSCompiler().compile(jsSrc, commonSrc, "-output", jsDest!!))
|
||||
}
|
||||
|
||||
if (common2Src != null) {
|
||||
appendln()
|
||||
appendln("-- Common (2) --")
|
||||
appendln(K2MetadataCompiler().compile(listOf(common2Src), "-d", common2Dest!!, "-cp", commonDest, *optionalStdlibCommon))
|
||||
appendln(K2MetadataCompiler().compile(common2Src, null, "-d", common2Dest!!, "-cp", commonDest, *optionalStdlibCommon))
|
||||
}
|
||||
|
||||
if (jvm2Src != null) {
|
||||
@@ -80,7 +80,7 @@ abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
|
||||
appendln("-- JVM (2) --")
|
||||
appendln(
|
||||
K2JVMCompiler().compile(
|
||||
listOf(jvm2Src), "-d", jvm2Dest!!,
|
||||
jvm2Src, common2Src, "-d", jvm2Dest!!,
|
||||
"-cp", listOfNotNull(commonDest, common2Dest, jvmDest).joinToString(File.pathSeparator)
|
||||
)
|
||||
)
|
||||
@@ -100,28 +100,12 @@ abstract class AbstractMultiPlatformIntegrationTest : KtUsefulTestCase() {
|
||||
}?.toFile() ?: error("kotlin-stdlib-common is not found in $stdlibCommonLibsDir")
|
||||
}
|
||||
|
||||
private fun CLICompiler<*>.compileBothWays(commonSource: File, platformSource: File, vararg mainArguments: String): String {
|
||||
val configurations = listOf(
|
||||
listOf(platformSource, commonSource),
|
||||
listOf(commonSource, platformSource)
|
||||
)
|
||||
|
||||
val (platformFirst, commonFirst) = configurations.map { compile(it, *mainArguments) }
|
||||
|
||||
if (platformFirst != commonFirst) {
|
||||
assertEquals(
|
||||
"Compilation results are different when compiling [platform-specific, common] compared to when compiling [common, platform-specific]",
|
||||
"// Compiling [platform-specific, common]\n\n$platformFirst",
|
||||
"// Compiling [common, platform-specific]\n\n$commonFirst"
|
||||
)
|
||||
}
|
||||
return platformFirst
|
||||
}
|
||||
|
||||
private fun CLICompiler<*>.compile(sources: List<File>, vararg mainArguments: String): String = buildString {
|
||||
private fun CLICompiler<*>.compile(sources: File, commonSources: File?, vararg mainArguments: String): String = buildString {
|
||||
val (output, exitCode) = AbstractCliTest.executeCompilerGrabOutput(
|
||||
this@compile,
|
||||
sources.map(File::getAbsolutePath) + listOf("-Xmulti-platform") + mainArguments + loadExtraArguments(sources)
|
||||
listOfNotNull(sources.absolutePath, commonSources?.absolutePath, commonSources?.absolutePath?.let("-Xcommon-sources="::plus)) +
|
||||
"-Xmulti-platform" + mainArguments +
|
||||
loadExtraArguments(listOfNotNull(sources, commonSources))
|
||||
)
|
||||
appendln("Exit code: $exitCode")
|
||||
appendln("Output:")
|
||||
|
||||
@@ -17,7 +17,7 @@ dependencies {
|
||||
sourceSets {
|
||||
"main" {
|
||||
projectDefault()
|
||||
resources.srcDir(File(rootDir, "resources")).apply { include("**") }
|
||||
resources.srcDir(File(rootDir, "resources"))
|
||||
}
|
||||
"test" {}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,8 @@ interface Module {
|
||||
|
||||
fun getSourceFiles(): List<String>
|
||||
|
||||
fun getCommonSourceFiles(): List<String>
|
||||
|
||||
fun getClasspathRoots(): List<String>
|
||||
|
||||
fun getJavaSourceRoots(): List<JavaRootPath>
|
||||
|
||||
@@ -371,7 +371,8 @@ open class JvmBuiltInsSettings(
|
||||
"startsWith(Ljava/lang/String;I)Z", "startsWith(Ljava/lang/String;)Z", "substring(II)Ljava/lang/String;",
|
||||
"substring(I)Ljava/lang/String;", "toCharArray()[C", "toLowerCase()Ljava/lang/String;",
|
||||
"toLowerCase(Ljava/util/Locale;)Ljava/lang/String;", "toUpperCase()Ljava/lang/String;",
|
||||
"toUpperCase(Ljava/util/Locale;)Ljava/lang/String;", "trim()Ljava/lang/String;"
|
||||
"toUpperCase(Ljava/util/Locale;)Ljava/lang/String;", "trim()Ljava/lang/String;",
|
||||
"isBlank()Z", "lines()Ljava/util/stream/Stream;", "repeat(I)Ljava/lang/String;"
|
||||
) +
|
||||
|
||||
inJavaLang("Double", "isInfinite()Z", "isNaN()Z") +
|
||||
|
||||
@@ -5,17 +5,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.load.kotlin
|
||||
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
|
||||
fun ModuleMapping.Companion.loadModuleMapping(
|
||||
bytes: ByteArray?,
|
||||
debugName: String,
|
||||
configuration: DeserializationConfiguration
|
||||
configuration: DeserializationConfiguration,
|
||||
reportIncompatibleVersionError: (JvmMetadataVersion) -> Unit
|
||||
): ModuleMapping =
|
||||
loadModuleMapping(
|
||||
bytes,
|
||||
debugName,
|
||||
configuration.skipMetadataVersionCheck,
|
||||
configuration.isJvmPackageNameSupported
|
||||
configuration.isJvmPackageNameSupported,
|
||||
reportIncompatibleVersionError
|
||||
)
|
||||
|
||||
@@ -18,6 +18,7 @@ package kotlin.reflect.jvm.internal.components
|
||||
|
||||
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
|
||||
import org.jetbrains.kotlin.load.kotlin.loadModuleMapping
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.ModuleMapping
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
@@ -45,11 +46,20 @@ class RuntimePackagePartProvider(private val classLoader: ClassLoader) : Package
|
||||
for (resource in resources) {
|
||||
try {
|
||||
resource.openStream()?.use { stream ->
|
||||
val mapping = ModuleMapping.loadModuleMapping(stream.readBytes(), resourcePath, DeserializationConfiguration.Default)
|
||||
val mapping = ModuleMapping.loadModuleMapping(
|
||||
stream.readBytes(), resourcePath, DeserializationConfiguration.Default
|
||||
) { version ->
|
||||
throw UnsupportedOperationException(
|
||||
"Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is $version, " +
|
||||
"expected version is ${JvmMetadataVersion.INSTANCE}. Please update Kotlin to the latest version"
|
||||
)
|
||||
}
|
||||
for ((packageFqName, parts) in mapping.packageFqName2Parts) {
|
||||
packageParts.getOrPut(packageFqName) { linkedSetOf() }.addAll(parts.parts)
|
||||
}
|
||||
}
|
||||
} catch (e: UnsupportedOperationException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
// TODO: do not swallow this exception?
|
||||
}
|
||||
|
||||
@@ -33,7 +33,8 @@ class ModuleMapping private constructor(
|
||||
bytes: ByteArray?,
|
||||
debugName: String,
|
||||
skipMetadataVersionCheck: Boolean,
|
||||
isJvmPackageNameSupported: Boolean
|
||||
isJvmPackageNameSupported: Boolean,
|
||||
reportIncompatibleVersionError: (JvmMetadataVersion) -> Unit
|
||||
): ModuleMapping {
|
||||
if (bytes == null) {
|
||||
return EMPTY
|
||||
@@ -47,47 +48,47 @@ class ModuleMapping private constructor(
|
||||
return CORRUPTED
|
||||
}
|
||||
|
||||
if (skipMetadataVersionCheck || JvmMetadataVersion(*versionNumber).isCompatible()) {
|
||||
val moduleProto = JvmModuleProtoBuf.Module.parseFrom(stream) ?: return EMPTY
|
||||
val result = linkedMapOf<String, PackageParts>()
|
||||
|
||||
for (proto in moduleProto.packagePartsList) {
|
||||
val packageFqName = proto.packageFqName
|
||||
val packageParts = result.getOrPut(packageFqName) { PackageParts(packageFqName) }
|
||||
|
||||
for ((index, partShortName) in proto.shortClassNameList.withIndex()) {
|
||||
val multifileFacadeId = proto.multifileFacadeShortNameIdList.getOrNull(index)?.minus(1)
|
||||
val facadeShortName = multifileFacadeId?.let(proto.multifileFacadeShortNameList::getOrNull)
|
||||
val facadeInternalName = facadeShortName?.let { internalNameOf(packageFqName, it) }
|
||||
packageParts.addPart(internalNameOf(packageFqName, partShortName), facadeInternalName)
|
||||
}
|
||||
|
||||
if (isJvmPackageNameSupported) {
|
||||
for ((index, partShortName) in proto.classWithJvmPackageNameShortNameList.withIndex()) {
|
||||
val packageId = proto.classWithJvmPackageNamePackageIdList.getOrNull(index)
|
||||
?: proto.classWithJvmPackageNamePackageIdList.lastOrNull()
|
||||
?: continue
|
||||
val jvmPackageName = moduleProto.jvmPackageNameList.getOrNull(packageId) ?: continue
|
||||
packageParts.addPart(internalNameOf(jvmPackageName, partShortName), null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (proto in moduleProto.metadataPartsList) {
|
||||
val packageParts = result.getOrPut(proto.packageFqName) { PackageParts(proto.packageFqName) }
|
||||
proto.shortClassNameList.forEach(packageParts::addMetadataPart)
|
||||
}
|
||||
|
||||
// TODO: read arguments of module annotations
|
||||
val nameResolver = NameResolverImpl(moduleProto.stringTable, moduleProto.qualifiedNameTable)
|
||||
val annotations = moduleProto.annotationList.map { proto -> nameResolver.getQualifiedClassName(proto.id) }
|
||||
|
||||
return ModuleMapping(result, BinaryModuleData(annotations), debugName)
|
||||
} else {
|
||||
// TODO: consider reporting "incompatible ABI version" error for package parts
|
||||
val version = JvmMetadataVersion(*versionNumber)
|
||||
if (!skipMetadataVersionCheck && !version.isCompatible()) {
|
||||
reportIncompatibleVersionError(version)
|
||||
return EMPTY
|
||||
}
|
||||
|
||||
return EMPTY
|
||||
val moduleProto = JvmModuleProtoBuf.Module.parseFrom(stream) ?: return EMPTY
|
||||
val result = linkedMapOf<String, PackageParts>()
|
||||
|
||||
for (proto in moduleProto.packagePartsList) {
|
||||
val packageFqName = proto.packageFqName
|
||||
val packageParts = result.getOrPut(packageFqName) { PackageParts(packageFqName) }
|
||||
|
||||
for ((index, partShortName) in proto.shortClassNameList.withIndex()) {
|
||||
val multifileFacadeId = proto.multifileFacadeShortNameIdList.getOrNull(index)?.minus(1)
|
||||
val facadeShortName = multifileFacadeId?.let(proto.multifileFacadeShortNameList::getOrNull)
|
||||
val facadeInternalName = facadeShortName?.let { internalNameOf(packageFqName, it) }
|
||||
packageParts.addPart(internalNameOf(packageFqName, partShortName), facadeInternalName)
|
||||
}
|
||||
|
||||
if (isJvmPackageNameSupported) {
|
||||
for ((index, partShortName) in proto.classWithJvmPackageNameShortNameList.withIndex()) {
|
||||
val packageId = proto.classWithJvmPackageNamePackageIdList.getOrNull(index)
|
||||
?: proto.classWithJvmPackageNamePackageIdList.lastOrNull()
|
||||
?: continue
|
||||
val jvmPackageName = moduleProto.jvmPackageNameList.getOrNull(packageId) ?: continue
|
||||
packageParts.addPart(internalNameOf(jvmPackageName, partShortName), null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (proto in moduleProto.metadataPartsList) {
|
||||
val packageParts = result.getOrPut(proto.packageFqName) { PackageParts(proto.packageFqName) }
|
||||
proto.shortClassNameList.forEach(packageParts::addMetadataPart)
|
||||
}
|
||||
|
||||
// TODO: read arguments of module annotations
|
||||
val nameResolver = NameResolverImpl(moduleProto.stringTable, moduleProto.qualifiedNameTable)
|
||||
val annotations = moduleProto.annotationList.map { proto -> nameResolver.getQualifiedClassName(proto.id) }
|
||||
|
||||
return ModuleMapping(result, BinaryModuleData(annotations), debugName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea
|
||||
|
||||
import com.intellij.ide.IconProvider
|
||||
import com.intellij.openapi.project.DumbAware
|
||||
import com.intellij.openapi.project.IndexNotReadyException
|
||||
import com.intellij.openapi.util.Iconable
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
@@ -52,7 +53,15 @@ class KotlinIconProvider : IconProvider(), DumbAware {
|
||||
val result = psiElement.getBaseIcon()
|
||||
if (flags and Iconable.ICON_FLAG_VISIBILITY > 0 && result != null && (psiElement is KtModifierListOwner && psiElement !is KtClassInitializer)) {
|
||||
val list = psiElement.modifierList
|
||||
return createRowIcon(result.addExpectActualMarker(psiElement), getVisibilityIcon(list))
|
||||
val visibilityIcon = getVisibilityIcon(list)
|
||||
|
||||
val withExpectedActual: Icon = try {
|
||||
result.addExpectActualMarker(psiElement)
|
||||
} catch (indexNotReady: IndexNotReadyException) {
|
||||
result
|
||||
}
|
||||
|
||||
createRowIcon(withExpectedActual, visibilityIcon)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.intellij.openapi.roots.impl.libraries.LibraryEx
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import com.intellij.openapi.util.ModificationTracker
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.ResolveScopeEnlarger
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.psi.util.CachedValueProvider
|
||||
import com.intellij.util.PathUtil
|
||||
@@ -58,6 +59,14 @@ interface IdeaModuleInfo : org.jetbrains.kotlin.idea.caches.resolve.IdeaModuleIn
|
||||
override fun dependencies(): List<IdeaModuleInfo>
|
||||
}
|
||||
|
||||
private fun enlargedSearchScope(searchScope: GlobalSearchScope, moduleFile: VirtualFile?): GlobalSearchScope {
|
||||
if (moduleFile == null) return searchScope
|
||||
return ResolveScopeEnlarger.EP_NAME.extensions.fold(searchScope) { scope, enlarger ->
|
||||
val extra = enlarger.getAdditionalResolveScope(moduleFile, scope.project)
|
||||
if (extra != null) scope.union(extra) else scope
|
||||
}
|
||||
}
|
||||
|
||||
private fun orderEntryToModuleInfo(project: Project, orderEntry: OrderEntry, forProduction: Boolean): List<IdeaModuleInfo> {
|
||||
fun Module.toInfos() = correspondingModuleInfos().filter { !forProduction || it is ModuleProductionSourceInfo }
|
||||
|
||||
@@ -161,7 +170,7 @@ data class ModuleProductionSourceInfo internal constructor(
|
||||
|
||||
override val stableName: Name = module.getStableName()
|
||||
|
||||
override fun contentScope(): GlobalSearchScope = ModuleProductionSourceScope(module)
|
||||
override fun contentScope(): GlobalSearchScope = enlargedSearchScope(ModuleProductionSourceScope(module), module.moduleFile)
|
||||
|
||||
override fun <T> createCachedValueProvider(f: () -> CachedValueProvider.Result<T>) = CachedValueProvider { f() }
|
||||
}
|
||||
@@ -177,7 +186,7 @@ data class ModuleTestSourceInfo internal constructor(override val module: Module
|
||||
|
||||
override val displayedName get() = module.name + " (test)"
|
||||
|
||||
override fun contentScope(): GlobalSearchScope = ModuleTestSourceScope(module)
|
||||
override fun contentScope(): GlobalSearchScope = enlargedSearchScope(ModuleTestSourceScope(module), module.moduleFile)
|
||||
|
||||
override fun modulesWhoseInternalsAreVisible() = module.cached(CachedValueProvider {
|
||||
val list = SmartList<ModuleInfo>()
|
||||
@@ -433,4 +442,4 @@ data class PlatformModuleInfo(
|
||||
}
|
||||
|
||||
fun IdeaModuleInfo.projectSourceModules(): List<ModuleSourceInfo>? =
|
||||
(this as? ModuleSourceInfo)?.let(::listOf) ?: (this as? PlatformModuleInfo)?.containedModules
|
||||
(this as? ModuleSourceInfo)?.let(::listOf) ?: (this as? PlatformModuleInfo)?.containedModules
|
||||
|
||||
@@ -29,6 +29,10 @@ import com.intellij.util.xmlb.XmlSerializerUtil
|
||||
)
|
||||
)
|
||||
class KotlinCompilerWorkspaceSettings : PersistentStateComponent<KotlinCompilerWorkspaceSettings> {
|
||||
/**
|
||||
* incrementalCompilationForJvmEnabled
|
||||
* (name `preciseIncrementalEnabled` is kept for workspace file compatibility)
|
||||
*/
|
||||
var preciseIncrementalEnabled: Boolean = true
|
||||
var incrementalCompilationForJsEnabled: Boolean = false
|
||||
var enableDaemon: Boolean = true
|
||||
|
||||
@@ -45,11 +45,13 @@ object KotlinJvmModuleAnnotationsIndex : FileBasedIndexExtension<String, List<Cl
|
||||
override fun getIndexer(): DataIndexer<String, List<ClassId>, FileContent> = DataIndexer { inputData ->
|
||||
val file = inputData.file
|
||||
try {
|
||||
val moduleMapping = ModuleMapping.loadModuleMapping(inputData.content, file.toString(), DeserializationConfiguration.Default)
|
||||
return@DataIndexer mapOf(file.nameWithoutExtension to moduleMapping.moduleData.annotations.map(ClassId::fromString))
|
||||
val moduleMapping = ModuleMapping.loadModuleMapping(inputData.content, file.toString(), DeserializationConfiguration.Default) {}
|
||||
if (moduleMapping !== ModuleMapping.EMPTY) {
|
||||
return@DataIndexer mapOf(file.nameWithoutExtension to moduleMapping.moduleData.annotations.map(ClassId::fromString))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
// Exceptions are already reported in KotlinModuleMappingIndex
|
||||
emptyMap()
|
||||
}
|
||||
emptyMap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,20 +73,19 @@ object KotlinModuleMappingIndex : FileBasedIndexExtension<String, PackageParts>(
|
||||
|
||||
override fun getVersion(): Int = 5
|
||||
|
||||
override fun getIndexer(): DataIndexer<String, PackageParts, FileContent> {
|
||||
return DataIndexer<String, PackageParts, FileContent> { inputData ->
|
||||
val content = inputData.content
|
||||
val file = inputData.file
|
||||
try {
|
||||
val moduleMapping = ModuleMapping.loadModuleMapping(content, file.toString(), DeserializationConfiguration.Default)
|
||||
if (moduleMapping === ModuleMapping.CORRUPTED) {
|
||||
file.refresh(true, false)
|
||||
}
|
||||
return@DataIndexer moduleMapping.packageFqName2Parts
|
||||
override fun getIndexer(): DataIndexer<String, PackageParts, FileContent> = DataIndexer { inputData ->
|
||||
val content = inputData.content
|
||||
val file = inputData.file
|
||||
try {
|
||||
val moduleMapping = ModuleMapping.loadModuleMapping(content, file.toString(), DeserializationConfiguration.Default) {
|
||||
// Do nothing; it's OK for an IDE index to just ignore incompatible module files
|
||||
}
|
||||
catch(e: Exception) {
|
||||
throw RuntimeException("Error on indexing $file", e)
|
||||
if (moduleMapping === ModuleMapping.CORRUPTED) {
|
||||
file.refresh(true, false)
|
||||
}
|
||||
return@DataIndexer moduleMapping.packageFqName2Parts
|
||||
} catch (e: Exception) {
|
||||
throw RuntimeException("Error on indexing $file", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.android.configure
|
||||
|
||||
import com.android.tools.idea.gradle.project.sync.GradleSyncInvoker
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleUtil
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.JavaSdkVersion
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.psi.PsiFile
|
||||
import org.jetbrains.kotlin.idea.configuration.AndroidGradle
|
||||
import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator
|
||||
import org.jetbrains.kotlin.idea.configuration.getBuildSystemType
|
||||
import org.jetbrains.kotlin.idea.util.projectStructure.version
|
||||
import org.jetbrains.kotlin.idea.versions.MAVEN_STDLIB_ID_JDK7
|
||||
import org.jetbrains.kotlin.idea.versions.hasJreSpecificRuntime
|
||||
import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||
|
||||
class KotlinAndroidGradleModuleConfigurator internal constructor() : KotlinWithGradleConfigurator() {
|
||||
|
||||
override val name: String = NAME
|
||||
|
||||
override val targetPlatform: TargetPlatform = JvmPlatform
|
||||
|
||||
override val presentableText: String = "Android with Gradle"
|
||||
|
||||
public override fun isApplicable(module: Module): Boolean = module.getBuildSystemType() == AndroidGradle
|
||||
|
||||
override val kotlinPluginName: String = KOTLIN_ANDROID
|
||||
|
||||
override fun getKotlinPluginExpression(forKotlinDsl: Boolean): String =
|
||||
if (forKotlinDsl) "kotlin(\"android\")" else "id 'org.jetbrains.kotlin.android' "
|
||||
|
||||
override fun addElementsToFile(file: PsiFile, isTopLevelProjectFile: Boolean, version: String): Boolean {
|
||||
val manipulator = getManipulator(file, false)
|
||||
val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk }
|
||||
val jvmTarget = getJvmTarget(sdk, version)
|
||||
return if (isTopLevelProjectFile) {
|
||||
manipulator.configureProjectBuildScript(kotlinPluginName, version)
|
||||
}
|
||||
else {
|
||||
manipulator.configureModuleBuildScript(
|
||||
kotlinPluginName,
|
||||
getKotlinPluginExpression(file.isKtDsl()),
|
||||
getStdlibArtifactName(sdk, version),
|
||||
version,
|
||||
jvmTarget
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getStdlibArtifactName(sdk: Sdk?, version: String): String {
|
||||
if (sdk != null && hasJreSpecificRuntime(version)) {
|
||||
val sdkVersion = sdk.version
|
||||
if (sdkVersion != null && sdkVersion.isAtLeast(JavaSdkVersion.JDK_1_8)) {
|
||||
// Android dex can't convert our kotlin-stdlib-jre8 artifact, so use jre7 instead (KT-16530)
|
||||
return MAVEN_STDLIB_ID_JDK7
|
||||
}
|
||||
}
|
||||
|
||||
return super.getStdlibArtifactName(sdk, version)
|
||||
}
|
||||
|
||||
@JvmSuppressWildcards
|
||||
override fun configure(project: Project, excludeModules: Collection<Module>) {
|
||||
super.configure(project, excludeModules)
|
||||
// Sync after changing build scripts
|
||||
GradleSyncInvoker.getInstance().requestProjectSync(project, GradleSyncInvoker.Request.projectModified())
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val NAME = "android-gradle"
|
||||
|
||||
private val KOTLIN_ANDROID = "kotlin-android"
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ dependencies {
|
||||
sourceSets {
|
||||
"main" {
|
||||
projectDefault()
|
||||
resources.srcDir("res").apply { include("**") }
|
||||
resources.srcDir("res")
|
||||
}
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ dependencies {
|
||||
sourceSets {
|
||||
"main" {
|
||||
projectDefault()
|
||||
resources.srcDir("res").apply { include("**") }
|
||||
resources.srcDir("res")
|
||||
}
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ dependencies {
|
||||
sourceSets {
|
||||
"main" {
|
||||
projectDefault()
|
||||
resources.srcDir("res").apply { include("**") }
|
||||
resources.srcDir("res")
|
||||
}
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ dependencies {
|
||||
sourceSets {
|
||||
"main" {
|
||||
projectDefault()
|
||||
resources.srcDir("res").apply { include("**") }
|
||||
resources.srcDir("res")
|
||||
}
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ dependencies {
|
||||
sourceSets {
|
||||
"main" {
|
||||
projectDefault()
|
||||
resources.srcDir("res").apply { include("**") }
|
||||
resources.srcDir("res")
|
||||
}
|
||||
"test" { projectDefault() }
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.allopen.ide.AllOpenGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.scripting.idea.plugin.ScriptingGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.kapt.idea.KaptGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.noarg.ide.NoArgGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverGradleProjectImportHandler"/>
|
||||
|
||||
|
||||
84
idea/src/META-INF/gradle-java.xml.as33
Normal file
84
idea/src/META-INF/gradle-java.xml.as33
Normal file
@@ -0,0 +1,84 @@
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJavaFrameworkSupportProvider"/>
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJSFrameworkSupportProvider"/>
|
||||
<kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJavaFrameworkSupportProvider"/>
|
||||
<kotlinDslFrameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.KotlinDslGradleKotlinJSFrameworkSupportProvider"/>
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinMPPCommonFrameworkSupportProvider"/>
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinMPPJavaFrameworkSupportProvider"/>
|
||||
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinMPPJSFrameworkSupportProvider"/>
|
||||
<pluginDescriptions implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradlePluginDescription"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectResolverExtension" order="first"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.kapt.idea.KaptProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.allopen.ide.AllOpenProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.noarg.ide.NoArgProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverProjectResolverExtension" order="last"/>
|
||||
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinMPPGradleProjectResolver"/>
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleSourceSetDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleLibraryDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinSourceSetDataService"/>
|
||||
<externalProjectDataService implementation="org.jetbrains.kotlin.idea.configuration.KotlinTargetDataService"/>
|
||||
<externalSystemTaskNotificationListener implementation="org.jetbrains.kotlin.idea.core.script.ReloadGradleTemplatesOnSync"/>
|
||||
|
||||
<localInspection
|
||||
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DifferentKotlinGradleVersionInspection"
|
||||
displayName="Kotlin Gradle and IDE plugins versions are different"
|
||||
groupName="Kotlin"
|
||||
enabledByDefault="true"
|
||||
language="Groovy"
|
||||
hasStaticDescription="true"
|
||||
level="WARNING"/>
|
||||
|
||||
<localInspection
|
||||
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DifferentStdlibGradleVersionInspection"
|
||||
displayName="Kotlin library and Gradle plugin versions are different"
|
||||
groupName="Kotlin"
|
||||
enabledByDefault="true"
|
||||
language="Groovy"
|
||||
hasStaticDescription="true"
|
||||
level="WARNING"/>
|
||||
|
||||
<localInspection
|
||||
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.DeprecatedGradleDependencyInspection"
|
||||
displayName="Deprecated library is used in Gradle"
|
||||
groupName="Kotlin"
|
||||
enabledByDefault="true"
|
||||
language="Groovy"
|
||||
hasStaticDescription="true"
|
||||
level="WARNING"/>
|
||||
|
||||
<localInspection
|
||||
implementationClass="org.jetbrains.kotlin.idea.inspections.gradle.GradleKotlinxCoroutinesDeprecationInspection"
|
||||
displayName="kotlinx.coroutines dependencies should be updated in Gradle for using with Kotlin 1.3+"
|
||||
groupPath="Kotlin,Migration"
|
||||
groupName="Gradle"
|
||||
enabledByDefault="true"
|
||||
language="Groovy"
|
||||
hasStaticDescription="true"
|
||||
level="ERROR"/>
|
||||
|
||||
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestClassGradleConfigurationProducer"/>
|
||||
<runConfigurationProducer implementation="org.jetbrains.kotlin.idea.run.KotlinTestMethodGradleConfigurationProducer"/>
|
||||
|
||||
</extensions>
|
||||
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.allopen.ide.AllOpenGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.scripting.idea.plugin.ScriptingGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.kapt.idea.KaptGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.noarg.ide.NoArgGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverGradleProjectImportHandler"/>
|
||||
|
||||
<projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleModuleConfigurator"/>
|
||||
<projectConfigurator implementation="org.jetbrains.kotlin.idea.configuration.KotlinJsGradleModuleConfigurator"/>
|
||||
<gradleModelFacade implementation="org.jetbrains.kotlin.idea.inspections.gradle.DefaultGradleModelFacade"/>
|
||||
|
||||
<scriptDefinitionContributor implementation="org.jetbrains.kotlin.idea.core.script.GradleScriptDefinitionsContributor" order="first"/>
|
||||
|
||||
<moduleBuilder implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleMultiplatformModuleBuilder"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
||||
@@ -78,6 +78,7 @@
|
||||
<extensions defaultExtensionNs="org.jetbrains.kotlin">
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.allopen.ide.AllOpenGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.scripting.idea.plugin.ScriptingGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.kapt.idea.KaptGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.noarg.ide.NoArgGradleProjectImportHandler"/>
|
||||
<gradleProjectImportHandler implementation="org.jetbrains.kotlin.samWithReceiver.ide.SamWithReceiverGradleProjectImportHandler"/>
|
||||
|
||||
|
||||
13
idea/src/META-INF/pluginIcon.svg
Normal file
13
idea/src/META-INF/pluginIcon.svg
Normal file
@@ -0,0 +1,13 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40">
|
||||
<defs>
|
||||
<linearGradient id="kotlin-a" x1="2.195%" x2="91.789%" y1="91.369%" y2="0%">
|
||||
<stop offset="0%" stop-color="#8F67FF" stop-opacity=".987"/>
|
||||
<stop offset="56.707%" stop-color="#F9A02F" stop-opacity=".993"/>
|
||||
<stop offset="100%" stop-color="#F7861E"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<polygon fill="#0EAEFF" points="4 4 4 35.995 36.001 35.995 20.045 19.925 36.001 4"/>
|
||||
<polygon fill="url(#kotlin-a)" points="20.064 4 4 20.893 4 35.995 20.041 19.925 35.995 4"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 631 B |
@@ -281,8 +281,12 @@ fun applyCompilerArgumentsToFacet(
|
||||
val defaultCompilerArguments = defaultArguments?.let { copyBean(it) } ?: compilerArguments::class.java.newInstance()
|
||||
defaultCompilerArguments.convertPathsToSystemIndependent()
|
||||
|
||||
val oldPluginOptions = compilerArguments.pluginOptions
|
||||
|
||||
val emptyArgs = compilerArguments::class.java.newInstance()
|
||||
copyBeanTo(arguments, compilerArguments) { property, value -> value != property.get(emptyArgs) }
|
||||
compilerArguments.pluginOptions = joinPluginOptions(oldPluginOptions, arguments.pluginOptions)
|
||||
|
||||
compilerArguments.convertPathsToSystemIndependent()
|
||||
|
||||
// Retain only fields exposed (and not explicitly ignored) in facet configuration editor.
|
||||
@@ -321,3 +325,15 @@ fun applyCompilerArgumentsToFacet(
|
||||
updateMergedArguments()
|
||||
}
|
||||
}
|
||||
|
||||
private fun joinPluginOptions(old: Array<String>?, new: Array<String>?): Array<String>? {
|
||||
if (old == null && new == null) {
|
||||
return old
|
||||
} else if (new == null) {
|
||||
return old
|
||||
} else if (old == null) {
|
||||
return new
|
||||
}
|
||||
|
||||
return (old + new).distinct().toTypedArray()
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createCallable
|
||||
|
||||
import com.intellij.codeInsight.intention.LowPriorityAction
|
||||
import com.intellij.codeInsight.navigation.NavigationUtil
|
||||
import com.intellij.ide.util.EditorHelper
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.fileEditor.FileEditorManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
@@ -177,20 +177,14 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
}
|
||||
|
||||
override fun invokeImpl(project: Project, editor: Editor?, file: PsiFile) {
|
||||
if (editor == null) return
|
||||
|
||||
val element = element ?: return
|
||||
val callableInfo = callableInfos.first()
|
||||
|
||||
val fileForBuilder: KtFile
|
||||
val editorForBuilder: Editor
|
||||
if (file is KtFile) {
|
||||
fileForBuilder = file
|
||||
editorForBuilder = editor
|
||||
} else {
|
||||
fileForBuilder = element.containingKtFile
|
||||
EditorHelper.openInEditor(element)
|
||||
editorForBuilder = FileEditorManager.getInstance(project).selectedTextEditor!!
|
||||
val fileForBuilder = element.containingKtFile
|
||||
|
||||
val editorForBuilder = EditorHelper.openInEditor(element)
|
||||
if (editorForBuilder != editor) {
|
||||
NavigationUtil.activateFileWithPsiElement(element)
|
||||
}
|
||||
|
||||
val callableBuilder =
|
||||
@@ -220,7 +214,7 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
val containers = receiverTypeCandidates
|
||||
.mapNotNull { candidate -> getDeclarationIfApplicable(project, candidate)?.let { candidate to it } }
|
||||
|
||||
chooseContainerElementIfNecessary(containers, editor, popupTitle, false, { it.second }) {
|
||||
chooseContainerElementIfNecessary(containers, editorForBuilder, popupTitle, false, { it.second }) {
|
||||
runBuilder(CallablePlacement.WithReceiver(it.first))
|
||||
}
|
||||
} else {
|
||||
@@ -228,7 +222,7 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
|
||||
"No receiver type candidates: ${element.text} in ${file.text}"
|
||||
}
|
||||
|
||||
chooseContainerElementIfNecessary(callableInfo.possibleContainers, editor, popupTitle, true, { it }) {
|
||||
chooseContainerElementIfNecessary(callableInfo.possibleContainers, editorForBuilder, popupTitle, true, { it }) {
|
||||
val container = if (it is KtClassBody) it.parent as KtClassOrObject else it
|
||||
runBuilder(CallablePlacement.NoReceiver(container))
|
||||
}
|
||||
|
||||
@@ -19,17 +19,20 @@ package org.jetbrains.kotlin.idea.quickfix.crossLanguage
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory
|
||||
import com.intellij.lang.java.beans.PropertyKind
|
||||
import com.intellij.lang.jvm.JvmClass
|
||||
import com.intellij.lang.jvm.JvmElement
|
||||
import com.intellij.lang.jvm.JvmModifier
|
||||
import com.intellij.lang.jvm.JvmModifiersOwner
|
||||
import com.intellij.lang.jvm.actions.*
|
||||
import com.intellij.lang.jvm.types.JvmType
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.codeStyle.SuggestedNameInfo
|
||||
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl
|
||||
import com.intellij.psi.util.PropertyUtilBase
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
@@ -144,9 +147,9 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
}
|
||||
|
||||
class CreatePropertyFix(
|
||||
private val targetClass: JvmClass,
|
||||
contextElement: KtElement,
|
||||
propertyInfo: PropertyInfo
|
||||
contextElement: KtElement,
|
||||
propertyInfo: PropertyInfo,
|
||||
private val classOrFileName: String?
|
||||
) : CreateCallableFromUsageFix<KtElement>(contextElement, listOf(propertyInfo)) {
|
||||
override fun getFamilyName() = "Add property"
|
||||
override fun getText(): String {
|
||||
@@ -157,7 +160,7 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
append("lateinit ")
|
||||
}
|
||||
append(if (info.writable) "var" else "val")
|
||||
append("' property '${info.name}' to '${targetClass.name}'")
|
||||
append("' property '${info.name}' to '$classOrFileName'")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -324,29 +327,42 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
|
||||
override fun createAddPropertyActions(targetClass: JvmClass, request: MemberRequest.Property): List<IntentionAction> {
|
||||
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
|
||||
return createAddPropertyActions(
|
||||
targetContainer, listOf(request.visibilityModifier),
|
||||
request.propertyType, request.propertyName, request.setterRequired, targetClass.name
|
||||
)
|
||||
}
|
||||
|
||||
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifier(request.visibilityModifier) }
|
||||
private fun createAddPropertyActions(
|
||||
targetContainer: KtElement,
|
||||
modifiers: Iterable<JvmModifier>,
|
||||
propertyType: JvmType,
|
||||
propertyName: String,
|
||||
setterRequired: Boolean,
|
||||
classOrFileName: String?
|
||||
): List<IntentionAction> {
|
||||
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifiers(modifiers) }
|
||||
if (!modifierBuilder.isValid) return emptyList()
|
||||
|
||||
val resolutionFacade = targetContainer.getResolutionFacade()
|
||||
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
|
||||
val ktType = (request.propertyType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
|
||||
|
||||
val ktType = (propertyType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
|
||||
val propertyInfo = PropertyInfo(
|
||||
request.propertyName,
|
||||
TypeInfo.Empty,
|
||||
TypeInfo(ktType, Variance.INVARIANT),
|
||||
request.setterRequired,
|
||||
listOf(targetContainer),
|
||||
modifierList = modifierBuilder.modifierList,
|
||||
withInitializer = true
|
||||
propertyName,
|
||||
TypeInfo.Empty,
|
||||
TypeInfo(ktType, Variance.INVARIANT),
|
||||
setterRequired,
|
||||
listOf(targetContainer),
|
||||
modifierList = modifierBuilder.modifierList,
|
||||
withInitializer = true
|
||||
)
|
||||
val propertyInfos = if (request.setterRequired) {
|
||||
val propertyInfos = if (setterRequired) {
|
||||
listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
listOf(propertyInfo)
|
||||
}
|
||||
return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) }
|
||||
return propertyInfos.map { CreatePropertyFix(targetContainer, it, classOrFileName) }
|
||||
}
|
||||
|
||||
override fun createAddFieldActions(targetClass: JvmClass, request: CreateFieldRequest): List<IntentionAction> {
|
||||
@@ -382,7 +398,7 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
else {
|
||||
listOf(propertyInfo(false))
|
||||
}
|
||||
return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) }
|
||||
return propertyInfos.map { CreatePropertyFix(targetContainer, it, targetClass.name) }
|
||||
}
|
||||
|
||||
override fun createAddMethodActions(targetClass: JvmClass, request: CreateMethodRequest): List<IntentionAction> {
|
||||
@@ -410,11 +426,27 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
preferEmptyBody = true
|
||||
)
|
||||
val targetClassName = targetClass.name
|
||||
|
||||
val action = object : CreateCallableFromUsageFix<KtElement>(targetContainer, listOf(functionInfo)) {
|
||||
override fun getFamilyName() = "Add method"
|
||||
override fun getText() = "Add method '$methodName' to '$targetClassName'"
|
||||
}
|
||||
return listOf(action)
|
||||
|
||||
val nameAndKind = PropertyUtilBase.getPropertyNameAndKind(methodName) ?: return listOf(action)
|
||||
|
||||
val propertyType = (request.expectedParameters.singleOrNull()?.expectedTypes ?: request.returnType)
|
||||
.firstOrNull { JvmPsiConversionHelper.getInstance(targetContainer.project).convertType(it.theType) != PsiType.VOID }
|
||||
?: return listOf(action)
|
||||
|
||||
return createAddPropertyActions(
|
||||
targetContainer,
|
||||
request.modifiers,
|
||||
propertyType.theType,
|
||||
nameAndKind.first,
|
||||
nameAndKind.second == PropertyKind.SETTER,
|
||||
targetClass.name
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
override fun createAddAnnotationActions(target: JvmModifiersOwner, request: AnnotationRequest): List<IntentionAction> {
|
||||
|
||||
@@ -17,17 +17,19 @@
|
||||
package org.jetbrains.kotlin.idea.quickfix.crossLanguage
|
||||
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.CreateParameterFromUsageFix
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.codeInsight.intention.QuickFixFactory
|
||||
import com.intellij.lang.java.beans.PropertyKind
|
||||
import com.intellij.lang.jvm.*
|
||||
import com.intellij.lang.jvm.actions.*
|
||||
import com.intellij.lang.jvm.types.JvmType
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.codeStyle.SuggestedNameInfo
|
||||
import com.intellij.psi.impl.source.tree.java.PsiReferenceExpressionImpl
|
||||
import com.intellij.psi.util.PropertyUtilBase
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade
|
||||
import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
|
||||
import org.jetbrains.kotlin.asJava.elements.KtLightElement
|
||||
@@ -142,9 +144,9 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
}
|
||||
|
||||
class CreatePropertyFix(
|
||||
private val targetClass: JvmClass,
|
||||
contextElement: KtElement,
|
||||
propertyInfo: PropertyInfo
|
||||
propertyInfo: PropertyInfo,
|
||||
private val classOrFileName: String?
|
||||
) : CreateCallableFromUsageFix<KtElement>(contextElement, listOf(propertyInfo)) {
|
||||
override fun getFamilyName() = "Add property"
|
||||
override fun getText(): String {
|
||||
@@ -155,7 +157,7 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
append("lateinit ")
|
||||
}
|
||||
append(if (info.writable) "var" else "val")
|
||||
append("' property '${info.name}' to '${targetClass.name}'")
|
||||
append("' property '${info.name}' to '$classOrFileName'")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,29 +324,43 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
|
||||
override fun createAddPropertyActions(targetClass: JvmClass, request: MemberRequest.Property): List<IntentionAction> {
|
||||
val targetContainer = targetClass.toKtClassOrFile() ?: return emptyList()
|
||||
return createAddPropertyActions(
|
||||
targetContainer, listOf(request.visibilityModifier),
|
||||
request.propertyType, request.propertyName, request.setterRequired, targetClass.name
|
||||
)
|
||||
}
|
||||
|
||||
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifier(request.visibilityModifier) }
|
||||
private fun createAddPropertyActions(
|
||||
targetContainer: KtElement,
|
||||
modifiers: Iterable<JvmModifier>,
|
||||
propertyType: JvmType,
|
||||
propertyName: String,
|
||||
setterRequired: Boolean,
|
||||
classOrFileName: String?
|
||||
): List<IntentionAction> {
|
||||
val modifierBuilder = ModifierBuilder(targetContainer).apply { addJvmModifiers(modifiers) }
|
||||
if (!modifierBuilder.isValid) return emptyList()
|
||||
|
||||
val resolutionFacade = targetContainer.getResolutionFacade()
|
||||
val nullableAnyType = resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
|
||||
val ktType = (request.propertyType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
|
||||
|
||||
val ktType = (propertyType as? PsiType)?.resolveToKotlinType(resolutionFacade) ?: nullableAnyType
|
||||
val propertyInfo = PropertyInfo(
|
||||
request.propertyName,
|
||||
propertyName,
|
||||
TypeInfo.Empty,
|
||||
TypeInfo(ktType, Variance.INVARIANT),
|
||||
request.setterRequired,
|
||||
setterRequired,
|
||||
listOf(targetContainer),
|
||||
modifierList = modifierBuilder.modifierList,
|
||||
withInitializer = true
|
||||
)
|
||||
val propertyInfos = if (request.setterRequired) {
|
||||
val propertyInfos = if (setterRequired) {
|
||||
listOf(propertyInfo, propertyInfo.copyProperty(isLateinitPreferred = true))
|
||||
}
|
||||
else {
|
||||
listOf(propertyInfo)
|
||||
}
|
||||
return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) }
|
||||
return propertyInfos.map { CreatePropertyFix(targetContainer, it, classOrFileName) }
|
||||
}
|
||||
|
||||
override fun createAddFieldActions(targetClass: JvmClass, request: CreateFieldRequest): List<IntentionAction> {
|
||||
@@ -380,7 +396,7 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
else {
|
||||
listOf(propertyInfo(false))
|
||||
}
|
||||
return propertyInfos.map { CreatePropertyFix(targetClass, targetContainer, it) }
|
||||
return propertyInfos.map { CreatePropertyFix(targetContainer, it, targetClass.name) }
|
||||
}
|
||||
|
||||
override fun createAddMethodActions(targetClass: JvmClass, request: CreateMethodRequest): List<IntentionAction> {
|
||||
@@ -412,7 +428,22 @@ class KotlinElementActionsFactory : JvmElementActionsFactory() {
|
||||
override fun getFamilyName() = "Add method"
|
||||
override fun getText() = "Add method '$methodName' to '$targetClassName'"
|
||||
}
|
||||
return listOf(action)
|
||||
|
||||
val nameAndKind = PropertyUtilBase.getPropertyNameAndKind(methodName) ?: return listOf(action)
|
||||
|
||||
val propertyType = (request.expectedParameters.singleOrNull()?.expectedTypes ?: request.returnType)
|
||||
.firstOrNull { JvmPsiConversionHelper.getInstance(targetContainer.project).convertType(it.theType) != PsiType.VOID }
|
||||
?: return listOf(action)
|
||||
|
||||
return createAddPropertyActions(
|
||||
targetContainer,
|
||||
request.modifiers,
|
||||
propertyType.theType,
|
||||
nameAndKind.first,
|
||||
nameAndKind.second == PropertyKind.SETTER,
|
||||
targetClass.name
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
override fun createAddAnnotationActions(target: JvmModifiersOwner, request: AnnotationRequest): List<IntentionAction> {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user