mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-08 08:31:32 +00:00
Compare commits
88 Commits
rrni/rever
...
v1.2.71
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3726f6331d | ||
|
|
a4f20ba14c | ||
|
|
d41cf03ccd | ||
|
|
85f1ce234d | ||
|
|
d10d140ef7 | ||
|
|
3d407d489a | ||
|
|
e0723c573d | ||
|
|
4447e4ce4e | ||
|
|
1c6ae28889 | ||
|
|
2d99872dc6 | ||
|
|
7a54feded5 | ||
|
|
833be3d349 | ||
|
|
6527fbfacc | ||
|
|
86e5d48716 | ||
|
|
a04ea1a16d | ||
|
|
07dc7e3b19 | ||
|
|
c579b5615c | ||
|
|
e403f8f930 | ||
|
|
1a5f4d884e | ||
|
|
51c0e3272d | ||
|
|
c3c7115450 | ||
|
|
fa6b0c878b | ||
|
|
b4e059f2e6 | ||
|
|
c102f7ca77 | ||
|
|
35fd69c395 | ||
|
|
3e810b756b | ||
|
|
9d155b0eab | ||
|
|
955f7bb287 | ||
|
|
07bf6a6b99 | ||
|
|
d5385a73a7 | ||
|
|
1f8eb7211b | ||
|
|
0600cb6174 | ||
|
|
5fb09f98d2 | ||
|
|
64c2bd427f | ||
|
|
5f1e5d7bb2 | ||
|
|
21470e59f5 | ||
|
|
46b78b1df4 | ||
|
|
af28757eda | ||
|
|
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 |
5904
ChangeLog.md
5904
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());
|
||||
|
||||
@@ -1592,7 +1592,10 @@ public abstract class StackValue {
|
||||
putReceiver(v, false);
|
||||
}
|
||||
callGenerator.processAndPutHiddenParameters(true);
|
||||
callGenerator.putValueIfNeeded(new JvmKotlinType(rightSide.type, rightSide.kotlinType), rightSide);
|
||||
callGenerator.putValueIfNeeded(new JvmKotlinType(
|
||||
CollectionsKt.last(setter.getValueParameters()).getAsmType(),
|
||||
CollectionsKt.last(setterDescriptor.getValueParameters()).getType()),
|
||||
rightSide);
|
||||
callGenerator.putHiddenParamsIntoLocals();
|
||||
callGenerator.genCall(setter, resolvedCall, false, codegen);
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ public class SingleAbstractMethodUtils {
|
||||
// Otherwise android data binding can cause resolve re-entrance
|
||||
// For details see KT-18687, KT-16149
|
||||
// TODO: prevent resolve re-entrance on architecture level, or (alternatively) ask data binding owners not to do it
|
||||
if (DescriptorUtilsKt.getFqNameSafe(klass).asString().equals("android.databinding.DataBindingComponent")) {
|
||||
if (DescriptorUtilsKt.getFqNameSafe(klass).asString().endsWith(".databinding.DataBindingComponent")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,11 @@ 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.MultiTargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.getMultiTargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
|
||||
|
||||
class OptionalExpectationUsageChecker : ClassifierUsageChecker {
|
||||
override fun check(targetDescriptor: ClassifierDescriptor, element: PsiElement, context: ClassifierUsageCheckerContext) {
|
||||
@@ -16,5 +21,11 @@ class OptionalExpectationUsageChecker : ClassifierUsageChecker {
|
||||
if (!element.isUsageAsAnnotationOrImport()) {
|
||||
context.trace.report(Errors.OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY.on(element))
|
||||
}
|
||||
|
||||
val ktFile = element.containingFile as KtFile
|
||||
// The first part is for the compiler, and the second one is for IDE
|
||||
if (ktFile.isCommonSource != true && targetDescriptor.module.getMultiTargetPlatform() != MultiTargetPlatform.Common) {
|
||||
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(
|
||||
@@ -37,13 +38,17 @@ fun makeJsIncrementally(
|
||||
messageCollector: MessageCollector = MessageCollector.NONE,
|
||||
reporter: ICReporter = EmptyICReporter
|
||||
) {
|
||||
val isIncremental = IncrementalCompilation.isEnabledForJs()
|
||||
val versions = commonCacheVersions(cachesDir, isIncremental) + standaloneCacheVersion(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 versions = commonCacheVersionsManagers(cachesDir, true) + standaloneCacheVersionManager(cachesDir, true)
|
||||
|
||||
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
|
||||
@@ -56,9 +57,6 @@ fun makeIncrementally(
|
||||
messageCollector: MessageCollector = MessageCollector.NONE,
|
||||
reporter: ICReporter = EmptyICReporter
|
||||
) {
|
||||
val isIncremental = IncrementalCompilation.isEnabledForJvm()
|
||||
val versions = commonCacheVersions(cachesDir, isIncremental) + standaloneCacheVersion(cachesDir, isIncremental)
|
||||
|
||||
val kotlinExtensions = listOf("kt", "kts")
|
||||
val allExtensions = kotlinExtensions + listOf("java")
|
||||
val rootsWalk = sourceRoots.asSequence().flatMap { it.walk() }
|
||||
@@ -67,6 +65,8 @@ fun makeIncrementally(
|
||||
val buildHistoryFile = File(cachesDir, "build-history.bin")
|
||||
|
||||
withIC {
|
||||
val versions = commonCacheVersionsManagers(cachesDir, true) + standaloneCacheVersionManager(cachesDir, true)
|
||||
|
||||
val compiler = IncrementalJvmCompilerRunner(
|
||||
cachesDir,
|
||||
sourceRoots.map { JvmSourceRoot(it, null) }.toSet(),
|
||||
@@ -99,20 +99,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 +145,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 +160,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 +171,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 +181,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 +243,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 +311,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 +340,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")
|
||||
|
||||
17
compiler/testData/codegen/boxInline/property/kt22649.kt
vendored
Normal file
17
compiler/testData/codegen/boxInline/property/kt22649.kt
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// FILE: 1.kt
|
||||
var result = ""
|
||||
|
||||
inline var apx:Int
|
||||
get() = 0
|
||||
set(value) { result = if (value == 1) "OK" else "fail" }
|
||||
|
||||
|
||||
// FILE: 2.kt
|
||||
fun test(s: Int?) {
|
||||
apx = s!!
|
||||
}
|
||||
|
||||
fun box() : String {
|
||||
test(1)
|
||||
return result
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
9
compiler/testData/diagnostics/testsWithStdLib/regression/kt26806.kt
vendored
Normal file
9
compiler/testData/diagnostics/testsWithStdLib/regression/kt26806.kt
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
const val myPi = kotlin.math.PI
|
||||
|
||||
annotation class Anno(val d: Double)
|
||||
|
||||
@Anno(kotlin.math.PI)
|
||||
fun f() {}
|
||||
|
||||
@Anno(myPi)
|
||||
fun g() {}
|
||||
13
compiler/testData/diagnostics/testsWithStdLib/regression/kt26806.txt
vendored
Normal file
13
compiler/testData/diagnostics/testsWithStdLib/regression/kt26806.txt
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
package
|
||||
|
||||
public const val myPi: kotlin.Double = 3.141592653589793.toDouble()
|
||||
@Anno(d = 3.141592653589793.toDouble()) public fun f(): kotlin.Unit
|
||||
@Anno(d = 3.141592653589793.toDouble()) public fun g(): kotlin.Unit
|
||||
|
||||
public final annotation class Anno : kotlin.Annotation {
|
||||
public constructor Anno(/*0*/ d: kotlin.Double)
|
||||
public final val d: kotlin.Double
|
||||
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
|
||||
}
|
||||
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");
|
||||
|
||||
@@ -2765,6 +2765,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt2082.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt26806.kt")
|
||||
public void testKt26806() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt26806.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt9345.kt")
|
||||
public void testKt9345() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt9345.kt");
|
||||
|
||||
@@ -2765,6 +2765,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt2082.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt26806.kt")
|
||||
public void testKt26806() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt26806.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt9345.kt")
|
||||
public void testKt9345() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/testsWithStdLib/regression/kt9345.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");
|
||||
|
||||
@@ -2410,6 +2410,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
||||
runTest("compiler/testData/codegen/boxInline/property/augAssignmentAndIncViaConvention.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt22649.kt")
|
||||
public void testKt22649() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/property/kt22649.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("property.kt")
|
||||
public void testProperty() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/property/property.kt");
|
||||
|
||||
@@ -2410,6 +2410,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
||||
runTest("compiler/testData/codegen/boxInline/property/augAssignmentAndIncViaConvention.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt22649.kt")
|
||||
public void testKt22649() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/property/kt22649.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("property.kt")
|
||||
public void testProperty() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/property/property.kt");
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -2410,6 +2410,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
||||
runTest("compiler/testData/codegen/boxInline/property/augAssignmentAndIncViaConvention.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt22649.kt")
|
||||
public void testKt22649() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/property/kt22649.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("property.kt")
|
||||
public void testProperty() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/property/property.kt");
|
||||
|
||||
@@ -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?
|
||||
}
|
||||
|
||||
@@ -102,12 +102,13 @@ object JvmProtoBufUtil {
|
||||
typeTable: TypeTable
|
||||
): JvmMemberSignature.Field? {
|
||||
val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature) ?: return null
|
||||
val field = if (signature.hasField()) signature.field else return null
|
||||
val field =
|
||||
if (signature.hasField()) signature.field else null
|
||||
|
||||
val name = if (field.hasName()) field.name else proto.name
|
||||
val name = if (field != null && field.hasName()) field.name else proto.name
|
||||
val desc =
|
||||
if (field.hasDesc()) nameResolver.getString(field.desc)
|
||||
else mapTypeDefault(proto.returnType(typeTable), nameResolver) ?: return null
|
||||
if (field != null && field.hasDesc()) nameResolver.getString(field.desc)
|
||||
else mapTypeDefault(proto.returnType(typeTable), nameResolver) ?: return null
|
||||
|
||||
return JvmMemberSignature.Field(nameResolver.getString(name), desc)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,17 +7,21 @@ package org.jetbrains.kotlin.idea.formatter
|
||||
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
|
||||
import com.intellij.psi.codeStyle.PredefinedCodeStyle
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
||||
|
||||
class KotlinObsoleteCodeStyle : PredefinedCodeStyle(CODE_STYLE_TITLE, KotlinLanguage.INSTANCE) {
|
||||
class KotlinObsoleteCodeStyle : KotlinPredefinedCodeStyle(CODE_STYLE_TITLE, KotlinLanguage.INSTANCE) {
|
||||
override val codeStyleId: String = CODE_STYLE_ID
|
||||
|
||||
override fun apply(settings: CodeStyleSettings) {
|
||||
Companion.apply(settings)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val INSTANCE = KotlinObsoleteCodeStyle()
|
||||
|
||||
const val CODE_STYLE_ID = "KOTLIN_OLD_DEFAULTS"
|
||||
const val CODE_STYLE_SETTING = "obsolete"
|
||||
const val CODE_STYLE_TITLE = "Kotlin obsolete IntelliJ IDEA codestyle"
|
||||
|
||||
fun apply(settings: CodeStyleSettings) {
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* 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.idea.formatter
|
||||
|
||||
import com.intellij.lang.Language
|
||||
import com.intellij.psi.codeStyle.PredefinedCodeStyle
|
||||
|
||||
abstract class KotlinPredefinedCodeStyle(name: String, language: Language) : PredefinedCodeStyle(name, language) {
|
||||
abstract val codeStyleId: String
|
||||
}
|
||||
@@ -18,17 +18,21 @@ package org.jetbrains.kotlin.idea.formatter
|
||||
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings
|
||||
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
|
||||
import com.intellij.psi.codeStyle.PredefinedCodeStyle
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
||||
|
||||
class KotlinStyleGuideCodeStyle : PredefinedCodeStyle("Kotlin style guide", KotlinLanguage.INSTANCE) {
|
||||
class KotlinStyleGuideCodeStyle : KotlinPredefinedCodeStyle("Kotlin style guide", KotlinLanguage.INSTANCE) {
|
||||
override val codeStyleId: String = CODE_STYLE_ID
|
||||
|
||||
override fun apply(settings: CodeStyleSettings) {
|
||||
Companion.apply(settings)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val INSTANCE = KotlinStyleGuideCodeStyle()
|
||||
|
||||
const val CODE_STYLE_ID = "KOTLIN_OFFICIAL"
|
||||
const val CODE_STYLE_SETTING = "official"
|
||||
const val CODE_STYLE_TITLE = "Kotlin Coding Conventions"
|
||||
|
||||
fun apply(settings: CodeStyleSettings) {
|
||||
@@ -36,7 +40,10 @@ class KotlinStyleGuideCodeStyle : PredefinedCodeStyle("Kotlin style guide", Kotl
|
||||
applyToCommonSettings(settings.kotlinCommonSettings)
|
||||
}
|
||||
|
||||
fun applyToKotlinCustomSettings(kotlinCustomSettings: KotlinCodeStyleSettings, modifyCodeStyle: Boolean = true) {
|
||||
fun applyToKotlinCustomSettings(
|
||||
kotlinCustomSettings: KotlinCodeStyleSettings,
|
||||
modifyCodeStyle: Boolean = true
|
||||
) {
|
||||
kotlinCustomSettings.apply {
|
||||
if (modifyCodeStyle) {
|
||||
CODE_STYLE_DEFAULTS = CODE_STYLE_ID
|
||||
|
||||
@@ -44,4 +44,8 @@ val CodeStyleSettings.kotlinCommonSettings: KotlinCommonCodeStyleSettings
|
||||
get() = getCommonSettings(KotlinLanguage.INSTANCE) as KotlinCommonCodeStyleSettings
|
||||
|
||||
val CodeStyleSettings.kotlinCustomSettings: KotlinCodeStyleSettings
|
||||
get() = getCustomSettings(KotlinCodeStyleSettings::class.java)
|
||||
get() = getCustomSettings(KotlinCodeStyleSettings::class.java)
|
||||
|
||||
fun CodeStyleSettings.kotlinCodeStyleDefaults(): String? {
|
||||
return kotlinCustomSettings.CODE_STYLE_DEFAULTS ?: kotlinCommonSettings.CODE_STYLE_DEFAULTS
|
||||
}
|
||||
@@ -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.idea.formatter
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
||||
|
||||
object ProjectCodeStyleImporter {
|
||||
fun apply(project: Project, codeStyleStr: String?): Boolean {
|
||||
return when (codeStyleStr) {
|
||||
KotlinObsoleteCodeStyle.CODE_STYLE_SETTING -> {
|
||||
ProjectCodeStyleImporter.apply(project, KotlinObsoleteCodeStyle.INSTANCE)
|
||||
true
|
||||
}
|
||||
KotlinStyleGuideCodeStyle.CODE_STYLE_SETTING -> {
|
||||
ProjectCodeStyleImporter.apply(project, KotlinStyleGuideCodeStyle.INSTANCE)
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
fun apply(project: Project, predefinedCodeStyle: KotlinPredefinedCodeStyle) {
|
||||
val settingsManager = CodeStyleSettingsManager.getInstance(project)
|
||||
|
||||
val currentSettings = settingsManager.currentSettings
|
||||
if (predefinedCodeStyle.codeStyleId == currentSettings.kotlinCodeStyleDefaults()) {
|
||||
// Don't bother user that already have correct code style
|
||||
return
|
||||
}
|
||||
|
||||
val projectSettingsUpdated: CodeStyleSettings = if (settingsManager.USE_PER_PROJECT_SETTINGS) {
|
||||
settingsManager.currentSettings.clone()
|
||||
} else {
|
||||
CodeStyleSettings()
|
||||
}
|
||||
|
||||
settingsManager.USE_PER_PROJECT_SETTINGS = true
|
||||
|
||||
predefinedCodeStyle.apply(projectSettingsUpdated)
|
||||
settingsManager.mainProjectCodeStyle = projectSettingsUpdated
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.caches
|
||||
|
||||
import com.intellij.ProjectTopics
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.progress.ProcessCanceledException
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.rootManager
|
||||
import com.intellij.openapi.roots.ModuleRootEvent
|
||||
import com.intellij.openapi.roots.ModuleRootListener
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.openapi.vfs.newvfs.BulkFileListener
|
||||
import com.intellij.openapi.vfs.newvfs.events.*
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.impl.PsiTreeChangeEventImpl
|
||||
import com.intellij.psi.impl.PsiTreeChangePreprocessor
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService.Companion.FULL_DROP_THRESHOLD
|
||||
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.getModuleInfoByVirtualFile
|
||||
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
|
||||
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
|
||||
import org.jetbrains.kotlin.idea.util.getSourceRoot
|
||||
import org.jetbrains.kotlin.idea.util.sourceRoot
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtPackageDirective
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.ConcurrentMap
|
||||
|
||||
class KotlinPackageContentModificationListener(private val project: Project) {
|
||||
init {
|
||||
val connection = project.messageBus.connect()
|
||||
|
||||
connection.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener {
|
||||
override fun before(events: MutableList<out VFileEvent>) = onEvents(events)
|
||||
override fun after(events: List<VFileEvent>) = onEvents(events)
|
||||
|
||||
private fun isRelevant(it: VFileEvent): Boolean =
|
||||
it is VFileMoveEvent || it is VFileCreateEvent || it is VFileCopyEvent || it is VFileDeleteEvent
|
||||
|
||||
fun onEvents(events: List<VFileEvent>) {
|
||||
val service = PerModulePackageCacheService.getInstance(project)
|
||||
if (events.size >= FULL_DROP_THRESHOLD) {
|
||||
service.onTooComplexChange()
|
||||
} else {
|
||||
events
|
||||
.asSequence()
|
||||
.filter { it.isValid }
|
||||
.filter { it.file != null }
|
||||
.filter(::isRelevant)
|
||||
.filter {
|
||||
val vFile = it.file!!
|
||||
vFile.isDirectory || FileTypeRegistry.getInstance().getFileTypeByFileName(vFile.name) == KotlinFileType.INSTANCE
|
||||
}
|
||||
.forEach { event -> service.notifyPackageChange(event) }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
connection.subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener {
|
||||
override fun rootsChanged(event: ModuleRootEvent) {
|
||||
PerModulePackageCacheService.getInstance(project).onTooComplexChange()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinPackageStatementPsiTreeChangePreprocessor(private val project: Project) : PsiTreeChangePreprocessor {
|
||||
override fun treeChanged(event: PsiTreeChangeEventImpl) {
|
||||
val file = event.file as? KtFile ?: return
|
||||
|
||||
when (event.code) {
|
||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED,
|
||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED,
|
||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED,
|
||||
PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED -> {
|
||||
val child = event.child ?: return
|
||||
if (child.getParentOfType<KtPackageDirective>(false) != null)
|
||||
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
|
||||
}
|
||||
PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED -> {
|
||||
val parent = event.parent ?: return
|
||||
if (parent.getChildrenOfType<KtPackageDirective>().any())
|
||||
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
|
||||
}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private typealias ImplicitPackageData = MutableMap<FqName, MutableList<VirtualFile>>
|
||||
|
||||
class ImplicitPackagePrefixCache(private val project: Project) {
|
||||
private val implicitPackageCache = ConcurrentHashMap<VirtualFile, ImplicitPackageData>()
|
||||
|
||||
fun getPrefix(sourceRoot: VirtualFile): FqName {
|
||||
val implicitPackageMap = implicitPackageCache.getOrPut(sourceRoot) { analyzeImplicitPackagePrefixes(sourceRoot) }
|
||||
return implicitPackageMap.keys.singleOrNull() ?: FqName.ROOT
|
||||
}
|
||||
|
||||
internal fun clear() {
|
||||
implicitPackageCache.clear()
|
||||
}
|
||||
|
||||
private fun analyzeImplicitPackagePrefixes(sourceRoot: VirtualFile): MutableMap<FqName, MutableList<VirtualFile>> {
|
||||
val result = mutableMapOf<FqName, MutableList<VirtualFile>>()
|
||||
val ktFiles = sourceRoot.children.filter { it.fileType == KotlinFileType.INSTANCE }
|
||||
for (ktFile in ktFiles) {
|
||||
result.addFile(ktFile)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun ImplicitPackageData.addFile(ktFile: VirtualFile) {
|
||||
synchronized(this) {
|
||||
val psiFile = PsiManager.getInstance(project).findFile(ktFile) as? KtFile ?: return
|
||||
addPsiFile(psiFile, ktFile)
|
||||
}
|
||||
}
|
||||
|
||||
private fun ImplicitPackageData.addPsiFile(
|
||||
psiFile: KtFile,
|
||||
ktFile: VirtualFile
|
||||
) = getOrPut(psiFile.packageFqName) { mutableListOf() }.add(ktFile)
|
||||
|
||||
private fun ImplicitPackageData.removeFile(file: VirtualFile) {
|
||||
synchronized(this) {
|
||||
for ((key, value) in this) {
|
||||
if (value.remove(file)) {
|
||||
if (value.isEmpty()) remove(key)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ImplicitPackageData.updateFile(file: KtFile) {
|
||||
synchronized(this) {
|
||||
removeFile(file.virtualFile)
|
||||
addPsiFile(file, file.virtualFile)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun update(event: VFileEvent) {
|
||||
when (event) {
|
||||
is VFileCreateEvent -> checkNewFileInSourceRoot(event.file)
|
||||
is VFileDeleteEvent -> checkDeletedFileInSourceRoot(event.file)
|
||||
is VFileCopyEvent -> {
|
||||
val newParent = event.newParent
|
||||
if (newParent.isValid) {
|
||||
checkNewFileInSourceRoot(newParent.findChild(event.newChildName))
|
||||
}
|
||||
}
|
||||
is VFileMoveEvent -> {
|
||||
checkNewFileInSourceRoot(event.file)
|
||||
if (event.oldParent.getSourceRoot(project) == event.oldParent) {
|
||||
implicitPackageCache[event.oldParent]?.removeFile(event.file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkNewFileInSourceRoot(file: VirtualFile?) {
|
||||
if (file == null) return
|
||||
if (file.getSourceRoot(project) == file.parent) {
|
||||
implicitPackageCache[file.parent]?.addFile(file)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDeletedFileInSourceRoot(file: VirtualFile?) {
|
||||
val directory = file?.parent
|
||||
if (directory == null || !directory.isValid) return
|
||||
if (directory.getSourceRoot(project) == directory) {
|
||||
implicitPackageCache[directory]?.removeFile(file)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun update(ktFile: KtFile) {
|
||||
val parent = ktFile.virtualFile.parent
|
||||
if (ktFile.sourceRoot == parent) {
|
||||
implicitPackageCache[parent]?.updateFile(ktFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PerModulePackageCacheService(private val project: Project) {
|
||||
|
||||
/*
|
||||
* Disposal of entries handled by Module child Disposable registered in packageExists
|
||||
* Actually an StrongMap<Module, SoftMap<ModuleSourceInfo, SoftMap<FqName, Boolean>>>
|
||||
*/
|
||||
private val cache = ConcurrentHashMap<Module, ConcurrentMap<ModuleSourceInfo, ConcurrentMap<FqName, Boolean>>>()
|
||||
private val implicitPackagePrefixCache = ImplicitPackagePrefixCache(project)
|
||||
|
||||
private val pendingVFileChanges: MutableSet<VFileEvent> = mutableSetOf()
|
||||
private val pendingKtFileChanges: MutableSet<KtFile> = mutableSetOf()
|
||||
|
||||
private val projectScope = GlobalSearchScope.projectScope(project)
|
||||
|
||||
internal fun onTooComplexChange(): Unit = synchronized(this) {
|
||||
pendingVFileChanges.clear()
|
||||
pendingKtFileChanges.clear()
|
||||
cache.clear()
|
||||
implicitPackagePrefixCache.clear()
|
||||
}
|
||||
|
||||
internal fun notifyPackageChange(file: VFileEvent): Unit = synchronized(this) {
|
||||
pendingVFileChanges += file
|
||||
}
|
||||
|
||||
internal fun notifyPackageChange(file: KtFile): Unit = synchronized(this) {
|
||||
pendingKtFileChanges += file
|
||||
}
|
||||
|
||||
private fun invalidateCacheForModuleSourceInfo(moduleSourceInfo: ModuleSourceInfo) {
|
||||
val perSourceInfoData = cache[moduleSourceInfo.module] ?: return
|
||||
val dataForSourceInfo = perSourceInfoData[moduleSourceInfo] ?: return
|
||||
dataForSourceInfo.clear()
|
||||
}
|
||||
|
||||
private fun checkPendingChanges() = synchronized(this) {
|
||||
if (pendingVFileChanges.size + pendingKtFileChanges.size >= FULL_DROP_THRESHOLD) {
|
||||
onTooComplexChange()
|
||||
} else {
|
||||
pendingVFileChanges.processPending { event ->
|
||||
val vfile = event.file ?: return@processPending
|
||||
// When VirtualFile !isValid (deleted for example), it impossible to use getModuleInfoByVirtualFile
|
||||
// For directory we must check both is it in some sourceRoot, and is it contains some sourceRoot
|
||||
if (vfile.isDirectory || !vfile.isValid) {
|
||||
for ((module, data) in cache) {
|
||||
val sourceRootUrls = module.rootManager.sourceRootUrls
|
||||
if (sourceRootUrls.any { url ->
|
||||
vfile.containedInOrContains(url)
|
||||
}) {
|
||||
data.clear()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(getModuleInfoByVirtualFile(project, vfile) as? ModuleSourceInfo)?.let {
|
||||
invalidateCacheForModuleSourceInfo(it)
|
||||
}
|
||||
}
|
||||
|
||||
implicitPackagePrefixCache.update(event)
|
||||
}
|
||||
|
||||
pendingKtFileChanges.processPending { file ->
|
||||
if (file.virtualFile != null && file.virtualFile !in projectScope) {
|
||||
return@processPending
|
||||
}
|
||||
(file.getNullableModuleInfo() as? ModuleSourceInfo)?.let { invalidateCacheForModuleSourceInfo(it) }
|
||||
implicitPackagePrefixCache.update(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> MutableCollection<T>.processPending(crossinline body: (T) -> Unit) {
|
||||
this.removeIf { value ->
|
||||
try {
|
||||
body(value)
|
||||
} catch (pce: ProcessCanceledException) {
|
||||
throw pce
|
||||
} catch (exc: Exception) {
|
||||
// Log and proceed. Otherwise pending object processing won't be cleared and exception will be thrown forever.
|
||||
LOG.error(exc)
|
||||
}
|
||||
|
||||
return@removeIf true
|
||||
}
|
||||
}
|
||||
|
||||
private fun VirtualFile.containedInOrContains(root: String) =
|
||||
(VfsUtilCore.isEqualOrAncestor(url, root)
|
||||
|| isDirectory && VfsUtilCore.isEqualOrAncestor(root, url))
|
||||
|
||||
|
||||
fun packageExists(packageFqName: FqName, moduleInfo: ModuleSourceInfo): Boolean {
|
||||
val module = moduleInfo.module
|
||||
checkPendingChanges()
|
||||
|
||||
val perSourceInfoCache = cache.getOrPut(module) {
|
||||
Disposer.register(module, Disposable { cache.remove(module) })
|
||||
ContainerUtil.createConcurrentSoftMap()
|
||||
}
|
||||
val cacheForCurrentModuleInfo = perSourceInfoCache.getOrPut(moduleInfo) {
|
||||
ContainerUtil.createConcurrentSoftMap()
|
||||
}
|
||||
return cacheForCurrentModuleInfo.getOrPut(packageFqName) {
|
||||
PackageIndexUtil.packageExists(packageFqName, moduleInfo.contentScope(), project)
|
||||
}
|
||||
}
|
||||
|
||||
fun getImplicitPackagePrefix(sourceRoot: VirtualFile): FqName {
|
||||
checkPendingChanges()
|
||||
return implicitPackagePrefixCache.getPrefix(sourceRoot)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val FULL_DROP_THRESHOLD = 1000
|
||||
private val LOG = Logger.getInstance(this::class.java)
|
||||
|
||||
fun getInstance(project: Project): PerModulePackageCacheService =
|
||||
ServiceManager.getService(project, PerModulePackageCacheService::class.java)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user