mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-04-05 15:52:05 +00:00
Compare commits
102 Commits
push/mg-ja
...
junie-init
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
178087009d | ||
|
|
8bc7c3c242 | ||
|
|
8e885da677 | ||
|
|
2ce391d317 | ||
|
|
7a5a2bfcd7 | ||
|
|
5e6442b475 | ||
|
|
5498f40ce7 | ||
|
|
42242e198b | ||
|
|
6360366ecc | ||
|
|
ed0bfabc51 | ||
|
|
0a5dee567e | ||
|
|
0781156b42 | ||
|
|
2ff4f10ff0 | ||
|
|
035f1ff89f | ||
|
|
d0e25eb987 | ||
|
|
79b70a6f98 | ||
|
|
21f36ef19a | ||
|
|
0ca7fb7af5 | ||
|
|
9bc695e245 | ||
|
|
b42358f893 | ||
|
|
32518eee4b | ||
|
|
a5a79215d7 | ||
|
|
07eef9b751 | ||
|
|
a7460e9061 | ||
|
|
b5fa129540 | ||
|
|
d33b70af1a | ||
|
|
894a446585 | ||
|
|
3b21759697 | ||
|
|
24fbe0f072 | ||
|
|
4661656b8c | ||
|
|
ae558c0290 | ||
|
|
f9b601edae | ||
|
|
17ae69416c | ||
|
|
7ba8e0d9cc | ||
|
|
f90b534c4c | ||
|
|
565ea2c4f5 | ||
|
|
e2816ffabb | ||
|
|
8aceff3641 | ||
|
|
7d3830ba7d | ||
|
|
16dfdb620e | ||
|
|
0d2a514a70 | ||
|
|
b74253521e | ||
|
|
a576160847 | ||
|
|
af59955566 | ||
|
|
a4730dd57e | ||
|
|
b1bce6a29e | ||
|
|
d3de0109ca | ||
|
|
ff6de0fe6a | ||
|
|
47d0211370 | ||
|
|
5819959cce | ||
|
|
1cd321a90f | ||
|
|
16f41bd80c | ||
|
|
8ab546ba51 | ||
|
|
a5e59e09ee | ||
|
|
6d7eb2bd21 | ||
|
|
21f7e16ee6 | ||
|
|
fb1eac0985 | ||
|
|
0a6e51e47f | ||
|
|
f37d880964 | ||
|
|
301f446433 | ||
|
|
a8077aebb0 | ||
|
|
753ba99b04 | ||
|
|
a0553f4dfd | ||
|
|
c3a327e118 | ||
|
|
1a5552bef8 | ||
|
|
6660c9b26b | ||
|
|
ab158a53c3 | ||
|
|
1cdbbad367 | ||
|
|
5e87d753b7 | ||
|
|
a7cc275c7d | ||
|
|
12d694de46 | ||
|
|
16f0ba8e46 | ||
|
|
49c412b022 | ||
|
|
6ea2dea28e | ||
|
|
e7a08b14e3 | ||
|
|
7e1c776376 | ||
|
|
4049cf94b1 | ||
|
|
da72f26d94 | ||
|
|
e18c3517a9 | ||
|
|
cd08dc49a0 | ||
|
|
4edc1239ac | ||
|
|
af12d61388 | ||
|
|
3cd43dced4 | ||
|
|
a17a61341b | ||
|
|
68f14fdd87 | ||
|
|
5a26e79b08 | ||
|
|
b77dc4136b | ||
|
|
64ebddcbc6 | ||
|
|
68e7476765 | ||
|
|
1e95717b8d | ||
|
|
f64a0efa8b | ||
|
|
26ede5d885 | ||
|
|
9fb41b6334 | ||
|
|
367db345a8 | ||
|
|
dda9bb93f6 | ||
|
|
3d4e861f05 | ||
|
|
6c246738a5 | ||
|
|
dff392f2cd | ||
|
|
1857096071 | ||
|
|
50a343f91e | ||
|
|
cdfe8d60a4 | ||
|
|
0c35a3b699 |
12
.devcontainer/devcontainer.json
Normal file
12
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "Java",
|
||||
"image": "mcr.microsoft.com/devcontainers/java:1-21",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers/features/java:1": {
|
||||
"version": "none",
|
||||
"installMaven": "true",
|
||||
"mavenVersion": "3.8.6",
|
||||
"installGradle": "true"
|
||||
}
|
||||
}
|
||||
}
|
||||
22
.github/workflows/junie.yml
vendored
Normal file
22
.github/workflows/junie.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Junie
|
||||
run-name: Junie run ${{ inputs.run_id }}
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
run_id:
|
||||
description: "id of workflow process"
|
||||
required: true
|
||||
workflow_params:
|
||||
description: "stringified params"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
call-workflow-passing-data:
|
||||
uses: jetbrains-junie/junie-workflows/.github/workflows/ej-issue.yml@main
|
||||
with:
|
||||
workflow_params: ${{ inputs.workflow_params }}
|
||||
@@ -118,10 +118,10 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves information about the given (kotlinc-generated) class to this cache, and stores changes between this class and its previous
|
||||
* version into the given [ChangesCollector].
|
||||
* Saves information about the given (Kotlin) class to this cache, and stores changes between this class and its previous version into
|
||||
* the given [ChangesCollector].
|
||||
*
|
||||
* @param kotlinClassInfo A kotlin-generated class
|
||||
* @param kotlinClassInfo Information about a Kotlin class
|
||||
* @param sourceFiles The source files that the given class was generated from, or `null` if this information is not available
|
||||
* @param changesCollector A [ChangesCollector]
|
||||
*/
|
||||
@@ -129,11 +129,13 @@ open class IncrementalJvmCache(
|
||||
val className = kotlinClassInfo.className
|
||||
|
||||
dirtyOutputClassesMap.notDirty(className)
|
||||
sourceFiles?.forEach {
|
||||
sourceToClassesMap.add(it, className)
|
||||
}
|
||||
|
||||
sourceFiles?.let { internalNameToSource[className.internalName] = it }
|
||||
if (sourceFiles != null) {
|
||||
sourceFiles.forEach {
|
||||
sourceToClassesMap.add(it, className)
|
||||
}
|
||||
internalNameToSource[className.internalName] = sourceFiles
|
||||
}
|
||||
|
||||
if (kotlinClassInfo.classId.isLocal) return
|
||||
|
||||
@@ -149,8 +151,8 @@ open class IncrementalJvmCache(
|
||||
inlineFunctionsMap.process(kotlinClassInfo, changesCollector)
|
||||
}
|
||||
KotlinClassHeader.Kind.MULTIFILE_CLASS -> {
|
||||
val partNames = kotlinClassInfo.classHeaderData?.toList()
|
||||
?: throw AssertionError("Multifile class has no parts: $className")
|
||||
val partNames = kotlinClassInfo.classHeaderData.toList()
|
||||
check(partNames.isNotEmpty()) { "Multifile class has no parts: $className" }
|
||||
multifileFacadeToParts[className] = partNames
|
||||
// When a class is replaced with a facade with the same name,
|
||||
// the class' proto wouldn't ever be deleted,
|
||||
@@ -315,8 +317,8 @@ open class IncrementalJvmCache(
|
||||
val oldData = storage[key]
|
||||
val newData = ProtoMapValue(
|
||||
kotlinClassInfo.classKind != KotlinClassHeader.Kind.CLASS,
|
||||
BitEncoding.decodeBytes(kotlinClassInfo.classHeaderData!!),
|
||||
kotlinClassInfo.classHeaderStrings!!
|
||||
BitEncoding.decodeBytes(kotlinClassInfo.classHeaderData),
|
||||
kotlinClassInfo.classHeaderStrings
|
||||
)
|
||||
storage[key] = newData
|
||||
|
||||
@@ -380,7 +382,8 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
// todo: reuse code with InlineFunctionsMap?
|
||||
private inner class ConstantsMap(storageFile: File) : BasicStringMap<Map<String, Any>>(storageFile, ConstantsMapExternalizer) {
|
||||
private inner class ConstantsMap(storageFile: File) :
|
||||
BasicStringMap<LinkedHashMap<String, Any>>(storageFile, LinkedHashMapExternalizer(StringExternalizer, ConstantExternalizer)) {
|
||||
|
||||
operator fun contains(className: JvmClassName): Boolean =
|
||||
className.internalName in storage
|
||||
@@ -419,7 +422,7 @@ open class IncrementalJvmCache(
|
||||
storage.remove(className.internalName)
|
||||
}
|
||||
|
||||
override fun dumpValue(value: Map<String, Any>): String =
|
||||
override fun dumpValue(value: LinkedHashMap<String, Any>): String =
|
||||
value.dumpMap(Any::toString)
|
||||
}
|
||||
|
||||
@@ -499,12 +502,12 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
private fun addToClassStorage(classInfo: KotlinClassInfo, srcFile: File) {
|
||||
val (nameResolver, proto) = JvmProtoBufUtil.readClassDataFrom(classInfo.classHeaderData!!, classInfo.classHeaderStrings!!)
|
||||
val (nameResolver, proto) = JvmProtoBufUtil.readClassDataFrom(classInfo.classHeaderData, classInfo.classHeaderStrings)
|
||||
addToClassStorage(proto, nameResolver, srcFile)
|
||||
}
|
||||
|
||||
private inner class InlineFunctionsMap(storageFile: File) :
|
||||
BasicStringMap<Map<String, Long>>(storageFile, StringToLongMapExternalizer) {
|
||||
BasicStringMap<LinkedHashMap<String, Long>>(storageFile, LinkedHashMapExternalizer(StringExternalizer, LongExternalizer)) {
|
||||
|
||||
@Synchronized
|
||||
fun process(kotlinClassInfo: KotlinClassInfo, changesCollector: ChangesCollector) {
|
||||
@@ -537,7 +540,7 @@ open class IncrementalJvmCache(
|
||||
storage.remove(className.internalName)
|
||||
}
|
||||
|
||||
override fun dumpValue(value: Map<String, Long>): String =
|
||||
override fun dumpValue(value: LinkedHashMap<String, Long>): String =
|
||||
value.dumpMap { java.lang.Long.toHexString(it) }
|
||||
}
|
||||
}
|
||||
@@ -596,18 +599,18 @@ fun <T : Comparable<T>> Collection<T>.dumpCollection(): String =
|
||||
"[${sorted().joinToString(", ", transform = Any::toString)}]"
|
||||
|
||||
/**
|
||||
* Minimal information about a kotlinc-generated class that will be used to compute recompilation-triggered changes to support incremental
|
||||
* compilation (see [IncrementalJvmCache.saveClassToCache]).
|
||||
* Minimal information about a Kotlin class to compute recompilation-triggering changes during an incremental run of the `KotlinCompile`
|
||||
* task (see [IncrementalJvmCache.saveClassToCache]).
|
||||
*
|
||||
* It's important that this class contain only the minimal required information, as it will be part of the classpath snapshot of the
|
||||
* `KotlinCompile` task and the task needs to support compile avoidance. For example, this class should contain public method signatures,
|
||||
* and should not contain private method signatures, or method implementations.
|
||||
*/
|
||||
class KotlinClassInfo private constructor(
|
||||
class KotlinClassInfo constructor(
|
||||
val classId: ClassId,
|
||||
val classKind: KotlinClassHeader.Kind,
|
||||
val classHeaderData: Array<String>?,
|
||||
val classHeaderStrings: Array<String>?,
|
||||
val classHeaderData: Array<String>, // Can be empty
|
||||
val classHeaderStrings: Array<String>, // Can be empty
|
||||
@Suppress("SpellCheckingInspection") val multifileClassName: String?,
|
||||
val constantsMap: LinkedHashMap<String, Any>,
|
||||
val inlineFunctionsMap: LinkedHashMap<String, Long>
|
||||
@@ -628,22 +631,22 @@ class KotlinClassInfo private constructor(
|
||||
return KotlinClassInfo(
|
||||
kotlinClass.classId,
|
||||
kotlinClass.classHeader.kind,
|
||||
kotlinClass.classHeader.data,
|
||||
kotlinClass.classHeader.strings,
|
||||
kotlinClass.classHeader.data ?: emptyArray(),
|
||||
kotlinClass.classHeader.strings ?: emptyArray(),
|
||||
kotlinClass.classHeader.multifileClassName,
|
||||
getConstantsMap(kotlinClass.fileContents),
|
||||
getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
|
||||
)
|
||||
}
|
||||
|
||||
/** Creates [KotlinClassInfo] from the given classContents, or returns `null` if the class is not a kotlinc-generated class. */
|
||||
/** Creates [KotlinClassInfo] from the given classContents, or returns `null` if the class is not a Kotlin class. */
|
||||
fun tryCreateFrom(classContents: ByteArray): KotlinClassInfo? {
|
||||
return FileBasedKotlinClass.create(classContents) { classId, _, classHeader, _ ->
|
||||
KotlinClassInfo(
|
||||
classId,
|
||||
classHeader.kind,
|
||||
classHeader.data,
|
||||
classHeader.strings,
|
||||
classHeader.data ?: emptyArray(),
|
||||
classHeader.strings ?: emptyArray(),
|
||||
classHeader.multifileClassName,
|
||||
getConstantsMap(classContents),
|
||||
getInlineFunctionsMap(classHeader, classContents)
|
||||
|
||||
@@ -94,13 +94,12 @@ object ProtoMapValueExternalizer : DataExternalizer<ProtoMapValue> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
abstract class StringMapExternalizer<T> : DataExternalizer<Map<String, T>> {
|
||||
override fun save(output: DataOutput, map: Map<String, T>?) {
|
||||
output.writeInt(map!!.size)
|
||||
|
||||
for ((key, value) in map.entries) {
|
||||
IOUtil.writeString(key, output)
|
||||
output.writeString(key)
|
||||
writeValue(output, value)
|
||||
}
|
||||
}
|
||||
@@ -110,7 +109,7 @@ abstract class StringMapExternalizer<T> : DataExternalizer<Map<String, T>> {
|
||||
val map = HashMap<String, T>(size)
|
||||
|
||||
repeat(size) {
|
||||
val name = IOUtil.readString(input)!!
|
||||
val name = input.readString()
|
||||
map[name] = readValue(input)
|
||||
}
|
||||
|
||||
@@ -121,7 +120,6 @@ abstract class StringMapExternalizer<T> : DataExternalizer<Map<String, T>> {
|
||||
protected abstract fun readValue(input: DataInput): T
|
||||
}
|
||||
|
||||
|
||||
object StringToLongMapExternalizer : StringMapExternalizer<Long>() {
|
||||
override fun readValue(input: DataInput): Long = input.readLong()
|
||||
|
||||
@@ -130,58 +128,43 @@ object StringToLongMapExternalizer : StringMapExternalizer<Long>() {
|
||||
}
|
||||
}
|
||||
|
||||
object ConstantsMapExternalizer : DataExternalizer<Map<String, Any>> {
|
||||
override fun save(output: DataOutput, map: Map<String, Any>?) {
|
||||
output.writeInt(map!!.size)
|
||||
for (name in map.keys.sorted()) {
|
||||
IOUtil.writeString(name, output)
|
||||
val value = map[name]!!
|
||||
when (value) {
|
||||
is Int -> {
|
||||
output.writeByte(Kind.INT.ordinal)
|
||||
output.writeInt(value)
|
||||
}
|
||||
is Float -> {
|
||||
output.writeByte(Kind.FLOAT.ordinal)
|
||||
output.writeFloat(value)
|
||||
}
|
||||
is Long -> {
|
||||
output.writeByte(Kind.LONG.ordinal)
|
||||
output.writeLong(value)
|
||||
}
|
||||
is Double -> {
|
||||
output.writeByte(Kind.DOUBLE.ordinal)
|
||||
output.writeDouble(value)
|
||||
}
|
||||
is String -> {
|
||||
output.writeByte(Kind.STRING.ordinal)
|
||||
IOUtil.writeString(value, output)
|
||||
}
|
||||
else -> throw IllegalStateException("Unexpected constant class: ${value::class.java}")
|
||||
/** [DataExternalizer] for a Kotlin constant. */
|
||||
object ConstantExternalizer : DataExternalizer<Any> {
|
||||
|
||||
override fun save(output: DataOutput, value: Any) {
|
||||
when (value) {
|
||||
is Int -> {
|
||||
output.writeByte(Kind.INT.ordinal)
|
||||
output.writeInt(value)
|
||||
}
|
||||
is Float -> {
|
||||
output.writeByte(Kind.FLOAT.ordinal)
|
||||
output.writeFloat(value)
|
||||
}
|
||||
is Long -> {
|
||||
output.writeByte(Kind.LONG.ordinal)
|
||||
output.writeLong(value)
|
||||
}
|
||||
is Double -> {
|
||||
output.writeByte(Kind.DOUBLE.ordinal)
|
||||
output.writeDouble(value)
|
||||
}
|
||||
is String -> {
|
||||
output.writeByte(Kind.STRING.ordinal)
|
||||
output.writeString(value)
|
||||
}
|
||||
else -> throw IllegalStateException("Unexpected constant class: ${value::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun read(input: DataInput): Map<String, Any> {
|
||||
val size = input.readInt()
|
||||
val map = HashMap<String, Any>(size)
|
||||
|
||||
repeat(size) {
|
||||
val name = IOUtil.readString(input)!!
|
||||
val kind = Kind.values()[input.readByte().toInt()]
|
||||
|
||||
val value: Any = when (kind) {
|
||||
Kind.INT -> input.readInt()
|
||||
Kind.FLOAT -> input.readFloat()
|
||||
Kind.LONG -> input.readLong()
|
||||
Kind.DOUBLE -> input.readDouble()
|
||||
Kind.STRING -> IOUtil.readString(input)!!
|
||||
}
|
||||
|
||||
map[name] = value
|
||||
override fun read(input: DataInput): Any {
|
||||
return when (Kind.values()[input.readByte().toInt()]) {
|
||||
Kind.INT -> input.readInt()
|
||||
Kind.FLOAT -> input.readFloat()
|
||||
Kind.LONG -> input.readLong()
|
||||
Kind.DOUBLE -> input.readDouble()
|
||||
Kind.STRING -> input.readString()
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
||||
|
||||
private enum class Kind {
|
||||
@@ -190,11 +173,18 @@ object ConstantsMapExternalizer : DataExternalizer<Map<String, Any>> {
|
||||
}
|
||||
|
||||
object IntExternalizer : DataExternalizer<Int> {
|
||||
override fun save(output: DataOutput, value: Int) = output.writeInt(value)
|
||||
override fun read(input: DataInput): Int = input.readInt()
|
||||
}
|
||||
|
||||
override fun save(output: DataOutput, value: Int) {
|
||||
output.writeInt(value)
|
||||
}
|
||||
object LongExternalizer : DataExternalizer<Long> {
|
||||
override fun save(output: DataOutput, value: Long) = output.writeLong(value)
|
||||
override fun read(input: DataInput): Long = input.readLong()
|
||||
}
|
||||
|
||||
object StringExternalizer : DataExternalizer<String> {
|
||||
override fun save(output: DataOutput, value: String) = IOUtil.writeString(value, output)
|
||||
override fun read(input: DataInput): String = IOUtil.readString(input)
|
||||
}
|
||||
|
||||
|
||||
@@ -244,3 +234,69 @@ open class CollectionExternalizer<T>(
|
||||
object StringCollectionExternalizer : CollectionExternalizer<String>(EnumeratorStringDescriptor(), { HashSet() })
|
||||
|
||||
object IntCollectionExternalizer : CollectionExternalizer<Int>(IntExternalizer, { HashSet() })
|
||||
|
||||
fun DataOutput.writeString(value: String) = StringExternalizer.save(this, value)
|
||||
|
||||
fun DataInput.readString(): String = StringExternalizer.read(this)
|
||||
|
||||
class ListExternalizer<T>(
|
||||
private val elementExternalizer: DataExternalizer<T>
|
||||
) : DataExternalizer<List<T>> {
|
||||
|
||||
override fun save(output: DataOutput, value: List<T>) {
|
||||
output.writeInt(value.size)
|
||||
value.forEach {
|
||||
elementExternalizer.save(output, it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun read(input: DataInput): List<T> {
|
||||
val size = input.readInt()
|
||||
val list = ArrayList<T>(size)
|
||||
repeat(size) {
|
||||
list.add(elementExternalizer.read(input))
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
class LinkedHashMapExternalizer<K, V>(
|
||||
private val keyExternalizer: DataExternalizer<K>,
|
||||
private val valueExternalizer: DataExternalizer<V>
|
||||
) : DataExternalizer<LinkedHashMap<K, V>> {
|
||||
|
||||
override fun save(output: DataOutput, map: LinkedHashMap<K, V>) {
|
||||
output.writeInt(map.size)
|
||||
for ((key, value) in map) {
|
||||
keyExternalizer.save(output, key)
|
||||
valueExternalizer.save(output, value)
|
||||
}
|
||||
}
|
||||
|
||||
override fun read(input: DataInput): LinkedHashMap<K, V> {
|
||||
val size = input.readInt()
|
||||
val map = LinkedHashMap<K, V>(size)
|
||||
repeat(size) {
|
||||
val key = keyExternalizer.read(input)
|
||||
val value = valueExternalizer.read(input)
|
||||
map[key] = value
|
||||
}
|
||||
return map
|
||||
}
|
||||
}
|
||||
|
||||
class NullableValueExternalizer<T>(private val valueExternalizer: DataExternalizer<T>) : DataExternalizer<T> {
|
||||
|
||||
override fun save(output: DataOutput, value: T?) {
|
||||
output.writeBoolean(value != null)
|
||||
value?.let {
|
||||
valueExternalizer.save(output, it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun read(input: DataInput): T? {
|
||||
return if (input.readBoolean()) {
|
||||
valueExternalizer.read(input)
|
||||
} else null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ extra["versions.kotlinx-collections-immutable-jvm"] = immutablesVersion
|
||||
extra["versions.ktor-network"] = "1.0.1"
|
||||
|
||||
if (!project.hasProperty("versions.kotlin-native")) {
|
||||
extra["versions.kotlin-native"] = "1.6.0-dev-1728"
|
||||
extra["versions.kotlin-native"] = "1.6.0-dev-2972"
|
||||
}
|
||||
|
||||
val useJvmFir by extra(project.kotlinBuildProperties.useFir)
|
||||
|
||||
@@ -39,7 +39,6 @@ internal class MethodNodeExaminer(
|
||||
private val popsBeforeSafeUnitInstances = mutableSetOf<AbstractInsnNode>()
|
||||
private val areturnsAfterSafeUnitInstances = mutableSetOf<AbstractInsnNode>()
|
||||
private val meaningfulSuccessorsCache = hashMapOf<AbstractInsnNode, List<AbstractInsnNode>>()
|
||||
private val meaningfulPredecessorsCache = hashMapOf<AbstractInsnNode, List<AbstractInsnNode>>()
|
||||
|
||||
init {
|
||||
if (!disableTailCallOptimizationForFunctionReturningUnit) {
|
||||
@@ -52,10 +51,8 @@ internal class MethodNodeExaminer(
|
||||
for (pop in popsBeforeUnitInstances) {
|
||||
val units = pop.meaningfulSuccessors()
|
||||
val allUnitsAreSafe = units.all { unit ->
|
||||
// check no other predecessor exists
|
||||
unit.meaningfulPredecessors().all { it in popsBeforeUnitInstances } &&
|
||||
// check they have only returns among successors
|
||||
unit.meaningfulSuccessors().all { it.opcode == Opcodes.ARETURN }
|
||||
// check they have only returns among successors
|
||||
unit.meaningfulSuccessors().all { it.opcode == Opcodes.ARETURN }
|
||||
}
|
||||
if (!allUnitsAreSafe) continue
|
||||
// save them all to the properties
|
||||
@@ -74,35 +71,22 @@ internal class MethodNodeExaminer(
|
||||
private fun AbstractInsnNode.isAreturnAfterSafeUnitInstance(): Boolean = this in areturnsAfterSafeUnitInstances
|
||||
|
||||
private fun AbstractInsnNode.meaningfulSuccessors(): List<AbstractInsnNode> = meaningfulSuccessorsCache.getOrPut(this) {
|
||||
meaningfulSuccessorsOrPredecessors(true)
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.meaningfulPredecessors(): List<AbstractInsnNode> = meaningfulPredecessorsCache.getOrPut(this) {
|
||||
meaningfulSuccessorsOrPredecessors(false)
|
||||
}
|
||||
|
||||
private fun AbstractInsnNode.meaningfulSuccessorsOrPredecessors(isSuccessors: Boolean): List<AbstractInsnNode> {
|
||||
fun AbstractInsnNode.isMeaningful() = isMeaningful && opcode != Opcodes.NOP && opcode != Opcodes.GOTO && this !is LineNumberNode
|
||||
|
||||
fun AbstractInsnNode.getIndices() =
|
||||
if (isSuccessors) controlFlowGraph.getSuccessorsIndices(this)
|
||||
else controlFlowGraph.getPredecessorsIndices(this)
|
||||
|
||||
val visited = mutableSetOf<AbstractInsnNode>()
|
||||
fun dfs(insn: AbstractInsnNode) {
|
||||
if (insn in visited) return
|
||||
visited += insn
|
||||
if (!insn.isMeaningful()) {
|
||||
for (succIndex in insn.getIndices()) {
|
||||
for (succIndex in controlFlowGraph.getSuccessorsIndices(insn)) {
|
||||
dfs(methodNode.instructions[succIndex])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (succIndex in getIndices()) {
|
||||
for (succIndex in controlFlowGraph.getSuccessorsIndices(this)) {
|
||||
dfs(methodNode.instructions[succIndex])
|
||||
}
|
||||
return visited.filter { it.isMeaningful() }
|
||||
visited.filter { it.isMeaningful() }
|
||||
}
|
||||
|
||||
fun replacePopsBeforeSafeUnitInstancesWithCoroutineSuspendedChecks() {
|
||||
|
||||
@@ -520,13 +520,10 @@ class AnonymousObjectTransformer(
|
||||
val paramTypes = transformationInfo.constructorDesc?.let { Type.getArgumentTypes(it) } ?: emptyArray()
|
||||
for (type in paramTypes) {
|
||||
val info = indexToFunctionalArgument[constructorParamBuilder.nextParameterOffset]
|
||||
val isCaptured = capturedParams.contains(constructorParamBuilder.nextParameterOffset)
|
||||
val parameterInfo = constructorParamBuilder.addNextParameter(type, info is LambdaInfo)
|
||||
parameterInfo.functionalArgument = info
|
||||
if (capturedParams.contains(parameterInfo.index)) {
|
||||
parameterInfo.isCaptured = true
|
||||
} else {
|
||||
//otherwise it's super constructor parameter
|
||||
}
|
||||
parameterInfo.isCaptured = isCaptured
|
||||
}
|
||||
|
||||
//For all inlined lambdas add their captured parameters
|
||||
|
||||
@@ -32,7 +32,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
private val initialFrameSize = codegen.frameMap.currentSize
|
||||
|
||||
protected val invocationParamBuilder = ParametersBuilder.newBuilder()
|
||||
protected val expressionMap = linkedMapOf<Int, FunctionalArgument>()
|
||||
private val maskValues = ArrayList<Int>()
|
||||
private var maskStartIndex = -1
|
||||
private var methodHandleInDefaultMethodIndex = -1
|
||||
@@ -80,8 +79,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
for (info in infos) {
|
||||
val lambda = DefaultLambda(info, sourceCompiler)
|
||||
parameters.getParameterByDeclarationSlot(info.offset).functionalArgument = lambda
|
||||
val prev = expressionMap.put(info.offset, lambda)
|
||||
assert(prev == null) { "Lambda with offset ${info.offset} already exists: $prev" }
|
||||
if (info.needReification) {
|
||||
lambda.reifiedTypeParametersUsages.mergeAll(reifiedTypeInliner.reifyInstructions(lambda.node.node))
|
||||
}
|
||||
@@ -98,7 +95,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
val parameters = invocationParamBuilder.buildParameters()
|
||||
|
||||
val info = RootInliningContext(
|
||||
expressionMap, state, codegen.inlineNameGenerator.subGenerator(jvmSignature.asmMethod.name),
|
||||
state, codegen.inlineNameGenerator.subGenerator(jvmSignature.asmMethod.name),
|
||||
sourceCompiler, sourceCompiler.inlineCallSiteInfo, reifiedTypeInliner, typeParameterMappings
|
||||
)
|
||||
|
||||
@@ -213,9 +210,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
}
|
||||
|
||||
protected fun rememberClosure(parameterType: Type, index: Int, lambdaInfo: LambdaInfo) {
|
||||
val closureInfo = invocationParamBuilder.addNextValueParameter(parameterType, true, null, index)
|
||||
closureInfo.functionalArgument = lambdaInfo
|
||||
expressionMap[closureInfo.index] = lambdaInfo
|
||||
invocationParamBuilder.addNextValueParameter(parameterType, true, null, index).functionalArgument = lambdaInfo
|
||||
}
|
||||
|
||||
protected fun putCapturedToLocalVal(stackValue: StackValue, capturedParam: CapturedParamDesc, kotlinType: KotlinType?) {
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.codegen.ClassBuilder
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
|
||||
class RootInliningContext(
|
||||
expressionMap: Map<Int, FunctionalArgument>,
|
||||
state: GenerationState,
|
||||
nameGenerator: NameGenerator,
|
||||
val sourceCompilerForInline: SourceCompilerForInline,
|
||||
@@ -17,12 +16,11 @@ class RootInliningContext(
|
||||
val inlineMethodReifier: ReifiedTypeInliner<*>,
|
||||
typeParameterMappings: TypeParameterMappings<*>
|
||||
) : InliningContext(
|
||||
null, expressionMap, state, nameGenerator, TypeRemapper.createRoot(typeParameterMappings), null, false
|
||||
null, state, nameGenerator, TypeRemapper.createRoot(typeParameterMappings), null, false
|
||||
)
|
||||
|
||||
class RegeneratedClassContext(
|
||||
parent: InliningContext,
|
||||
expressionMap: Map<Int, FunctionalArgument>,
|
||||
state: GenerationState,
|
||||
nameGenerator: NameGenerator,
|
||||
typeRemapper: TypeRemapper,
|
||||
@@ -30,14 +28,13 @@ class RegeneratedClassContext(
|
||||
override val callSiteInfo: InlineCallSiteInfo,
|
||||
override val transformationInfo: TransformationInfo
|
||||
) : InliningContext(
|
||||
parent, expressionMap, state, nameGenerator, typeRemapper, lambdaInfo, true
|
||||
parent, state, nameGenerator, typeRemapper, lambdaInfo, true
|
||||
) {
|
||||
val continuationBuilders: MutableMap<String, ClassBuilder> = hashMapOf()
|
||||
}
|
||||
|
||||
open class InliningContext(
|
||||
val parent: InliningContext?,
|
||||
val expressionMap: Map<Int, FunctionalArgument>,
|
||||
val state: GenerationState,
|
||||
val nameGenerator: NameGenerator,
|
||||
val typeRemapper: TypeRemapper,
|
||||
@@ -97,7 +94,7 @@ open class InliningContext(
|
||||
callSiteInfo: InlineCallSiteInfo,
|
||||
transformationInfo: TransformationInfo
|
||||
): InliningContext = RegeneratedClassContext(
|
||||
this, expressionMap, state, generator, TypeRemapper.createFrom(typeRemapper, newTypeMappings),
|
||||
this, state, generator, TypeRemapper.createFrom(typeRemapper, newTypeMappings),
|
||||
lambdaInfo, callSiteInfo, transformationInfo
|
||||
)
|
||||
|
||||
@@ -110,7 +107,7 @@ open class InliningContext(
|
||||
): InliningContext {
|
||||
val isInliningLambda = lambdaInfo != null
|
||||
return InliningContext(
|
||||
this, expressionMap, state, generator,
|
||||
this, state, generator,
|
||||
TypeRemapper.createFrom(
|
||||
typeRemapper,
|
||||
additionalTypeMappings,
|
||||
|
||||
@@ -62,19 +62,16 @@ class PsiInlineCodegen(
|
||||
return
|
||||
}
|
||||
try {
|
||||
val registerLineNumber = registerLineNumberAfterwards(resolvedCall)
|
||||
for (info in expressionMap.values) {
|
||||
if (info is PsiExpressionLambda) {
|
||||
// Can't be done immediately in `rememberClosure` for some reason:
|
||||
info.generateLambdaBody(sourceCompiler)
|
||||
// Requires `generateLambdaBody` first if the closure is non-empty (for bound callable references,
|
||||
// or indeed any callable references, it *is* empty, so this was done in `rememberClosure`):
|
||||
if (!info.isBoundCallableReference) {
|
||||
putClosureParametersOnStack(info, null)
|
||||
}
|
||||
for (info in closuresToGenerate) {
|
||||
// Can't be done immediately in `rememberClosure` for some reason:
|
||||
info.generateLambdaBody(sourceCompiler)
|
||||
// Requires `generateLambdaBody` first if the closure is non-empty (for bound callable references,
|
||||
// or indeed any callable references, it *is* empty, so this was done in `rememberClosure`):
|
||||
if (!info.isBoundCallableReference) {
|
||||
putClosureParametersOnStack(info, null)
|
||||
}
|
||||
}
|
||||
performInline(registerLineNumber, functionDescriptor.isInlineOnly())
|
||||
performInline(registerLineNumberAfterwards(resolvedCall), functionDescriptor.isInlineOnly())
|
||||
} finally {
|
||||
state.globalInlineContext.exitFromInlining()
|
||||
}
|
||||
@@ -144,6 +141,8 @@ class PsiInlineCodegen(
|
||||
private fun isCallSiteIsSuspend(descriptor: ValueParameterDescriptor): Boolean =
|
||||
state.bindingContext[CodegenBinding.CALL_SITE_IS_SUSPEND_FOR_CROSSINLINE_LAMBDA, descriptor] == true
|
||||
|
||||
private val closuresToGenerate = mutableListOf<PsiExpressionLambda>()
|
||||
|
||||
private fun rememberClosure(expression: KtExpression, type: Type, parameter: ValueParameterDescriptor) {
|
||||
val ktLambda = KtPsiUtil.deparenthesize(expression)
|
||||
assert(isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" }
|
||||
@@ -155,6 +154,7 @@ class PsiInlineCodegen(
|
||||
|
||||
val lambda = PsiExpressionLambda(ktLambda!!, state, parameter.isCrossinline, boundReceiver != null)
|
||||
rememberClosure(type, parameter.index, lambda)
|
||||
closuresToGenerate += lambda
|
||||
if (boundReceiver != null) {
|
||||
// Has to be done immediately to preserve evaluation order.
|
||||
val receiver = codegen.generateReceiverValue(boundReceiver, false)
|
||||
|
||||
@@ -12,7 +12,7 @@ fun test() {
|
||||
|
||||
bar(1, z = true, y = *arrayOf("my", "yours"))
|
||||
|
||||
bar(0, z = false, y = "", <!ARGUMENT_PASSED_TWICE!>y<!> = "other")
|
||||
bar(0, z = false, y = <!ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION_ERROR!>""<!>, <!ARGUMENT_PASSED_TWICE!>y<!> = "other")
|
||||
bar(0, "", true<!NO_VALUE_FOR_PARAMETER!>)<!>
|
||||
bar(0, z = false, y = "", <!ARGUMENT_PASSED_TWICE!>y<!> = "other", <!ARGUMENT_PASSED_TWICE!>y<!> = "yet other")
|
||||
bar(0, z = false, y = <!ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION_ERROR!>""<!>, <!ARGUMENT_PASSED_TWICE!>y<!> = "other", <!ARGUMENT_PASSED_TWICE!>y<!> = "yet other")
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@ interface B {
|
||||
}
|
||||
|
||||
interface C {
|
||||
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun toString(): String = "Rest"<!>
|
||||
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun toString(): String = "Rest"<!>
|
||||
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun equals(other: Any?): Boolean = false<!>
|
||||
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override operator fun hashCode(): Int = 2<!>
|
||||
<!METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE!>override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hashCode(): Int = 2<!>
|
||||
}
|
||||
|
||||
interface D {
|
||||
override operator fun toString(): String
|
||||
override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun toString(): String
|
||||
override operator fun equals(other: Any?): Boolean
|
||||
override operator fun hashCode(): Int
|
||||
override <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hashCode(): Int
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ FILE: test.kt
|
||||
private final val DERIVED_FACTORY: R|DiagnosticFactory0<ft<DerivedElement, DerivedElement?>>| = R|/DiagnosticFactory0.DiagnosticFactory0|<R|ft<DerivedElement, DerivedElement?>|>()
|
||||
private get(): R|DiagnosticFactory0<ft<DerivedElement, DerivedElement?>>|
|
||||
public final fun createViaFactory(d: R|EmptyDiagnostic|): R|kotlin/Unit| {
|
||||
lval casted: R|Diagnostic<ft<DerivedElement, DerivedElement?>>| = R|/DERIVED_FACTORY|.R|SubstitutionOverride</DiagnosticFactory0.cast: R|Diagnostic<ft<DerivedElement, DerivedElement?>>|>|(R|<local>/d|)
|
||||
lval casted: R|Diagnostic<ft<DerivedElement, DerivedElement?>>| = R|/DERIVED_FACTORY|.R|SubstitutionOverride</DiagnosticFactory0.cast: R|@EnhancedNullability Diagnostic<ft<DerivedElement, DerivedElement?>>|>|(R|<local>/d|)
|
||||
lval element: R|DerivedElement| = R|<local>/casted|.R|/Diagnostic.element|
|
||||
R|/Fix.Fix|(R|<local>/element|)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ abstract class NotRange4() {
|
||||
}
|
||||
|
||||
abstract class ImproperIterator3 {
|
||||
abstract operator fun hasNext() : Int
|
||||
abstract <!INAPPLICABLE_OPERATOR_MODIFIER!>operator<!> fun hasNext() : Int
|
||||
abstract operator fun next() : Int
|
||||
}
|
||||
|
||||
|
||||
@@ -16855,6 +16855,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/innerNestedClassFromJava.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("integerNotNullable.kt")
|
||||
public void testIntegerNotNullable() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/integerNotNullable.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invisiblePackagePrivateInheritedMember.kt")
|
||||
public void testInvisiblePackagePrivateInheritedMember() throws Exception {
|
||||
@@ -21700,6 +21706,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinOutProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinStarProjection.kt")
|
||||
public void testKotlinStarProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinStarProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("listSuperType.kt")
|
||||
public void testListSuperType() throws Exception {
|
||||
@@ -28046,6 +28058,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("otherModuleInheritance.kt")
|
||||
public void testOtherModuleInheritance() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protected.kt")
|
||||
public void testProtected() throws Exception {
|
||||
|
||||
@@ -16855,6 +16855,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/innerNestedClassFromJava.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("integerNotNullable.kt")
|
||||
public void testIntegerNotNullable() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/j+k/integerNotNullable.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("invisiblePackagePrivateInheritedMember.kt")
|
||||
public void testInvisiblePackagePrivateInheritedMember() throws Exception {
|
||||
@@ -21700,6 +21706,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinOutProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinStarProjection.kt")
|
||||
public void testKotlinStarProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinStarProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("listSuperType.kt")
|
||||
public void testListSuperType() throws Exception {
|
||||
@@ -28046,6 +28058,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModule.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("otherModuleInheritance.kt")
|
||||
public void testOtherModuleInheritance() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/publicVals/otherModuleInheritance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("protected.kt")
|
||||
public void testProtected() throws Exception {
|
||||
|
||||
@@ -29,6 +29,7 @@ fun main(args: Array<String>) {
|
||||
alias<FirStatement>("BasicExpressionChecker")
|
||||
alias<FirQualifiedAccess>("QualifiedAccessChecker")
|
||||
alias<FirQualifiedAccessExpression>("QualifiedAccessExpressionChecker")
|
||||
alias<FirCall>("CallChecker")
|
||||
alias<FirFunctionCall>("FunctionCallChecker")
|
||||
alias<FirVariableAssignment>("VariableAssignmentChecker")
|
||||
alias<FirTryExpression>("TryExpressionChecker")
|
||||
|
||||
@@ -301,35 +301,35 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val MODIFIERS by object : DiagnosticGroup("Modifiers") {
|
||||
val INAPPLICABLE_INFIX_MODIFIER by error<PsiElement>()
|
||||
val REPEATED_MODIFIER by error<PsiElement> {
|
||||
parameter<String>("modifier")
|
||||
parameter<KtModifierKeywordToken>("modifier")
|
||||
}
|
||||
val REDUNDANT_MODIFIER by error<PsiElement> {
|
||||
parameter<String>("redundantModifier")
|
||||
parameter<String>("conflictingModifier")
|
||||
parameter<KtModifierKeywordToken>("redundantModifier")
|
||||
parameter<KtModifierKeywordToken>("conflictingModifier")
|
||||
}
|
||||
val DEPRECATED_MODIFIER by warning<PsiElement> {
|
||||
parameter<String>("deprecatedModifier")
|
||||
parameter<String>("actualModifier")
|
||||
parameter<KtModifierKeywordToken>("deprecatedModifier")
|
||||
parameter<KtModifierKeywordToken>("actualModifier")
|
||||
}
|
||||
val DEPRECATED_MODIFIER_PAIR by error<PsiElement> {
|
||||
parameter<String>("deprecatedModifier")
|
||||
parameter<String>("conflictingModifier")
|
||||
parameter<KtModifierKeywordToken>("deprecatedModifier")
|
||||
parameter<KtModifierKeywordToken>("conflictingModifier")
|
||||
}
|
||||
val DEPRECATED_MODIFIER_FOR_TARGET by warning<PsiElement> {
|
||||
parameter<String>("deprecatedModifier")
|
||||
parameter<KtModifierKeywordToken>("deprecatedModifier")
|
||||
parameter<String>("target")
|
||||
}
|
||||
val REDUNDANT_MODIFIER_FOR_TARGET by warning<PsiElement> {
|
||||
parameter<String>("redundantModifier")
|
||||
parameter<KtModifierKeywordToken>("redundantModifier")
|
||||
parameter<String>("target")
|
||||
}
|
||||
val INCOMPATIBLE_MODIFIERS by error<PsiElement> {
|
||||
parameter<String>("modifier1")
|
||||
parameter<String>("modifier2")
|
||||
parameter<KtModifierKeywordToken>("modifier1")
|
||||
parameter<KtModifierKeywordToken>("modifier2")
|
||||
}
|
||||
val REDUNDANT_OPEN_IN_INTERFACE by warning<KtModifierListOwner>(PositioningStrategy.OPEN_MODIFIER)
|
||||
val WRONG_MODIFIER_TARGET by error<PsiElement> {
|
||||
parameter<String>("modifier")
|
||||
parameter<KtModifierKeywordToken>("modifier")
|
||||
parameter<String>("target")
|
||||
}
|
||||
val OPERATOR_MODIFIER_REQUIRED by error<PsiElement> {
|
||||
@@ -340,13 +340,16 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<FirNamedFunctionSymbol>("functionSymbol")
|
||||
}
|
||||
val WRONG_MODIFIER_CONTAINING_DECLARATION by error<PsiElement> {
|
||||
parameter<String>("modifier")
|
||||
parameter<KtModifierKeywordToken>("modifier")
|
||||
parameter<String>("target")
|
||||
}
|
||||
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning<PsiElement> {
|
||||
parameter<String>("modifier")
|
||||
parameter<KtModifierKeywordToken>("modifier")
|
||||
parameter<String>("target")
|
||||
}
|
||||
val INAPPLICABLE_OPERATOR_MODIFIER by error<PsiElement>(PositioningStrategy.OPERATOR_MODIFIER) {
|
||||
parameter<String>("message")
|
||||
}
|
||||
}
|
||||
|
||||
val INLINE_CLASSES by object : DiagnosticGroup("Inline classes") {
|
||||
@@ -442,6 +445,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
}
|
||||
|
||||
val SPREAD_OF_NULLABLE by error<PsiElement>(PositioningStrategy.SPREAD_OPERATOR)
|
||||
|
||||
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)
|
||||
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError<KtExpression>(LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm)
|
||||
}
|
||||
|
||||
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
|
||||
@@ -1115,6 +1121,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<ConeKotlinType>("leftType")
|
||||
parameter<ConeKotlinType>("rightType")
|
||||
}
|
||||
val INC_DEC_SHOULD_NOT_RETURN_UNIT by error<KtExpression>(PositioningStrategy.OPERATOR)
|
||||
val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT by error<KtExpression>(PositioningStrategy.OPERATOR) {
|
||||
parameter<FirNamedFunctionSymbol>("functionSymbol")
|
||||
parameter<String>("operator")
|
||||
}
|
||||
}
|
||||
|
||||
val TYPE_ALIAS by object : DiagnosticGroup("Type alias") {
|
||||
@@ -1258,13 +1269,6 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val RETURN_FOR_BUILT_IN_SUSPEND by error<KtReturnExpression>()
|
||||
}
|
||||
|
||||
val JVM by object : DiagnosticGroup("jvm") {
|
||||
val JAVA_TYPE_MISMATCH by error<KtExpression> {
|
||||
parameter<ConeKotlinType>("expectedType")
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = {
|
||||
|
||||
@@ -6,8 +6,14 @@
|
||||
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
|
||||
@Suppress("UNUSED_VARIABLE", "LocalVariableName", "ClassName", "unused")
|
||||
@OptIn(PrivateForInline::class)
|
||||
@@ -15,4 +21,44 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
|
||||
val DECLARATIONS by object : DiagnosticGroup("Declarations") {
|
||||
val CONFLICTING_JVM_DECLARATIONS by error<PsiElement>()
|
||||
}
|
||||
|
||||
val TYPES by object : DiagnosticGroup("Types") {
|
||||
val JAVA_TYPE_MISMATCH by error<KtExpression> {
|
||||
parameter<ConeKotlinType>("expectedType")
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
}
|
||||
}
|
||||
|
||||
val TYPE_PARAMETERS by object : DiagnosticGroup("Type parameters") {
|
||||
val UPPER_BOUND_CANNOT_BE_ARRAY by error<PsiElement>()
|
||||
}
|
||||
|
||||
val ANNOTATIONS by object : DiagnosticGroup("annotations") {
|
||||
val STRICTFP_ON_CLASS by error<KtAnnotationEntry>()
|
||||
val VOLATILE_ON_VALUE by error<KtAnnotationEntry>()
|
||||
val VOLATILE_ON_DELEGATE by error<KtAnnotationEntry>()
|
||||
val SYNCHRONIZED_ON_ABSTRACT by error<KtAnnotationEntry>()
|
||||
val SYNCHRONIZED_IN_INTERFACE by error<KtAnnotationEntry>()
|
||||
val SYNCHRONIZED_ON_INLINE by warning<KtAnnotationEntry>()
|
||||
val OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS by warning<KtAnnotationEntry>()
|
||||
val OVERLOADS_ABSTRACT by error<KtAnnotationEntry>()
|
||||
val OVERLOADS_INTERFACE by error<KtAnnotationEntry>()
|
||||
val OVERLOADS_LOCAL by error<KtAnnotationEntry>()
|
||||
val OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR by deprecationError<KtAnnotationEntry>(LanguageFeature.ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses)
|
||||
val OVERLOADS_PRIVATE by warning<KtAnnotationEntry>()
|
||||
val DEPRECATED_JAVA_ANNOTATION by warning<KtAnnotationEntry>() {
|
||||
parameter<FqName>("kotlinName")
|
||||
}
|
||||
|
||||
val JVM_PACKAGE_NAME_CANNOT_BE_EMPTY by error<KtAnnotationEntry>()
|
||||
val JVM_PACKAGE_NAME_MUST_BE_VALID_NAME by error<KtAnnotationEntry>()
|
||||
val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error<KtAnnotationEntry>()
|
||||
}
|
||||
|
||||
val SUPER by object : DiagnosticGroup("Super") {
|
||||
val SUPER_CALL_WITH_DEFAULT_PARAMETERS by error<PsiElement>() {
|
||||
parameter<String>("name")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
ABSTRACT_MODIFIER,
|
||||
LABEL,
|
||||
COMMAS,
|
||||
OPERATOR_MODIFIER,
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -6,7 +6,12 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.diagnostics.jvm
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
/*
|
||||
* This file was generated automatically
|
||||
@@ -17,4 +22,31 @@ object FirJvmErrors {
|
||||
// Declarations
|
||||
val CONFLICTING_JVM_DECLARATIONS by error0<PsiElement>()
|
||||
|
||||
// Types
|
||||
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||
|
||||
// Type parameters
|
||||
val UPPER_BOUND_CANNOT_BE_ARRAY by error0<PsiElement>()
|
||||
|
||||
// annotations
|
||||
val STRICTFP_ON_CLASS by error0<KtAnnotationEntry>()
|
||||
val VOLATILE_ON_VALUE by error0<KtAnnotationEntry>()
|
||||
val VOLATILE_ON_DELEGATE by error0<KtAnnotationEntry>()
|
||||
val SYNCHRONIZED_ON_ABSTRACT by error0<KtAnnotationEntry>()
|
||||
val SYNCHRONIZED_IN_INTERFACE by error0<KtAnnotationEntry>()
|
||||
val SYNCHRONIZED_ON_INLINE by warning0<KtAnnotationEntry>()
|
||||
val OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS by warning0<KtAnnotationEntry>()
|
||||
val OVERLOADS_ABSTRACT by error0<KtAnnotationEntry>()
|
||||
val OVERLOADS_INTERFACE by error0<KtAnnotationEntry>()
|
||||
val OVERLOADS_LOCAL by error0<KtAnnotationEntry>()
|
||||
val OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR by deprecationError0<KtAnnotationEntry>(ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses)
|
||||
val OVERLOADS_PRIVATE by warning0<KtAnnotationEntry>()
|
||||
val DEPRECATED_JAVA_ANNOTATION by warning1<KtAnnotationEntry, FqName>()
|
||||
val JVM_PACKAGE_NAME_CANNOT_BE_EMPTY by error0<KtAnnotationEntry>()
|
||||
val JVM_PACKAGE_NAME_MUST_BE_VALID_NAME by error0<KtAnnotationEntry>()
|
||||
val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error0<KtAnnotationEntry>()
|
||||
|
||||
// Super
|
||||
val SUPER_CALL_WITH_DEFAULT_PARAMETERS by error1<PsiElement, String>()
|
||||
|
||||
}
|
||||
|
||||
@@ -5,13 +5,33 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.jvm.checkers
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration.FirJvmExternalDeclarationChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.*
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.declaration.*
|
||||
|
||||
object JvmDeclarationCheckers : DeclarationCheckers() {
|
||||
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
|
||||
get() = setOf(
|
||||
FirJvmExternalDeclarationChecker,
|
||||
)
|
||||
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
get() = setOf(
|
||||
FirStrictfpApplicabilityChecker,
|
||||
)
|
||||
|
||||
override val propertyCheckers: Set<FirPropertyChecker>
|
||||
get() = setOf(
|
||||
FirVolatileAnnotationChecker,
|
||||
)
|
||||
|
||||
override val functionCheckers: Set<FirFunctionChecker>
|
||||
get() = setOf(
|
||||
FirSynchronizedAnnotationChecker,
|
||||
FirOverloadsChecker,
|
||||
)
|
||||
|
||||
override val typeParameterCheckers: Set<FirTypeParameterChecker>
|
||||
get() = setOf(
|
||||
FirUpperBoundsChecker,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,12 +6,23 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.jvm.checkers
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirDeprecatedJavaAnnotationsChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirJavaGenericVarianceViolationTypeChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirJvmPackageNameAnnotationsChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirSuperCallWithDefaultsChecker
|
||||
|
||||
object JvmExpressionCheckers : ExpressionCheckers() {
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
get() = setOf(
|
||||
FirJavaGenericVarianceViolationTypeChecker,
|
||||
FirSuperCallWithDefaultsChecker,
|
||||
)
|
||||
|
||||
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
|
||||
get() = setOf(
|
||||
FirDeprecatedJavaAnnotationsChecker,
|
||||
FirJvmPackageNameAnnotationsChecker,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ object FirJvmExternalDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
val externalModifier = declaration.getModifier(KtTokens.EXTERNAL_KEYWORD)
|
||||
externalModifier?.let {
|
||||
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token.toString(), target, context)
|
||||
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token, target, context)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.jvm.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFunctionChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isActual
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.isLocalClassOrAnonymousObject
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object FirOverloadsChecker : FirFunctionChecker() {
|
||||
|
||||
private val JVM_OVERLOADS_FQ_NAME = FqName("kotlin.jvm.JvmOverloads")
|
||||
|
||||
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val annotation = declaration.getAnnotationByFqName(JVM_OVERLOADS_FQ_NAME) ?: return
|
||||
//todo need to have expect declaration here to check if it has default values
|
||||
if (declaration.isActual) return
|
||||
|
||||
val containingDeclaration = declaration.getContainingClassSymbol(context.session)
|
||||
when {
|
||||
containingDeclaration?.classKind == ClassKind.INTERFACE ->
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_INTERFACE, context)
|
||||
declaration.isAbstract ->
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_ABSTRACT, context)
|
||||
(declaration is FirSimpleFunction && declaration.isLocal) ||
|
||||
context.containingDeclarations.any { it.isLocalClassOrAnonymousObject() } ->
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_LOCAL, context)
|
||||
declaration is FirConstructor && containingDeclaration?.classKind == ClassKind.ANNOTATION_CLASS ->
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR, context)
|
||||
!declaration.visibility.isPublicAPI && declaration.visibility != Visibilities.Internal ->
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_PRIVATE, context)
|
||||
declaration.valueParameters.none { it.defaultValue != null } ->
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS, context)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.jvm.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirClassChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object FirStrictfpApplicabilityChecker : FirClassChecker() {
|
||||
private val STRICTFP_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Strictfp")
|
||||
|
||||
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val annotation = declaration.getAnnotationByFqName(STRICTFP_ANNOTATION_FQ_NAME) ?: return
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.STRICTFP_ON_CLASS, context)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.jvm.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirFunctionChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isAbstract
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInline
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object FirSynchronizedAnnotationChecker : FirFunctionChecker() {
|
||||
|
||||
private val SYNCHRONIZED_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Synchronized")
|
||||
|
||||
override fun check(declaration: FirFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val annotation = declaration.getAnnotationByFqName(SYNCHRONIZED_ANNOTATION_FQ_NAME) ?: return
|
||||
|
||||
if (declaration.isInline) {
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_INLINE, context)
|
||||
return
|
||||
}
|
||||
|
||||
val containingClass = declaration.getContainingClassSymbol(context.session) ?: return
|
||||
if (containingClass.classKind == ClassKind.INTERFACE) {
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_IN_INTERFACE, context)
|
||||
} else if (declaration.isAbstract) {
|
||||
reporter.reportOn(annotation.source, FirJvmErrors.SYNCHRONIZED_ON_ABSTRACT, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.jvm.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirTypeParameterChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isArrayType
|
||||
|
||||
object FirUpperBoundsChecker : FirTypeParameterChecker() {
|
||||
|
||||
override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration.bounds.any { it.coneType.isArrayType }) {
|
||||
reporter.reportOn(declaration.source, FirJvmErrors.UPPER_BOUND_CANNOT_BE_ARRAY, context)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.jvm.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirPropertyChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object FirVolatileAnnotationChecker : FirPropertyChecker() {
|
||||
|
||||
private val VOLATILE_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.Volatile")
|
||||
|
||||
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration.source?.kind != FirRealSourceElementKind) return
|
||||
|
||||
val fieldAnnotation = declaration.backingFieldSymbol.getAnnotationByFqName(VOLATILE_ANNOTATION_FQ_NAME)
|
||||
if (fieldAnnotation != null && !declaration.isVar) {
|
||||
reporter.reportOn(fieldAnnotation.source, FirJvmErrors.VOLATILE_ON_VALUE, context)
|
||||
}
|
||||
|
||||
val delegateAnnotation = declaration.delegateFieldSymbol?.getAnnotationByFqName(VOLATILE_ANNOTATION_FQ_NAME)
|
||||
if (delegateAnnotation != null) {
|
||||
reporter.reportOn(delegateAnnotation.source, FirJvmErrors.VOLATILE_ON_DELEGATE, context)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.jvm.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
object FirDeprecatedJavaAnnotationsChecker : FirAnnotationCallChecker() {
|
||||
|
||||
private val javaToKotlinNameMap: Map<FqName, FqName> =
|
||||
mapOf(
|
||||
JvmAnnotationNames.TARGET_ANNOTATION to StandardNames.FqNames.target,
|
||||
JvmAnnotationNames.RETENTION_ANNOTATION to StandardNames.FqNames.retention,
|
||||
JvmAnnotationNames.DEPRECATED_ANNOTATION to StandardNames.FqNames.deprecated,
|
||||
JvmAnnotationNames.DOCUMENTED_ANNOTATION to StandardNames.FqNames.mustBeDocumented
|
||||
)
|
||||
|
||||
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (context.containingDeclarations.lastOrNull()?.source?.kind != FirRealSourceElementKind) return
|
||||
|
||||
val lookupTag = expression.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return
|
||||
javaToKotlinNameMap[lookupTag.classId.asSingleFqName()]?.let { betterName ->
|
||||
reporter.reportOn(expression.source, FirJvmErrors.DEPRECATED_JAVA_ANNOTATION, betterName, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,10 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.StandardTypes
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
@@ -109,7 +110,7 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
|
||||
// actually created because of type projection from `get`. Hence, to workaround this problem, we simply remove all the out
|
||||
// projection and type capturing and compare the types after such erasure. This way, we won't incorrectly reject any valid code
|
||||
// though we may accept some invalid code. But in presence of the unsound flexible types, we are allowing invalid code already.
|
||||
val argTypeWithoutOutProjection = argType.removeOutProjection(true)
|
||||
val argTypeWithoutOutProjection = argType.removeOutProjection(isCovariant = true)
|
||||
val lowerBoundWithoutCapturing = context.session.inferenceComponents.approximator.approximateToSuperType(
|
||||
lowerBound,
|
||||
TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
|
||||
@@ -121,36 +122,39 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
|
||||
lowerBoundWithoutCapturing.withNullability(ConeNullability.NULLABLE, typeCtx)
|
||||
)
|
||||
) {
|
||||
reporter.reportOn(arg.source, FirErrors.JAVA_TYPE_MISMATCH, expectedType, argType, context)
|
||||
reporter.reportOn(arg.source, FirJvmErrors.JAVA_TYPE_MISMATCH, expectedType, argType, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.removeOutProjection(positive: Boolean): ConeKotlinType {
|
||||
private fun ConeKotlinType.removeOutProjection(isCovariant: Boolean): ConeKotlinType {
|
||||
return when (this) {
|
||||
is ConeFlexibleType -> ConeFlexibleType(lowerBound.removeOutProjection(positive), upperBound.removeOutProjection(positive))
|
||||
is ConeFlexibleType -> ConeFlexibleType(
|
||||
lowerBound.removeOutProjection(isCovariant),
|
||||
upperBound.removeOutProjection(isCovariant)
|
||||
)
|
||||
is ConeCapturedType -> ConeCapturedType(
|
||||
captureStatus,
|
||||
lowerType?.removeOutProjection(positive),
|
||||
lowerType?.removeOutProjection(isCovariant),
|
||||
nullability,
|
||||
constructor.apply {
|
||||
ConeCapturedTypeConstructor(
|
||||
projection.removeOutProjection(positive),
|
||||
supertypes?.map { it.removeOutProjection(positive) },
|
||||
projection.removeOutProjection(isCovariant),
|
||||
supertypes?.map { it.removeOutProjection(isCovariant) },
|
||||
typeParameterMarker
|
||||
)
|
||||
},
|
||||
attributes,
|
||||
isProjectionNotNull
|
||||
)
|
||||
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.removeOutProjection(positive))
|
||||
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.removeOutProjection(isCovariant))
|
||||
is ConeIntersectionType -> ConeIntersectionType(
|
||||
intersectedTypes.map { it.removeOutProjection(positive) },
|
||||
alternativeType?.removeOutProjection(positive)
|
||||
intersectedTypes.map { it.removeOutProjection(isCovariant) },
|
||||
alternativeType?.removeOutProjection(isCovariant)
|
||||
)
|
||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(
|
||||
lookupTag,
|
||||
typeArguments.map { it.removeOutProjection(positive) }.toTypedArray(),
|
||||
typeArguments.map { it.removeOutProjection(isCovariant) }.toTypedArray(),
|
||||
isNullable,
|
||||
attributes
|
||||
)
|
||||
@@ -158,14 +162,20 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeTypeProjection.removeOutProjection(positive: Boolean): ConeTypeProjection {
|
||||
/**
|
||||
* @param isCovariant true if the current context is covariant and false if contravariant.
|
||||
*
|
||||
* This function only remove out projections in covariant context.
|
||||
* 'in' projections are never removed, nor would an out projection in a contravariant context.
|
||||
*/
|
||||
private fun ConeTypeProjection.removeOutProjection(isCovariant: Boolean): ConeTypeProjection {
|
||||
return when (this) {
|
||||
is ConeKotlinTypeProjectionOut -> if (positive) type else this
|
||||
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(type.removeOutProjection(!positive))
|
||||
is ConeKotlinTypeProjectionOut -> if (isCovariant) type else this
|
||||
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(type.removeOutProjection(!isCovariant))
|
||||
is ConeStarProjection -> if (isCovariant) StandardTypes.Any else this
|
||||
// Don't remove nested projections for types at invariant position.
|
||||
is ConeKotlinTypeConflictingProjection,
|
||||
is ConeKotlinType,
|
||||
is ConeStarProjection -> this
|
||||
is ConeKotlinType -> this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +191,10 @@ object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
|
||||
for (immediateSuperType in subTypeConstructor.supertypes()) {
|
||||
val immediateSuperTypeConstructor = immediateSuperType.typeConstructor()
|
||||
if (superTypeConstructor == immediateSuperTypeConstructor) return true
|
||||
if (this@isTypeConstructorEqualOrSubClassOf.isTypeConstructorEqualOrSubClassOf(immediateSuperTypeConstructor, superTypeConstructor)) return true
|
||||
if (this@isTypeConstructorEqualOrSubClassOf.isTypeConstructorEqualOrSubClassOf(
|
||||
immediateSuperTypeConstructor, superTypeConstructor
|
||||
)
|
||||
) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.jvm.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.declarations.getStringArgument
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.name.*
|
||||
|
||||
object FirJvmPackageNameAnnotationsChecker : FirAnnotationCallChecker() {
|
||||
|
||||
private val jvmPackageNameClassId = ClassId.topLevel(FqName("kotlin.jvm.JvmPackageName"))
|
||||
private val stringParameterName = Name.identifier("name")
|
||||
|
||||
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val lookupTag = expression.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return
|
||||
if (lookupTag.classId != jvmPackageNameClassId) return
|
||||
|
||||
val nameValue = expression.getStringArgument(stringParameterName) ?: return
|
||||
if (nameValue.isEmpty()) {
|
||||
reporter.reportOn(expression.source, FirJvmErrors.JVM_PACKAGE_NAME_CANNOT_BE_EMPTY, context)
|
||||
} else if (!isValidJavaFqName(nameValue)) {
|
||||
reporter.reportOn(expression.source, FirJvmErrors.JVM_PACKAGE_NAME_MUST_BE_VALID_NAME, context)
|
||||
}
|
||||
|
||||
val file = context.containingDeclarations.firstOrNull() as? FirFile ?: return
|
||||
if (file.declarations.any { it is FirClass }) {
|
||||
reporter.reportOn(expression.source, FirJvmErrors.JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.jvm.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
object FirSuperCallWithDefaultsChecker : FirFunctionCallChecker() {
|
||||
|
||||
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
expression.explicitReceiver.safeAs<FirQualifiedAccessExpression>()
|
||||
?.calleeReference.safeAs<FirSuperReference>()
|
||||
?: return
|
||||
|
||||
val functionSymbol =
|
||||
(expression.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirNamedFunctionSymbol ?: return
|
||||
if (!functionSymbol.valueParameterSymbols.any { it.hasDefaultValue }) return
|
||||
val arguments = expression.argumentList as? FirResolvedArgumentList ?: return
|
||||
if (arguments.arguments.size < functionSymbol.valueParameterSymbols.size) {
|
||||
reporter.reportOn(
|
||||
expression.calleeReference.source,
|
||||
FirJvmErrors.SUPER_CALL_WITH_DEFAULT_PARAMETERS,
|
||||
functionSymbol.name.asString(),
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.jvm.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDefaultErrorMessages
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.RENDER_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticRenderers.TO_STRING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.CONFLICTING_JVM_DECLARATIONS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.DEPRECATED_JAVA_ANNOTATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JAVA_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_CANNOT_BE_EMPTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_MUST_BE_VALID_NAME
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_ABSTRACT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_LOCAL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_PRIVATE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.STRICTFP_ON_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SUPER_CALL_WITH_DEFAULT_PARAMETERS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_ON_ABSTRACT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.SYNCHRONIZED_ON_INLINE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.UPPER_BOUND_CANNOT_BE_ARRAY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VOLATILE_ON_DELEGATE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.VOLATILE_ON_VALUE
|
||||
|
||||
object FirJvmDefaultErrorMessages {
|
||||
fun installJvmErrorMessages() {
|
||||
FirDefaultErrorMessages.Companion.MAP.also { map ->
|
||||
map.put(CONFLICTING_JVM_DECLARATIONS, "Platform declaration clash")
|
||||
map.put(JAVA_TYPE_MISMATCH, "Java type mismatch expected {0} but found {1}. Use explicit cast", RENDER_TYPE, RENDER_TYPE)
|
||||
map.put(UPPER_BOUND_CANNOT_BE_ARRAY, "Upper bound of a type parameter cannot be an array")
|
||||
map.put(STRICTFP_ON_CLASS, "'@Strictfp' annotation on classes is unsupported yet")
|
||||
map.put(VOLATILE_ON_VALUE, "'@Volatile' annotation cannot be used on immutable properties")
|
||||
map.put(VOLATILE_ON_DELEGATE, "'@Volatile' annotation cannot be used on delegated properties")
|
||||
map.put(SYNCHRONIZED_ON_ABSTRACT, "'@Synchronized' annotation cannot be used on abstract functions")
|
||||
map.put(SYNCHRONIZED_ON_INLINE, "'@Synchronized' annotation has no effect on inline functions")
|
||||
map.put(SYNCHRONIZED_IN_INTERFACE, "'@Synchronized' annotation cannot be used on interface members")
|
||||
map.put(OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS, "'@JvmOverloads' annotation has no effect for methods without default arguments")
|
||||
map.put(OVERLOADS_ABSTRACT, "'@JvmOverloads' annotation cannot be used on abstract methods")
|
||||
map.put(OVERLOADS_INTERFACE, "'@JvmOverloads' annotation cannot be used on interface methods")
|
||||
map.put(OVERLOADS_PRIVATE, "'@JvmOverloads' annotation has no effect on private declarations")
|
||||
map.put(OVERLOADS_LOCAL, "'@JvmOverloads' annotation cannot be used on local declarations")
|
||||
map.put(
|
||||
OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR,
|
||||
"'@JvmOverloads' annotation cannot be used on constructors of annotation classes"
|
||||
)
|
||||
map.put(DEPRECATED_JAVA_ANNOTATION, "This annotation is deprecated in Kotlin. Use ''@{0}'' instead", TO_STRING)
|
||||
map.put(JVM_PACKAGE_NAME_CANNOT_BE_EMPTY, "''@JvmPackageName'' annotation value cannot be empty")
|
||||
map.put(
|
||||
JVM_PACKAGE_NAME_MUST_BE_VALID_NAME,
|
||||
"''@JvmPackageName'' annotation value must be a valid dot-qualified name of a package"
|
||||
)
|
||||
map.put(
|
||||
JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES,
|
||||
"''@JvmPackageName'' annotation is not supported for files with class declarations"
|
||||
)
|
||||
map.put(
|
||||
SUPER_CALL_WITH_DEFAULT_PARAMETERS,
|
||||
"Super-calls with default arguments are not allowed. Please specify all arguments of ''super.{0}'' explicitly",
|
||||
TO_STRING
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
get() = _qualifiedAccessCheckers
|
||||
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
|
||||
get() = _qualifiedAccessExpressionCheckers
|
||||
override val callCheckers: Set<FirCallChecker>
|
||||
get() = _callCheckers
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
get() = _functionCallCheckers
|
||||
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
|
||||
@@ -73,6 +75,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
private val _basicExpressionCheckers: MutableSet<FirBasicExpressionChecker> = mutableSetOf()
|
||||
private val _qualifiedAccessCheckers: MutableSet<FirQualifiedAccessChecker> = mutableSetOf()
|
||||
private val _qualifiedAccessExpressionCheckers: MutableSet<FirQualifiedAccessExpressionChecker> = mutableSetOf()
|
||||
private val _callCheckers: MutableSet<FirCallChecker> = mutableSetOf()
|
||||
private val _functionCallCheckers: MutableSet<FirFunctionCallChecker> = mutableSetOf()
|
||||
private val _variableAssignmentCheckers: MutableSet<FirVariableAssignmentChecker> = mutableSetOf()
|
||||
private val _tryExpressionCheckers: MutableSet<FirTryExpressionChecker> = mutableSetOf()
|
||||
@@ -104,6 +107,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
_basicExpressionCheckers += checkers.basicExpressionCheckers
|
||||
_qualifiedAccessCheckers += checkers.qualifiedAccessCheckers
|
||||
_qualifiedAccessExpressionCheckers += checkers.qualifiedAccessExpressionCheckers
|
||||
_callCheckers += checkers.callCheckers
|
||||
_functionCallCheckers += checkers.functionCallCheckers
|
||||
_variableAssignmentCheckers += checkers.variableAssignmentCheckers
|
||||
_tryExpressionCheckers += checkers.tryExpressionCheckers
|
||||
|
||||
@@ -20,6 +20,7 @@ abstract class ExpressionCheckers {
|
||||
open val basicExpressionCheckers: Set<FirBasicExpressionChecker> = emptySet()
|
||||
open val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker> = emptySet()
|
||||
open val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> = emptySet()
|
||||
open val callCheckers: Set<FirCallChecker> = emptySet()
|
||||
open val functionCallCheckers: Set<FirFunctionCallChecker> = emptySet()
|
||||
open val variableAssignmentCheckers: Set<FirVariableAssignmentChecker> = emptySet()
|
||||
open val tryExpressionCheckers: Set<FirTryExpressionChecker> = emptySet()
|
||||
@@ -49,7 +50,8 @@ abstract class ExpressionCheckers {
|
||||
@CheckersComponentInternal internal val allBasicExpressionCheckers: Set<FirBasicExpressionChecker> by lazy { basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allQualifiedAccessCheckers: Set<FirQualifiedAccessChecker> by lazy { qualifiedAccessCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allQualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker> by lazy { qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allCallCheckers: Set<FirCallChecker> by lazy { callCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allFunctionCallCheckers: Set<FirFunctionCallChecker> by lazy { functionCallCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> by lazy { variableAssignmentCheckers + qualifiedAccessCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allTryExpressionCheckers: Set<FirTryExpressionChecker> by lazy { tryExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allWhenExpressionCheckers: Set<FirWhenExpressionChecker> by lazy { whenExpressionCheckers + basicExpressionCheckers }
|
||||
@@ -58,20 +60,20 @@ abstract class ExpressionCheckers {
|
||||
@CheckersComponentInternal internal val allLogicExpressionCheckers: Set<FirLogicExpressionChecker> by lazy { logicExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allReturnExpressionCheckers: Set<FirReturnExpressionChecker> by lazy { returnExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allBlockCheckers: Set<FirBlockChecker> by lazy { blockCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allAnnotationCallCheckers: Set<FirAnnotationCallChecker> by lazy { annotationCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allCheckNotNullCallCheckers: Set<FirCheckNotNullCallChecker> by lazy { checkNotNullCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allAnnotationCallCheckers: Set<FirAnnotationCallChecker> by lazy { annotationCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allCheckNotNullCallCheckers: Set<FirCheckNotNullCallChecker> by lazy { checkNotNullCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allElvisExpressionCheckers: Set<FirElvisExpressionChecker> by lazy { elvisExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allGetClassCallCheckers: Set<FirGetClassCallChecker> by lazy { getClassCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allGetClassCallCheckers: Set<FirGetClassCallChecker> by lazy { getClassCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allSafeCallExpressionCheckers: Set<FirSafeCallExpressionChecker> by lazy { safeCallExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> by lazy { equalityOperatorCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> by lazy { stringConcatenationCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> by lazy { typeOperatorCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> by lazy { equalityOperatorCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> by lazy { stringConcatenationCallCheckers + callCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> by lazy { typeOperatorCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allResolvedQualifierCheckers: Set<FirResolvedQualifierChecker> by lazy { resolvedQualifierCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allConstExpressionCheckers: Set<FirConstExpressionChecker> by lazy { constExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allCallableReferenceAccessCheckers: Set<FirCallableReferenceAccessChecker> by lazy { callableReferenceAccessCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allThisReceiverExpressionCheckers: Set<FirThisReceiverExpressionChecker> by lazy { thisReceiverExpressionCheckers + qualifiedAccessExpressionCheckers + basicExpressionCheckers + qualifiedAccessCheckers }
|
||||
@CheckersComponentInternal internal val allWhileLoopCheckers: Set<FirWhileLoopChecker> by lazy { whileLoopCheckers + loopExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allDoWhileLoopCheckers: Set<FirDoWhileLoopChecker> by lazy { doWhileLoopCheckers + loopExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allArrayOfCallCheckers: Set<FirArrayOfCallChecker> by lazy { arrayOfCallCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allArrayOfCallCheckers: Set<FirArrayOfCallChecker> by lazy { arrayOfCallCheckers + basicExpressionCheckers + callCheckers }
|
||||
@CheckersComponentInternal internal val allClassReferenceExpressionCheckers: Set<FirClassReferenceExpressionChecker> by lazy { classReferenceExpressionCheckers + basicExpressionCheckers }
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirArrayOfCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirBinaryLogicExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirBlock
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCheckNotNullCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirClassReferenceExpression
|
||||
@@ -42,6 +43,7 @@ import org.jetbrains.kotlin.fir.expressions.FirWhileLoop
|
||||
typealias FirBasicExpressionChecker = FirExpressionChecker<FirStatement>
|
||||
typealias FirQualifiedAccessChecker = FirExpressionChecker<FirQualifiedAccess>
|
||||
typealias FirQualifiedAccessExpressionChecker = FirExpressionChecker<FirQualifiedAccessExpression>
|
||||
typealias FirCallChecker = FirExpressionChecker<FirCall>
|
||||
typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
|
||||
typealias FirVariableAssignmentChecker = FirExpressionChecker<FirVariableAssignment>
|
||||
typealias FirTryExpressionChecker = FirExpressionChecker<FirTryExpression>
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes
|
||||
@@ -37,6 +38,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
@@ -253,19 +255,20 @@ object FirErrors {
|
||||
|
||||
// Modifiers
|
||||
val INAPPLICABLE_INFIX_MODIFIER by error0<PsiElement>()
|
||||
val REPEATED_MODIFIER by error1<PsiElement, String>()
|
||||
val REDUNDANT_MODIFIER by error2<PsiElement, String, String>()
|
||||
val DEPRECATED_MODIFIER by warning2<PsiElement, String, String>()
|
||||
val DEPRECATED_MODIFIER_PAIR by error2<PsiElement, String, String>()
|
||||
val DEPRECATED_MODIFIER_FOR_TARGET by warning2<PsiElement, String, String>()
|
||||
val REDUNDANT_MODIFIER_FOR_TARGET by warning2<PsiElement, String, String>()
|
||||
val INCOMPATIBLE_MODIFIERS by error2<PsiElement, String, String>()
|
||||
val REPEATED_MODIFIER by error1<PsiElement, KtModifierKeywordToken>()
|
||||
val REDUNDANT_MODIFIER by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
val DEPRECATED_MODIFIER by warning2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
val DEPRECATED_MODIFIER_PAIR by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
val DEPRECATED_MODIFIER_FOR_TARGET by warning2<PsiElement, KtModifierKeywordToken, String>()
|
||||
val REDUNDANT_MODIFIER_FOR_TARGET by warning2<PsiElement, KtModifierKeywordToken, String>()
|
||||
val INCOMPATIBLE_MODIFIERS by error2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
|
||||
val REDUNDANT_OPEN_IN_INTERFACE by warning0<KtModifierListOwner>(SourceElementPositioningStrategies.OPEN_MODIFIER)
|
||||
val WRONG_MODIFIER_TARGET by error2<PsiElement, String, String>()
|
||||
val WRONG_MODIFIER_TARGET by error2<PsiElement, KtModifierKeywordToken, String>()
|
||||
val OPERATOR_MODIFIER_REQUIRED by error2<PsiElement, FirNamedFunctionSymbol, String>()
|
||||
val INFIX_MODIFIER_REQUIRED by error1<PsiElement, FirNamedFunctionSymbol>()
|
||||
val WRONG_MODIFIER_CONTAINING_DECLARATION by error2<PsiElement, String, String>()
|
||||
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning2<PsiElement, String, String>()
|
||||
val WRONG_MODIFIER_CONTAINING_DECLARATION by error2<PsiElement, KtModifierKeywordToken, String>()
|
||||
val DEPRECATED_MODIFIER_CONTAINING_DECLARATION by warning2<PsiElement, KtModifierKeywordToken, String>()
|
||||
val INAPPLICABLE_OPERATOR_MODIFIER by error1<PsiElement, String>(SourceElementPositioningStrategies.OPERATOR_MODIFIER)
|
||||
|
||||
// Inline classes
|
||||
val INLINE_CLASS_NOT_TOP_LEVEL by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
|
||||
@@ -305,6 +308,8 @@ object FirErrors {
|
||||
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
|
||||
val NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER by error1<KtElement, String>()
|
||||
val SPREAD_OF_NULLABLE by error0<PsiElement>(SourceElementPositioningStrategies.SPREAD_OPERATOR)
|
||||
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm)
|
||||
val ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION by deprecationError0<KtExpression>(ProhibitAssigningSingleElementsToVarargsInNamedForm)
|
||||
|
||||
// Ambiguity
|
||||
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
@@ -577,6 +582,8 @@ object FirErrors {
|
||||
val EQUALITY_NOT_APPLICABLE by error3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||
val EQUALITY_NOT_APPLICABLE_WARNING by warning3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
val INC_DEC_SHOULD_NOT_RETURN_UNIT by error0<KtExpression>(SourceElementPositioningStrategies.OPERATOR)
|
||||
val ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT by error2<KtExpression, FirNamedFunctionSymbol, String>(SourceElementPositioningStrategies.OPERATOR)
|
||||
|
||||
// Type alias
|
||||
val TOPLEVEL_TYPEALIASES_ONLY by error0<KtTypeAlias>()
|
||||
@@ -646,7 +653,4 @@ object FirErrors {
|
||||
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val RETURN_FOR_BUILT_IN_SUSPEND by error0<KtReturnExpression>()
|
||||
|
||||
// jvm
|
||||
val JAVA_TYPE_MISMATCH by error2<KtExpression, ConeKotlinType, ConeKotlinType>()
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
get() = setOf(
|
||||
FirFunctionNameChecker,
|
||||
FirFunctionTypeParametersSyntaxChecker,
|
||||
FirOperatorModifierChecker,
|
||||
)
|
||||
|
||||
override val propertyCheckers: Set<FirPropertyChecker>
|
||||
|
||||
@@ -45,12 +45,19 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirSuspendCallChecker,
|
||||
)
|
||||
|
||||
override val callCheckers: Set<FirCallChecker>
|
||||
get() = setOf(
|
||||
FirNamedVarargChecker,
|
||||
)
|
||||
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
get() = setOf(
|
||||
FirConventionFunctionCallChecker,
|
||||
FirDivisionByZeroChecker,
|
||||
FirConstructorCallChecker,
|
||||
FirSpreadOfNullableChecker
|
||||
FirSpreadOfNullableChecker,
|
||||
FirAssignmentOperatorCallChecker,
|
||||
FirNamedVarargChecker,
|
||||
)
|
||||
|
||||
override val tryExpressionCheckers: Set<FirTryExpressionChecker>
|
||||
|
||||
@@ -16,8 +16,11 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.analysis.getChild
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirEmptyExpressionBlock
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
|
||||
@@ -578,7 +581,11 @@ fun checkTypeMismatch(
|
||||
rValueType = lValueType
|
||||
lValueType = tempType
|
||||
}
|
||||
reporter.reportOn(source, FirErrors.RESULT_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
if (rValueType.isUnit) {
|
||||
reporter.reportOn(source, FirErrors.INC_DEC_SHOULD_NOT_RETURN_UNIT, context)
|
||||
} else {
|
||||
reporter.reportOn(source, FirErrors.RESULT_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
reporter.reportOn(source, FirErrors.ASSIGNMENT_TYPE_MISMATCH, lValueType, rValueType, context)
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the licensedot/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers
|
||||
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||
import org.jetbrains.kotlin.resolve.KeywordType
|
||||
|
||||
fun getKeywordType(modifier: FirModifier<*>): KeywordType {
|
||||
return ktKeywordToKeywordTypeMap[modifier.token]!!
|
||||
}
|
||||
|
||||
private val ktKeywordToKeywordTypeMap: Map<KtKeywordToken, KeywordType> = mapOf(
|
||||
INNER_KEYWORD to KeywordType.Inner,
|
||||
OVERRIDE_KEYWORD to KeywordType.Override,
|
||||
PUBLIC_KEYWORD to KeywordType.Public,
|
||||
PROTECTED_KEYWORD to KeywordType.Protected,
|
||||
INTERNAL_KEYWORD to KeywordType.Internal,
|
||||
PRIVATE_KEYWORD to KeywordType.Private,
|
||||
COMPANION_KEYWORD to KeywordType.Companion,
|
||||
FINAL_KEYWORD to KeywordType.Final,
|
||||
VARARG_KEYWORD to KeywordType.Vararg,
|
||||
ENUM_KEYWORD to KeywordType.Enum,
|
||||
ABSTRACT_KEYWORD to KeywordType.Abstract,
|
||||
OPEN_KEYWORD to KeywordType.Open,
|
||||
SEALED_KEYWORD to KeywordType.Sealed,
|
||||
IN_KEYWORD to KeywordType.In,
|
||||
OUT_KEYWORD to KeywordType.Out,
|
||||
REIFIED_KEYWORD to KeywordType.Reified,
|
||||
LATEINIT_KEYWORD to KeywordType.Lateinit,
|
||||
DATA_KEYWORD to KeywordType.Data,
|
||||
INLINE_KEYWORD to KeywordType.Inline,
|
||||
NOINLINE_KEYWORD to KeywordType.Noinline,
|
||||
TAILREC_KEYWORD to KeywordType.Tailrec,
|
||||
SUSPEND_KEYWORD to KeywordType.Suspend,
|
||||
EXTERNAL_KEYWORD to KeywordType.External,
|
||||
ANNOTATION_KEYWORD to KeywordType.Annotation,
|
||||
CROSSINLINE_KEYWORD to KeywordType.Crossinline,
|
||||
CONST_KEYWORD to KeywordType.Const,
|
||||
OPERATOR_KEYWORD to KeywordType.Operator,
|
||||
INFIX_KEYWORD to KeywordType.Infix,
|
||||
HEADER_KEYWORD to KeywordType.Header,
|
||||
IMPL_KEYWORD to KeywordType.Impl,
|
||||
EXPECT_KEYWORD to KeywordType.Expect,
|
||||
ACTUAL_KEYWORD to KeywordType.Actual,
|
||||
FUN_KEYWORD to KeywordType.Fun,
|
||||
VALUE_KEYWORD to KeywordType.Value
|
||||
)
|
||||
@@ -29,7 +29,7 @@ object FirConstPropertyChecker : FirPropertyChecker() {
|
||||
if (declaration.isVar) {
|
||||
val constModifier = declaration.getModifier(KtTokens.CONST_KEYWORD)
|
||||
constModifier?.let {
|
||||
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token.toString(), "vars", context)
|
||||
reporter.reportOn(it.source, FirErrors.WRONG_MODIFIER_TARGET, it.token, "vars", context)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,8 @@ import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
|
||||
object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
@@ -87,10 +89,10 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
if (secondModifier !in reportedNodes) {
|
||||
val modifierSource = secondModifier.source
|
||||
val modifierType = getKeywordType(secondModifier)
|
||||
val modifier = secondModifier.token
|
||||
when {
|
||||
!checkTarget(modifierSource, modifierType, actualTargets, parent, context, reporter) -> reportedNodes += secondModifier
|
||||
!checkParent(modifierSource, modifierType, actualParents, context, reporter) -> reportedNodes += secondModifier
|
||||
!checkTarget(modifierSource, modifier, actualTargets, parent, context, reporter) -> reportedNodes += secondModifier
|
||||
!checkParent(modifierSource, modifier, actualParents, context, reporter) -> reportedNodes += secondModifier
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,21 +106,21 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
owner: FirDeclaration?,
|
||||
context: CheckerContext
|
||||
) {
|
||||
val firstModifierType = getKeywordType(firstModifier)
|
||||
val secondModifierType = getKeywordType(secondModifier)
|
||||
when (val compatibilityType = compatibility(firstModifierType, secondModifierType)) {
|
||||
val firstModifierToken = firstModifier.token
|
||||
val secondModifierToken = secondModifier.token
|
||||
when (val compatibilityType = compatibility(firstModifierToken, secondModifierToken)) {
|
||||
Compatibility.COMPATIBLE -> {
|
||||
}
|
||||
Compatibility.REPEATED ->
|
||||
if (reportedNodes.add(secondModifier)) {
|
||||
reporter.reportOn(secondModifier.source, FirErrors.REPEATED_MODIFIER, secondModifierType.render(), context)
|
||||
reporter.reportOn(secondModifier.source, FirErrors.REPEATED_MODIFIER, secondModifierToken, context)
|
||||
}
|
||||
Compatibility.REDUNDANT -> {
|
||||
reporter.reportOn(
|
||||
secondModifier.source,
|
||||
FirErrors.REDUNDANT_MODIFIER,
|
||||
secondModifierType.render(),
|
||||
firstModifierType.render(),
|
||||
secondModifierToken,
|
||||
firstModifierToken,
|
||||
context
|
||||
)
|
||||
}
|
||||
@@ -126,8 +128,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
reporter.reportOn(
|
||||
firstModifier.source,
|
||||
FirErrors.REDUNDANT_MODIFIER,
|
||||
firstModifierType.render(),
|
||||
secondModifierType.render(),
|
||||
firstModifierToken,
|
||||
secondModifierToken,
|
||||
context
|
||||
)
|
||||
}
|
||||
@@ -135,15 +137,15 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
reporter.reportOn(
|
||||
firstModifier.source,
|
||||
FirErrors.DEPRECATED_MODIFIER_PAIR,
|
||||
firstModifierType.render(),
|
||||
secondModifierType.render(),
|
||||
firstModifierToken,
|
||||
secondModifierToken,
|
||||
context
|
||||
)
|
||||
reporter.reportOn(
|
||||
secondModifier.source,
|
||||
FirErrors.DEPRECATED_MODIFIER_PAIR,
|
||||
secondModifierType.render(),
|
||||
firstModifierType.render(),
|
||||
secondModifierToken,
|
||||
firstModifierToken,
|
||||
context
|
||||
)
|
||||
}
|
||||
@@ -155,8 +157,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
reporter.reportOn(
|
||||
firstModifier.source,
|
||||
FirErrors.INCOMPATIBLE_MODIFIERS,
|
||||
firstModifierType.render(),
|
||||
secondModifierType.render(),
|
||||
firstModifierToken,
|
||||
secondModifierToken,
|
||||
context
|
||||
)
|
||||
}
|
||||
@@ -164,8 +166,8 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
reporter.reportOn(
|
||||
secondModifier.source,
|
||||
FirErrors.INCOMPATIBLE_MODIFIERS,
|
||||
secondModifierType.render(),
|
||||
firstModifierType.render(),
|
||||
secondModifierToken,
|
||||
firstModifierToken,
|
||||
context
|
||||
)
|
||||
}
|
||||
@@ -175,19 +177,19 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
|
||||
private fun checkTarget(
|
||||
modifierSource: FirSourceElement,
|
||||
modifierType: KeywordType,
|
||||
modifierToken: KtModifierKeywordToken,
|
||||
actualTargets: List<KotlinTarget>,
|
||||
parent: FirDeclaration?,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
): Boolean {
|
||||
fun checkModifier(factory: FirDiagnosticFactory2<String, String>): Boolean {
|
||||
fun checkModifier(factory: FirDiagnosticFactory2<KtModifierKeywordToken, String>): Boolean {
|
||||
val map = when (factory) {
|
||||
FirErrors.WRONG_MODIFIER_TARGET -> possibleTargetMap
|
||||
FirErrors.DEPRECATED_MODIFIER_FOR_TARGET -> deprecatedTargetMap
|
||||
else -> redundantTargetMap
|
||||
}
|
||||
val set = map[modifierType] ?: emptySet()
|
||||
val set = map[modifierToken] ?: emptySet()
|
||||
val checkResult = if (factory == FirErrors.WRONG_MODIFIER_TARGET) {
|
||||
actualTargets.none { it in set }
|
||||
} else {
|
||||
@@ -197,7 +199,7 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
reporter.reportOn(
|
||||
modifierSource,
|
||||
factory,
|
||||
modifierType.render(),
|
||||
modifierToken,
|
||||
actualTargets.firstOrThis(),
|
||||
context
|
||||
)
|
||||
@@ -211,19 +213,19 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
|
||||
if (parent is FirRegularClass) {
|
||||
if (modifierType == KeywordType.Expect || modifierType == KeywordType.Header) {
|
||||
reporter.reportOn(modifierSource, FirErrors.WRONG_MODIFIER_TARGET, modifierType.render(), "nested class", context)
|
||||
if (modifierToken == KtTokens.EXPECT_KEYWORD || modifierToken == KtTokens.HEADER_KEYWORD) {
|
||||
reporter.reportOn(modifierSource, FirErrors.WRONG_MODIFIER_TARGET, modifierToken, "nested class", context)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
val deprecatedModifierReplacement = deprecatedModifierMap[modifierType]
|
||||
val deprecatedModifierReplacement = deprecatedModifierMap[modifierToken]
|
||||
if (deprecatedModifierReplacement != null) {
|
||||
reporter.reportOn(
|
||||
modifierSource,
|
||||
FirErrors.DEPRECATED_MODIFIER,
|
||||
modifierType.render(),
|
||||
deprecatedModifierReplacement.render(),
|
||||
modifierToken,
|
||||
deprecatedModifierReplacement,
|
||||
context
|
||||
)
|
||||
} else if (checkModifier(FirErrors.DEPRECATED_MODIFIER_FOR_TARGET)) {
|
||||
@@ -235,30 +237,30 @@ object FirModifierChecker : FirBasicDeclarationChecker() {
|
||||
|
||||
private fun checkParent(
|
||||
modifierSource: FirSourceElement,
|
||||
modifierType: KeywordType,
|
||||
modifierToken: KtModifierKeywordToken,
|
||||
actualParents: List<KotlinTarget>,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
): Boolean {
|
||||
val deprecatedParents = deprecatedParentTargetMap[modifierType]
|
||||
val deprecatedParents = deprecatedParentTargetMap[modifierToken]
|
||||
if (deprecatedParents != null && actualParents.any { it in deprecatedParents }) {
|
||||
reporter.reportOn(
|
||||
modifierSource,
|
||||
FirErrors.DEPRECATED_MODIFIER_CONTAINING_DECLARATION,
|
||||
modifierType.render(),
|
||||
modifierToken,
|
||||
actualParents.firstOrThis(),
|
||||
context
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
val possibleParentPredicate = possibleParentTargetPredicateMap[modifierType] ?: return true
|
||||
val possibleParentPredicate = possibleParentTargetPredicateMap[modifierToken] ?: return true
|
||||
if (actualParents.any { possibleParentPredicate.isAllowed(it, context.session.languageVersionSettings) }) return true
|
||||
|
||||
reporter.reportOn(
|
||||
modifierSource,
|
||||
FirErrors.WRONG_MODIFIER_CONTAINING_DECLARATION,
|
||||
modifierType.render(),
|
||||
modifierToken,
|
||||
actualParents.firstOrThis(),
|
||||
context
|
||||
)
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.checkers.declaration
|
||||
|
||||
import javaslang.Function2
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.Returns
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.ValueParametersCount
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.isKProperty
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.member
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.memberOrExtension
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.Checks.noDefaultAndVarargs
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isSubtypeOf
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.isSupertypeOf
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.overriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.containingClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isOperator
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.ASSIGNMENT_OPERATIONS
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.BINARY_OPERATION_NAMES
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.COMPARE_TO
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.COMPONENT_REGEX
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.CONTAINS
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.DEC
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.EQUALS
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.GET
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.GET_VALUE
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.HAS_NEXT
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.INC
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.INVOKE
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.ITERATOR
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.NEXT
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.PROVIDE_DELEGATE
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.RANGE_TO
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.SET
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.SET_VALUE
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions.SIMPLE_UNARY_OPERATION_NAMES
|
||||
|
||||
|
||||
object FirOperatorModifierChecker : FirSimpleFunctionChecker() {
|
||||
|
||||
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.isOperator) return
|
||||
//we are not interested in implicit operators from override
|
||||
if (!declaration.hasModifier(KtTokens.OPERATOR_KEYWORD)) return
|
||||
|
||||
val checks = OperatorFunctionChecks.checksByName.getOrElse(declaration.name) {
|
||||
OperatorFunctionChecks.regexChecks.find { it.first.matches(declaration.name.asString()) }?.second
|
||||
}
|
||||
|
||||
if (checks == null) {
|
||||
reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_OPERATOR_MODIFIER, "illegal function name", context)
|
||||
return
|
||||
}
|
||||
|
||||
for (check in checks) {
|
||||
check.check(context, declaration)?.let { error ->
|
||||
reporter.reportOn(declaration.source, FirErrors.INAPPLICABLE_OPERATOR_MODIFIER, error, context)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface Check : Function2<CheckerContext, FirSimpleFunction, String?> {
|
||||
override fun apply(t1: CheckerContext, t2: FirSimpleFunction): String? = check(t1, t2)
|
||||
fun check(context: CheckerContext, function: FirSimpleFunction): String?
|
||||
}
|
||||
|
||||
object Checks {
|
||||
fun simple(message: String, predicate: (FirSimpleFunction) -> Boolean) = object : Check {
|
||||
override fun check(context: CheckerContext, function: FirSimpleFunction): String? = message.takeIf { !predicate(function) }
|
||||
}
|
||||
|
||||
fun full(message: String, predicate: (CheckerContext, FirSimpleFunction) -> Boolean) = object : Check {
|
||||
override fun check(context: CheckerContext, function: FirSimpleFunction): String? = message.takeIf { !predicate(context, function) }
|
||||
}
|
||||
|
||||
val memberOrExtension = simple("must be a member or an extension function") {
|
||||
it.dispatchReceiverType != null || it.receiverTypeRef != null
|
||||
}
|
||||
|
||||
val member = simple("must be a member function") {
|
||||
it.dispatchReceiverType != null
|
||||
}
|
||||
|
||||
object ValueParametersCount {
|
||||
fun atLeast(n: Int) = simple("must have at least $n value parameter" + (if (n > 1) "s" else "")) {
|
||||
it.valueParameters.size >= n
|
||||
}
|
||||
|
||||
fun exactly(n: Int) = simple("must have exactly $n value parameters") {
|
||||
it.valueParameters.size == n
|
||||
}
|
||||
|
||||
val single = simple("must have a single value parameter") {
|
||||
it.valueParameters.size == 1
|
||||
}
|
||||
val none = simple("must have no value parameters") {
|
||||
it.valueParameters.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
object Returns {
|
||||
val boolean = simple("must return Boolean") {
|
||||
it.returnTypeRef.isBoolean
|
||||
}
|
||||
|
||||
val int = simple("must return Int") {
|
||||
it.returnTypeRef.isInt
|
||||
}
|
||||
|
||||
val unit = simple("must return Unit") {
|
||||
it.returnTypeRef.isUnit
|
||||
}
|
||||
}
|
||||
|
||||
val noDefaultAndVarargs = simple("should not have varargs or parameters with default values") {
|
||||
it.valueParameters.all { param ->
|
||||
param.defaultValue == null && !param.isVararg
|
||||
}
|
||||
}
|
||||
|
||||
private val kPropertyType = ConeClassLikeTypeImpl(
|
||||
ConeClassLikeLookupTagImpl(StandardNames.FqNames.kProperty),
|
||||
arrayOf(ConeStarProjection),
|
||||
isNullable = false
|
||||
)
|
||||
|
||||
val isKProperty = full("second parameter must be of type KProperty<*> or its supertype") { ctx, function ->
|
||||
val paramType = function.valueParameters[1].returnTypeRef.coneType
|
||||
paramType.isSupertypeOf(ctx.session.typeContext, kPropertyType)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
object OperatorFunctionChecks {
|
||||
|
||||
//reimplementation of org.jetbrains.kotlin.util.OperatorChecks for FIR
|
||||
val checksByName: Map<Name, List<Check>> = buildMap<Name, List<Check>> {
|
||||
checkFor(GET, memberOrExtension, ValueParametersCount.atLeast(1))
|
||||
checkFor(
|
||||
SET,
|
||||
memberOrExtension, ValueParametersCount.atLeast(2),
|
||||
Checks.simple("last parameter should not have a default value or be a vararg") {
|
||||
it.valueParameters.lastOrNull()?.let { param ->
|
||||
param.defaultValue == null && !param.isVararg
|
||||
} == true
|
||||
}
|
||||
)
|
||||
checkFor(GET_VALUE, memberOrExtension, noDefaultAndVarargs, ValueParametersCount.atLeast(2), isKProperty)
|
||||
checkFor(SET_VALUE, memberOrExtension, noDefaultAndVarargs, ValueParametersCount.atLeast(3), isKProperty)
|
||||
checkFor(PROVIDE_DELEGATE, memberOrExtension, noDefaultAndVarargs, ValueParametersCount.exactly(2), isKProperty)
|
||||
checkFor(INVOKE, memberOrExtension)
|
||||
checkFor(CONTAINS, memberOrExtension, ValueParametersCount.single, noDefaultAndVarargs, Returns.boolean)
|
||||
checkFor(ITERATOR, memberOrExtension, ValueParametersCount.none)
|
||||
checkFor(NEXT, memberOrExtension, ValueParametersCount.none)
|
||||
checkFor(HAS_NEXT, memberOrExtension, ValueParametersCount.none, Returns.boolean)
|
||||
checkFor(RANGE_TO, memberOrExtension, ValueParametersCount.single, noDefaultAndVarargs)
|
||||
checkFor(
|
||||
EQUALS,
|
||||
member,
|
||||
Checks.full("must override ''equals()'' in Any") { ctx, function ->
|
||||
val containingClass = function.containingClass()?.toFirRegularClass(ctx.session) ?: return@full true
|
||||
function.overriddenFunctions(containingClass, ctx).any {
|
||||
it.containingClass()?.classId?.asSingleFqName() == StandardNames.FqNames.any.toSafe()
|
||||
}
|
||||
}
|
||||
)
|
||||
checkFor(COMPARE_TO, memberOrExtension, Returns.int, ValueParametersCount.single, noDefaultAndVarargs)
|
||||
checkFor(BINARY_OPERATION_NAMES, memberOrExtension, ValueParametersCount.single, noDefaultAndVarargs)
|
||||
checkFor(SIMPLE_UNARY_OPERATION_NAMES, memberOrExtension, ValueParametersCount.none)
|
||||
checkFor(
|
||||
setOf(INC, DEC),
|
||||
memberOrExtension,
|
||||
Checks.full("receiver must be a supertype of the return type") { ctx, function ->
|
||||
val receiver = function.dispatchReceiverType ?: function.receiverTypeRef?.coneType ?: return@full false
|
||||
function.returnTypeRef.coneType.isSubtypeOf(ctx.session.typeContext, receiver)
|
||||
}
|
||||
)
|
||||
checkFor(ASSIGNMENT_OPERATIONS, memberOrExtension, Returns.unit, ValueParametersCount.single, noDefaultAndVarargs)
|
||||
}
|
||||
|
||||
val regexChecks: List<Pair<Regex, List<Check>>> = buildList {
|
||||
checkFor(COMPONENT_REGEX, memberOrExtension, ValueParametersCount.none)
|
||||
}
|
||||
|
||||
private fun MutableMap<Name, List<Check>>.checkFor(name: Name, vararg checks: Check) {
|
||||
put(name, checks.asList())
|
||||
}
|
||||
|
||||
private fun MutableMap<Name, List<Check>>.checkFor(names: Set<Name>, vararg checks: Check) {
|
||||
names.forEach { put(it, checks.asList()) }
|
||||
}
|
||||
|
||||
private fun MutableList<Pair<Regex, List<Check>>>.checkFor(regex: Regex, vararg checks: Check) {
|
||||
add(regex to checks.asList())
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,14 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnnotatedDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationByFqName
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
|
||||
object FirPublishedApiChecker : FirAnnotatedDeclarationChecker() {
|
||||
override fun check(declaration: FirAnnotatedDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration !is FirMemberDeclaration) return
|
||||
if (declaration is FirValueParameter) return
|
||||
if (declaration.visibility == Visibilities.Internal) return
|
||||
val annotation = declaration.getAnnotationByFqName(StandardNames.FqNames.publishedApi) ?: return
|
||||
reporter.reportOn(annotation.source, FirErrors.NON_INTERNAL_PUBLISHED_API, context)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCallOrigin
|
||||
import org.jetbrains.kotlin.fir.expressions.FirOperationNameConventions
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isUnit
|
||||
|
||||
object FirAssignmentOperatorCallChecker : FirFunctionCallChecker() {
|
||||
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val resolvedCallee = expression.calleeReference as? FirResolvedNamedReference ?: return
|
||||
val resolvedCalleeSymbol = resolvedCallee.resolvedSymbol as? FirNamedFunctionSymbol ?: return
|
||||
val resolvedCalleeName = resolvedCalleeSymbol.name
|
||||
if (expression.origin != FirFunctionCallOrigin.Operator ||
|
||||
resolvedCalleeName !in FirOperationNameConventions.ASSIGNMENT_NAMES
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (!expression.typeRef.coneType.isUnit) {
|
||||
reporter.reportOn(
|
||||
expression.source,
|
||||
FirErrors.ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT,
|
||||
resolvedCalleeSymbol,
|
||||
FirOperationNameConventions.ASSIGNMENT_NAMES[resolvedCalleeName]!!.operator,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ object FirDeprecationChecker : FirBasicExpressionChecker() {
|
||||
|
||||
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!allowedSourceKinds.contains(expression.source?.kind)) return
|
||||
if (expression is FirAnnotationCall) return //checked by FirDeprecatedTypeChecker
|
||||
if (expression is FirAnnotationCall || expression is FirDelegatedConstructorCall) return //checked by FirDeprecatedTypeChecker
|
||||
val resolvable = expression as? FirResolvable ?: return
|
||||
val reference = resolvable.calleeReference as? FirResolvedNamedReference ?: return
|
||||
val referencedSymbol = reference.resolvedSymbol
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.isArrayType
|
||||
|
||||
object FirNamedVarargChecker : FirCallChecker() {
|
||||
override fun check(expression: FirCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (expression !is FirFunctionCall && expression !is FirAnnotationCall && expression !is FirDelegatedConstructorCall) return
|
||||
val isAnnotation = expression is FirAnnotationCall
|
||||
val errorFactory =
|
||||
if (isAnnotation) FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION
|
||||
else FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION
|
||||
|
||||
val allowAssignArray = context.session.languageVersionSettings.supportsFeature(
|
||||
if (isAnnotation) LanguageFeature.AssigningArraysToVarargsInNamedFormInAnnotations
|
||||
else LanguageFeature.AllowAssigningArrayElementsToVarargsInNamedFormForFunctions
|
||||
)
|
||||
|
||||
fun checkArgument(argument: FirExpression) {
|
||||
if (argument !is FirNamedArgumentExpression) return
|
||||
if (argument.isSpread) return
|
||||
val typeRef = argument.expression.typeRef
|
||||
if (typeRef is FirErrorTypeRef) return
|
||||
if (argument.expression is FirArrayOfCall) return
|
||||
if (allowAssignArray && typeRef.isArrayType) return
|
||||
|
||||
reporter.reportOn(argument.expression.source, errorFactory, context)
|
||||
}
|
||||
|
||||
val argumentMap = expression.argumentMapping ?: return
|
||||
for ((argument, parameter) in argumentMap) {
|
||||
if (!parameter.isVararg) continue
|
||||
if (argument is FirVarargArgumentsExpression) {
|
||||
argument.arguments.forEach(::checkArgument)
|
||||
} else {
|
||||
checkArgument(argument)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -38,7 +38,7 @@ object FirSuspendModifierChecker : FirTypeRefChecker() {
|
||||
reporter.reportOn(
|
||||
suspendModifier.source,
|
||||
FirErrors.WRONG_MODIFIER_TARGET,
|
||||
suspendModifier.token.toString(),
|
||||
suspendModifier.token,
|
||||
"non-functional type",
|
||||
context
|
||||
)
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirExpressionChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkersComponent
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
|
||||
@OptIn(CheckersComponentInternal::class)
|
||||
@@ -137,6 +136,10 @@ class ExpressionCheckersDiagnosticComponent(
|
||||
checkers.allBlockCheckers.check(block, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitDelegatedConstructorCall(delegatedConstructorCall: FirDelegatedConstructorCall, data: CheckerContext) {
|
||||
checkers.allCallCheckers.check(delegatedConstructorCall, data, reporter)
|
||||
}
|
||||
|
||||
private fun <E : FirStatement> Collection<FirExpressionChecker<E>>.check(
|
||||
expression: E,
|
||||
context: CheckerContext,
|
||||
|
||||
@@ -64,6 +64,9 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_PASSED_T
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARGUMENT_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ARRAY_EQUALITY_OPERATOR_CAN_BE_REPLACED_WITH_EQUALS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNED_VALUE_IS_NEVER_READ
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGNMENT_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BACKING_FIELD_IN_INTERFACE
|
||||
@@ -208,6 +211,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CAND
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_FILE_TARGET
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_INFIX_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_LATEINIT_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_OPERATOR_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_PARAM_TARGET
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_TARGET_ON_PROPERTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD
|
||||
@@ -219,6 +223,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCOMPATIBLE_TYPES_WARNING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCONSISTENT_TYPE_PARAMETER_BOUNDS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INCONSISTENT_TYPE_PARAMETER_VALUES
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INC_DEC_SHOULD_NOT_RETURN_UNIT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFERENCE_ERROR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFIX_MODIFIER_REQUIRED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZATION_BEFORE_DECLARATION
|
||||
@@ -238,14 +243,13 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_INSID
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INTERFACE_WITH_SUPERCLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_CHARACTERS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_IF_AS_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVISIBLE_REFERENCE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.IS_ENUM_ENTRY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ITERATOR_AMBIGUITY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.JAVA_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LEAKED_IN_PLACE_LAMBDA
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.LOCAL_ANNOTATION_CLASS_ERROR
|
||||
@@ -290,9 +294,9 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_LOOP_LABEL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_A_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_CALLABLE_REFERENCE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_NULL_ASSERTION_ON_LAMBDA_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_YET_SUPPORTED_IN_INLINE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ACTUAL_FOR_EXPECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_YET_SUPPORTED_IN_INLINE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_COMPANION_OBJECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_ELSE_IN_WHEN
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NO_GET_METHOD
|
||||
@@ -729,18 +733,19 @@ class FirDefaultErrorMessages {
|
||||
|
||||
// Modifiers
|
||||
map.put(INAPPLICABLE_INFIX_MODIFIER, "''infix'' modifier is inapplicable on this function")
|
||||
map.put(REPEATED_MODIFIER, "Repeated ''{0}''", STRING)
|
||||
map.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", STRING, STRING)
|
||||
map.put(DEPRECATED_MODIFIER, "Modifier ''{0}'' is deprecated, use ''{1}'' instead", STRING, STRING)
|
||||
map.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", STRING, STRING)
|
||||
map.put(DEPRECATED_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is deprecated for ''{1}''", STRING, STRING)
|
||||
map.put(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", STRING, STRING)
|
||||
map.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''", STRING, STRING)
|
||||
map.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING)
|
||||
map.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING)
|
||||
map.put(DEPRECATED_MODIFIER, "Modifier ''{0}'' is deprecated, use ''{1}'' instead", TO_STRING, TO_STRING)
|
||||
map.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", TO_STRING, TO_STRING)
|
||||
map.put(DEPRECATED_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is deprecated for ''{1}''", TO_STRING, STRING)
|
||||
map.put(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", TO_STRING, STRING)
|
||||
map.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''", TO_STRING, TO_STRING)
|
||||
map.put(REDUNDANT_OPEN_IN_INTERFACE, "Modifier 'open' is redundant for abstract interface members")
|
||||
map.put(WRONG_MODIFIER_TARGET, "Modifier ''{0}'' is not applicable to ''{1}''", STRING, STRING)
|
||||
map.put(WRONG_MODIFIER_TARGET, "Modifier ''{0}'' is not applicable to ''{1}''", TO_STRING, STRING)
|
||||
map.put(INFIX_MODIFIER_REQUIRED, "''infix'' modifier is required on ''{0}''", TO_STRING)
|
||||
map.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", STRING, STRING)
|
||||
map.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", STRING, STRING)
|
||||
map.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", TO_STRING, STRING)
|
||||
map.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", TO_STRING, STRING)
|
||||
map.put(INAPPLICABLE_OPERATOR_MODIFIER, "''operator'' modifier is inapplicable on this function: {0}", STRING)
|
||||
|
||||
// Classes and interfaces
|
||||
map.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here")
|
||||
@@ -758,6 +763,8 @@ class FirDefaultErrorMessages {
|
||||
map.put(NAMED_PARAMETER_NOT_FOUND, "Cannot find a parameter with this name: {0}", TO_STRING)
|
||||
map.put(MANY_LAMBDA_EXPRESSION_ARGUMENTS, "Only one lambda expression is allowed outside a parenthesized argument list")
|
||||
map.put(SPREAD_OF_NULLABLE, "The spread operator (*foo) may not be applied to an argument of nullable type")
|
||||
map.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_FUNCTION, "Assigning single elements to varargs in named form is forbidden")
|
||||
map.put(ASSIGNING_SINGLE_ELEMENT_TO_VARARG_IN_NAMED_FORM_ANNOTATION, "Assigning single elements to varargs in named form is forbidden")
|
||||
|
||||
map.put(TYPE_MISMATCH, "Type mismatch: inferred type is {1} but {0} was expected", TO_STRING, TO_STRING)
|
||||
map.put(THROWABLE_TYPE_MISMATCH, "Throwable type mismatch: actual type is {0}", TO_STRING)
|
||||
@@ -1471,6 +1478,13 @@ class FirDefaultErrorMessages {
|
||||
RENDER_TYPE,
|
||||
RENDER_TYPE
|
||||
)
|
||||
map.put(INC_DEC_SHOULD_NOT_RETURN_UNIT, "Functions inc(), dec() shouldn't return Unit to be used by operators ++, --")
|
||||
map.put(
|
||||
ASSIGNMENT_OPERATOR_SHOULD_RETURN_UNIT,
|
||||
"Function ''{0}'' should return Unit to be used by corresponding operator ''{1}''",
|
||||
SYMBOL,
|
||||
TO_STRING
|
||||
)
|
||||
|
||||
// Type alias
|
||||
map.put(TOPLEVEL_TYPEALIASES_ONLY, "Nested and local type aliases are not supported")
|
||||
@@ -1597,9 +1611,6 @@ class FirDefaultErrorMessages {
|
||||
)
|
||||
map.put(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited")
|
||||
|
||||
// JVM
|
||||
map.put(JAVA_TYPE_MISMATCH, "Java type mismatch expected {0} but found {1}. Use explicit cast", RENDER_TYPE, RENDER_TYPE)
|
||||
|
||||
// Extended checkers group
|
||||
map.put(REDUNDANT_VISIBILITY_MODIFIER, "Redundant visibility modifier")
|
||||
map.put(REDUNDANT_MODALITY_MODIFIER, "Redundant modality modifier")
|
||||
|
||||
@@ -373,6 +373,9 @@ object LightTreePositioningStrategies {
|
||||
val DATA_MODIFIER: LightTreePositioningStrategy =
|
||||
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.DATA_KEYWORD))
|
||||
|
||||
val OPERATOR_MODIFIER: LightTreePositioningStrategy =
|
||||
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.OPERATOR_KEYWORD))
|
||||
|
||||
val INLINE_PARAMETER_MODIFIER: LightTreePositioningStrategy =
|
||||
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.NOINLINE_KEYWORD, KtTokens.CROSSINLINE_KEYWORD))
|
||||
|
||||
|
||||
@@ -304,4 +304,9 @@ object SourceElementPositioningStrategies {
|
||||
LightTreePositioningStrategies.INLINE_PARAMETER_MODIFIER,
|
||||
PositioningStrategies.INLINE_PARAMETER_MODIFIER
|
||||
)
|
||||
|
||||
val OPERATOR_MODIFIER = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.OPERATOR_MODIFIER,
|
||||
PositioningStrategies.OPERATOR_MODIFIER
|
||||
)
|
||||
}
|
||||
|
||||
@@ -212,11 +212,10 @@ data class ConeCapturedType(
|
||||
|
||||
data class ConeTypeVariableType(
|
||||
override val nullability: ConeNullability,
|
||||
override val lookupTag: ConeClassifierLookupTag
|
||||
override val lookupTag: ConeClassifierLookupTag,
|
||||
override val attributes: ConeAttributes = ConeAttributes.Empty,
|
||||
) : ConeLookupTagBasedType() {
|
||||
override val typeArguments: Array<out ConeTypeProjection> get() = emptyArray()
|
||||
|
||||
override val attributes: ConeAttributes get() = ConeAttributes.Empty
|
||||
}
|
||||
|
||||
data class ConeDefinitelyNotNullType(val original: ConeKotlinType) : ConeSimpleKotlinType(), DefinitelyNotNullTypeMarker {
|
||||
@@ -227,7 +226,7 @@ data class ConeDefinitelyNotNullType(val original: ConeKotlinType) : ConeSimpleK
|
||||
get() = ConeNullability.NOT_NULL
|
||||
|
||||
override val attributes: ConeAttributes
|
||||
get() = ConeAttributes.Empty
|
||||
get() = original.attributes
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkersComponent
|
||||
import org.jetbrains.kotlin.fir.analysis.extensions.additionalCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.diagnostics.FirJvmDefaultErrorMessages
|
||||
import org.jetbrains.kotlin.fir.checkers.registerCommonCheckers
|
||||
import org.jetbrains.kotlin.fir.checkers.registerJvmCheckers
|
||||
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
|
||||
@@ -180,6 +181,7 @@ object FirSessionFactory {
|
||||
dependenciesSymbolProvider
|
||||
)
|
||||
|
||||
FirJvmDefaultErrorMessages.installJvmErrorMessages()
|
||||
FirSessionConfigurator(this).apply {
|
||||
registerCommonCheckers()
|
||||
registerJvmCheckers()
|
||||
|
||||
@@ -67,7 +67,7 @@ abstract class AbstractFirDeserializedSymbolsProvider(
|
||||
|
||||
private val packagePartsCache = session.firCachesFactory.createCache(::tryComputePackagePartInfos)
|
||||
private val typeAliasCache = session.firCachesFactory.createCache(::findAndDeserializeTypeAlias)
|
||||
private val classCache: FirCache<ClassId, FirRegularClassSymbol?, FirDeserializationContext?> =
|
||||
protected val classCache: FirCache<ClassId, FirRegularClassSymbol?, FirDeserializationContext?> =
|
||||
session.firCachesFactory.createCacheWithPostCompute(
|
||||
createValue = { classId, context -> findAndDeserializeClass(classId, context) },
|
||||
postCompute = { _, symbol, postProcessor ->
|
||||
@@ -154,6 +154,9 @@ abstract class AbstractFirDeserializedSymbolsProvider(
|
||||
|
||||
private fun findAndDeserializeClassViaParent(classId: ClassId): FirRegularClassSymbol? {
|
||||
val outerClassId = classId.outerClassId ?: return null
|
||||
//This will cause cyclic cache request that is highly observable in IDE (but not in the compiler - but possible SOE bug also)
|
||||
//To avoid it in IDE there is special implementation that forces load parent class before any nested class request:
|
||||
//[org.jetbrains.kotlin.idea.fir.low.level.api.sessions.FirIdeSessionFactory.KotlinDeserializedJvmSymbolsProviderForIde]
|
||||
getClass(outerClassId) ?: return null
|
||||
return classCache.getValueIfComputed(classId)
|
||||
}
|
||||
@@ -180,7 +183,7 @@ abstract class AbstractFirDeserializedSymbolsProvider(
|
||||
return packagePartsCache.getValue(packageFqName)
|
||||
}
|
||||
|
||||
private fun getClass(
|
||||
protected open fun getClass(
|
||||
classId: ClassId,
|
||||
parentContext: FirDeserializationContext? = null
|
||||
): FirRegularClassSymbol? {
|
||||
|
||||
@@ -92,18 +92,18 @@ class FirJvmTypeMapper(val session: FirSession) : TypeMappingContext<JvmSignatur
|
||||
typeContext.hasNothingInNonContravariantPosition(type)
|
||||
}
|
||||
|
||||
private fun FirClassLikeSymbol<*>.toRegularClassSymbol(): FirRegularClassSymbol? = when (this) {
|
||||
is FirRegularClassSymbol -> this
|
||||
is FirTypeAliasSymbol -> {
|
||||
val expandedType = fir.expandedTypeRef.coneType.fullyExpandedType(session) as? ConeClassLikeType
|
||||
expandedType?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.buildPossiblyInnerType(): PossiblyInnerConeType? {
|
||||
if (this !is ConeClassLikeType) return null
|
||||
return buildPossiblyInnerType(lookupTag.toSymbol(session)?.toRegularClassSymbol(), 0)
|
||||
|
||||
return when (val symbol = lookupTag.toSymbol(session)) {
|
||||
is FirRegularClassSymbol -> buildPossiblyInnerType(symbol, 0)
|
||||
is FirTypeAliasSymbol -> {
|
||||
val expandedType = fullyExpandedType(session) as? ConeClassLikeType
|
||||
val classSymbol = expandedType?.lookupTag?.toSymbol(session) as? FirRegularClassSymbol
|
||||
classSymbol?.let { expandedType.buildPossiblyInnerType(it, 0) }
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeClassLikeType.parentClassOrNull(): FirRegularClassSymbol? {
|
||||
|
||||
@@ -217,7 +217,7 @@ class Fir2IrVisitor(
|
||||
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Any?): IrElement {
|
||||
val irFunction = if (simpleFunction.visibility == Visibilities.Local) {
|
||||
declarationStorage.createIrFunction(
|
||||
simpleFunction, irParent = conversionScope.parent(), isLocal = true
|
||||
simpleFunction, irParent = conversionScope.parent(), origin = IrDeclarationOrigin.LOCAL_FUNCTION, isLocal = true
|
||||
)
|
||||
} else {
|
||||
declarationStorage.getCachedIrFunction(simpleFunction)!!
|
||||
@@ -236,7 +236,7 @@ class Fir2IrVisitor(
|
||||
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Any?): IrElement {
|
||||
return anonymousFunction.convertWithOffsets { startOffset, endOffset ->
|
||||
val irFunction = declarationStorage.createIrFunction(
|
||||
anonymousFunction, irParent = conversionScope.parent(), isLocal = true
|
||||
anonymousFunction, irParent = conversionScope.parent(), origin = IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA, isLocal = true
|
||||
)
|
||||
conversionScope.withFunction(irFunction) {
|
||||
memberGenerator.convertFunctionContent(irFunction, anonymousFunction, containingClass = null)
|
||||
|
||||
@@ -42,17 +42,17 @@ private fun leastCommonPrimitiveNumericType(t1: ConeClassLikeType, t2: ConeClass
|
||||
val pt2 = t2.promoteIntegerTypeToIntIfRequired()
|
||||
|
||||
return when {
|
||||
pt1.isDouble() || pt2.isDouble() -> PrimitiveTypes.Double
|
||||
pt1.isFloat() || pt2.isFloat() -> PrimitiveTypes.Float
|
||||
pt1.isLong() || pt2.isLong() -> PrimitiveTypes.Long
|
||||
pt1.isInt() || pt2.isInt() -> PrimitiveTypes.Int
|
||||
pt1.isDouble() || pt2.isDouble() -> StandardTypes.Double
|
||||
pt1.isFloat() || pt2.isFloat() -> StandardTypes.Float
|
||||
pt1.isLong() || pt2.isLong() -> StandardTypes.Long
|
||||
pt1.isInt() || pt2.isInt() -> StandardTypes.Int
|
||||
else -> error("Unexpected types: t1=$t1, t2=$t2")
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeClassLikeType.promoteIntegerTypeToIntIfRequired(): ConeClassLikeType =
|
||||
when (lookupTag.classId) {
|
||||
StandardClassIds.Byte, StandardClassIds.Short -> PrimitiveTypes.Int
|
||||
StandardClassIds.Byte, StandardClassIds.Short -> StandardTypes.Int
|
||||
StandardClassIds.Long, StandardClassIds.Int, StandardClassIds.Float, StandardClassIds.Double, StandardClassIds.Char -> this
|
||||
else -> error("Primitive number type expected: $this")
|
||||
}
|
||||
|
||||
@@ -505,10 +505,15 @@ class CallAndReferenceGenerator(
|
||||
return applyArgumentsWithReorderingIfNeeded(argumentMapping, valueParameters, substitutor, annotationMode)
|
||||
}
|
||||
}
|
||||
// Case without argument mapping (deserialized annotation)
|
||||
// TODO: support argument mapping in deserialized annotations and remove me
|
||||
for ((index, argument) in call.arguments.withIndex()) {
|
||||
val valueParameter = valueParameters?.get(index)
|
||||
val valueParameter = when (argument) {
|
||||
is FirNamedArgumentExpression -> valueParameters?.find { it.name == argument.name }
|
||||
else -> null
|
||||
} ?: valueParameters?.get(index)
|
||||
val argumentExpression = convertArgument(argument, valueParameter, substitutor)
|
||||
putValueArgument(index, argumentExpression)
|
||||
putValueArgument(valueParameters?.indexOf(valueParameter)?.takeIf { it >= 0 } ?: index, argumentExpression)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -2390,6 +2390,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/builtinStubMethods/inheritedImplementations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("int2IntMap.kt")
|
||||
public void testInt2IntMap() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/builtinStubMethods/int2IntMap.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("Iterator.kt")
|
||||
public void testIterator() throws Exception {
|
||||
@@ -12138,6 +12144,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/functionReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inline.kt")
|
||||
public void testInline() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/coroutines/tailCallOptimizations/unit/inline.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("override.kt")
|
||||
public void testOverride() throws Exception {
|
||||
@@ -41754,6 +41766,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/syntheticExtensions"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("firstCapitalizedProperty.kt")
|
||||
public void testFirstCapitalizedProperty() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/syntheticExtensions/firstCapitalizedProperty.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fromTwoBases.kt")
|
||||
public void testFromTwoBases() throws Exception {
|
||||
|
||||
@@ -1318,6 +1318,18 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
||||
runTest("compiler/testData/codegen/boxInline/capture/generics.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt48230.kt")
|
||||
public void testKt48230() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/capture/kt48230.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt48230_2.kt")
|
||||
public void testKt48230_2() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/capture/kt48230_2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simpleCapturingInClass.kt")
|
||||
public void testSimpleCapturingInClass() throws Exception {
|
||||
@@ -1727,6 +1739,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
||||
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/checkStaticObjectClassIsPresent.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("defaultAfterCapturing.kt")
|
||||
public void testDefaultAfterCapturing() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/defaultAfterCapturing.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("defaultCallInDefaultLambda.kt")
|
||||
public void testDefaultCallInDefaultLambda() throws Exception {
|
||||
@@ -1841,6 +1859,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
||||
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/receiverClashInClass2.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("reordering.kt")
|
||||
public void testReordering() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/reordering.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
@@ -1958,6 +1982,12 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
|
||||
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/callableReferences/constuctorReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("defaultAfterBoundReference.kt")
|
||||
public void testDefaultAfterBoundReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/boxInline/defaultValues/lambdaInlining/callableReferences/defaultAfterBoundReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("differentInvokeSignature.kt")
|
||||
public void testDifferentInvokeSignature() throws Exception {
|
||||
|
||||
@@ -36,7 +36,7 @@ import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
@ThreadSafeMutableState
|
||||
class KotlinDeserializedJvmSymbolsProvider(
|
||||
open class KotlinDeserializedJvmSymbolsProvider(
|
||||
session: FirSession,
|
||||
moduleDataProvider: ModuleDataProvider,
|
||||
kotlinScopeProvider: FirKotlinScopeProvider,
|
||||
|
||||
@@ -66,11 +66,22 @@ class JavaOverrideChecker internal constructor(
|
||||
candidateTypeRef: FirTypeRef,
|
||||
baseTypeRef: FirTypeRef,
|
||||
substitutor: ConeSubstitutor
|
||||
) = isEqualTypes(
|
||||
candidateTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack),
|
||||
baseTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack),
|
||||
substitutor
|
||||
)
|
||||
): Boolean {
|
||||
val candidateType = candidateTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack)
|
||||
val baseType = baseTypeRef.toConeKotlinTypeProbablyFlexible(session, javaTypeParameterStack)
|
||||
|
||||
if (candidateType.isPrimitiveInJava() != baseType.isPrimitiveInJava()) return false
|
||||
|
||||
return isEqualTypes(
|
||||
candidateType,
|
||||
baseType,
|
||||
substitutor
|
||||
)
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.isPrimitiveInJava(): Boolean = with(context) {
|
||||
!isNullableType() && CompilerConeAttributes.EnhancedNullability !in attributes && isPrimitiveOrNullablePrimitive
|
||||
}
|
||||
|
||||
private fun isEqualArrayElementTypeProjections(
|
||||
candidateTypeProjection: ConeTypeProjection,
|
||||
|
||||
@@ -28,6 +28,8 @@ object FirJavaSyntheticNamesProvider : FirSyntheticNamesProvider() {
|
||||
if (name.isSpecial) return emptyList()
|
||||
val identifier = name.identifier
|
||||
if (identifier.isEmpty()) return emptyList()
|
||||
val firstChar = identifier[0]
|
||||
if (!firstChar.isJavaIdentifierStart() || firstChar in 'A'..'Z') return emptyList()
|
||||
val result = ArrayList<Name>(3)
|
||||
val standardName = Name.identifier(GETTER_PREFIX + identifier.capitalizeAsciiOnly())
|
||||
val length = identifier.length
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
@@ -19,6 +20,7 @@ import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
private val RETENTION_CLASS_ID = ClassId.fromString("kotlin/annotation/Retention")
|
||||
private val TARGET_CLASS_ID = ClassId.fromString("kotlin/annotation/Target")
|
||||
@@ -97,6 +99,10 @@ fun FirAnnotationContainer.getAnnotationByFqName(fqName: FqName): FirAnnotationC
|
||||
}
|
||||
}
|
||||
|
||||
fun <D> FirBasedSymbol<out D>.getAnnotationByFqName(fqName: FqName): FirAnnotationCall? where D : FirAnnotationContainer, D : FirDeclaration {
|
||||
return fir.getAnnotationByFqName(fqName)
|
||||
}
|
||||
|
||||
fun FirAnnotationContainer.getAnnotationsByFqName(fqName: FqName): List<FirAnnotationCall> = annotations.getAnnotationsByFqName(fqName)
|
||||
|
||||
fun List<FirAnnotationCall>.getAnnotationsByFqName(fqName: FqName): List<FirAnnotationCall> {
|
||||
@@ -120,3 +126,8 @@ fun FirAnnotationCall.findArgumentByName(name: Name): FirExpression? {
|
||||
// TODO: this line is still needed. However it should be replaced with 'return null'
|
||||
return arguments.singleOrNull()
|
||||
}
|
||||
|
||||
fun FirAnnotationCall.getStringArgument(name: Name): String? =
|
||||
findArgumentByName(name)?.let { expression ->
|
||||
expression.safeAs<FirConstExpression<*>>()?.value as? String
|
||||
}
|
||||
|
||||
@@ -90,11 +90,6 @@ private fun FirBasedSymbol<*>.getDeprecationForCallSite(
|
||||
return (deprecations ?: EmptyDeprecationsPerUseSite).forUseSite(*sites)
|
||||
}
|
||||
|
||||
private fun FirAnnotationCall.getStringArgument(name: Name): String? =
|
||||
findArgumentByName(name)?.let { expression ->
|
||||
expression.safeAs<FirConstExpression<*>>()?.value as? String
|
||||
}
|
||||
|
||||
private fun FirAnnotationCall.getVersionFromArgument(name: Name): ApiVersion? =
|
||||
getStringArgument(name)?.let { ApiVersion.parse(it) }
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.originalIfFakeOverride
|
||||
import org.jetbrains.kotlin.fir.originalOrSelf
|
||||
import org.jetbrains.kotlin.fir.references.FirThisReference
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
@@ -184,7 +186,7 @@ class VariableStorage(private val session: FirSession) {
|
||||
property.isVar -> PropertyStability.MUTABLE_PROPERTY
|
||||
property.receiverTypeRef != null -> PropertyStability.PROPERTY_WITH_GETTER
|
||||
property.getter.let { it != null && it !is FirDefaultPropertyAccessor } -> PropertyStability.PROPERTY_WITH_GETTER
|
||||
property.moduleData.session != session -> PropertyStability.ALIEN_PUBLIC_PROPERTY
|
||||
property.originalOrSelf().moduleData.session != session -> PropertyStability.ALIEN_PUBLIC_PROPERTY
|
||||
property.modality != Modality.FINAL -> {
|
||||
val dispatchReceiver = (originalFir.unwrapElement() as? FirQualifiedAccess)?.dispatchReceiver ?: return null
|
||||
val receiverType = dispatchReceiver.typeRef.coneTypeSafe<ConeClassLikeType>()?.fullyExpandedType(session) ?: return null
|
||||
|
||||
@@ -84,7 +84,10 @@ abstract class AbstractConeSubstitutor(private val typeContext: ConeTypeContext)
|
||||
}
|
||||
|
||||
private fun ConeDefinitelyNotNullType.substituteOriginal(): ConeKotlinType? {
|
||||
val substituted = substituteOrNull(original)?.withNullability(ConeNullability.NOT_NULL, typeContext) ?: return null
|
||||
val substituted = substituteOrNull(original)
|
||||
?.withNullability(ConeNullability.NOT_NULL, typeContext)
|
||||
?.withAttributes(original.attributes, typeContext)
|
||||
?: return null
|
||||
return ConeDefinitelyNotNullType.create(substituted, typeContext) ?: substituted
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ class FirStatusResolver(
|
||||
ProcessorAction.NEXT
|
||||
}
|
||||
}.map {
|
||||
it.ensureResolved(FirResolvePhase.STATUS)
|
||||
it.status as FirResolvedDeclarationStatus
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1148,7 +1148,7 @@ open class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransform
|
||||
anonymousObjectExpression.transformAnonymousObject(transformer, data)
|
||||
if (anonymousObjectExpression.typeRef !is FirResolvedTypeRef) {
|
||||
anonymousObjectExpression.resultType = buildResolvedTypeRef {
|
||||
source = anonymousObjectExpression.source
|
||||
source = anonymousObjectExpression.source?.fakeElement(FirFakeSourceElementKind.ImplicitTypeRef)
|
||||
this.type = anonymousObjectExpression.anonymousObject.defaultType()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,8 @@ import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLookupTagWithFixedSymbol
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||
@@ -110,6 +110,13 @@ fun <T : ConeKotlinType> T.withAttributes(attributes: ConeAttributes, typeSystem
|
||||
lowerBound.withAttributes(attributes, typeSystemContext),
|
||||
upperBound.withAttributes(attributes, typeSystemContext)
|
||||
)
|
||||
is ConeTypeVariableType -> ConeTypeVariableType(nullability, lookupTag, attributes)
|
||||
is ConeCapturedType -> ConeCapturedType(
|
||||
captureStatus, lowerType, nullability, constructor, attributes, isProjectionNotNull,
|
||||
)
|
||||
// TODO: Consider correct application of attributes to ConeIntersectionType
|
||||
// Currently, ConeAttributes.union works a bit strange, because it lefts only `other` parts
|
||||
is ConeIntersectionType -> this
|
||||
else -> error("Not supported: $this: ${this.render()}")
|
||||
} as T
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
object PrimitiveTypes {
|
||||
object StandardTypes {
|
||||
val Boolean: ConeClassLikeType = StandardClassIds.Boolean.createType()
|
||||
val Char: ConeClassLikeType = StandardClassIds.Char.createType()
|
||||
val Byte: ConeClassLikeType = StandardClassIds.Byte.createType()
|
||||
@@ -23,6 +23,8 @@ object PrimitiveTypes {
|
||||
val Long: ConeClassLikeType = StandardClassIds.Long.createType()
|
||||
val Float: ConeClassLikeType = StandardClassIds.Float.createType()
|
||||
val Double: ConeClassLikeType = StandardClassIds.Double.createType()
|
||||
|
||||
val Any: ConeClassLikeType = StandardClassIds.Any.createType()
|
||||
}
|
||||
|
||||
private fun ClassId.createType(): ConeClassLikeType =
|
||||
|
||||
@@ -60,6 +60,7 @@ object FirOperationNameConventions {
|
||||
FirOperation.REM_ASSIGN to OperatorNameConventions.REM_ASSIGN
|
||||
)
|
||||
)
|
||||
val ASSIGNMENT_NAMES = ASSIGNMENTS.map { (k, v) -> v to k }.toMap()
|
||||
|
||||
val ASSIGNMENTS_TO_SIMPLE_OPERATOR: Map<FirOperation, Name> = EnumMap(
|
||||
mapOf(
|
||||
|
||||
@@ -40,6 +40,7 @@ val FirTypeRef.isNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing
|
||||
val FirTypeRef.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds.Nothing, true)
|
||||
val FirTypeRef.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false)
|
||||
val FirTypeRef.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
|
||||
val FirTypeRef.isInt: Boolean get() = isBuiltinType(StandardClassIds.Int, false)
|
||||
val FirTypeRef.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
||||
val FirTypeRef.isArrayType: Boolean
|
||||
get() =
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.builtins.StandardNames.FqNames
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
object ArrayFqNames {
|
||||
@@ -20,5 +22,20 @@ object ArrayFqNames {
|
||||
PrimitiveType.DOUBLE to Name.identifier("doubleArrayOf")
|
||||
)
|
||||
|
||||
val ARRAY_OF_FUNCTION = Name.identifier("arrayOf")
|
||||
}
|
||||
val UNSIGNED_TYPE_TO_ARRAY: Map<FqName, Name> = hashMapOf(
|
||||
FqNames.uByteFqName to Name.identifier("ubyteArrayOf"),
|
||||
FqNames.uShortFqName to Name.identifier("ushortArrayOf"),
|
||||
FqNames.uIntFqName to Name.identifier("uintArrayOf"),
|
||||
FqNames.uLongFqName to Name.identifier("ulongArrayOf")
|
||||
)
|
||||
|
||||
val ARRAY_OF_FUNCTION: Name = Name.identifier("arrayOf")
|
||||
|
||||
val EMPTY_ARRAY: Name = Name.identifier("emptyArray")
|
||||
|
||||
val ARRAY_CALL_NAMES: Set<Name> =
|
||||
setOf(ARRAY_OF_FUNCTION, EMPTY_ARRAY) + PRIMITIVE_TYPE_TO_ARRAY.values.toSet() + UNSIGNED_TYPE_TO_ARRAY.values.toSet()
|
||||
|
||||
@JvmField
|
||||
val ARRAY_CALL_FQ_NAMES: Set<FqName> = ARRAY_CALL_NAMES.map { FqName("kotlin." + it.identifier) }.toSet()
|
||||
}
|
||||
|
||||
@@ -224,7 +224,7 @@ public interface Errors {
|
||||
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken> REDUNDANT_MODIFIER = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> WRONG_MODIFIER_TARGET = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> DEPRECATED_MODIFIER = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, KtModifierKeywordToken> DEPRECATED_MODIFIER = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> REDUNDANT_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING);
|
||||
DiagnosticFactory0<KtDeclaration> NO_EXPLICIT_VISIBILITY_IN_API_MODE = DiagnosticFactory0.create(ERROR, DECLARATION_START_TO_NAME);
|
||||
DiagnosticFactory0<KtNamedDeclaration> NO_EXPLICIT_RETURN_TYPE_IN_API_MODE = DiagnosticFactory0.create(ERROR, DECLARATION_NAME);
|
||||
|
||||
@@ -377,6 +377,9 @@ object PositioningStrategies {
|
||||
@JvmField
|
||||
val DATA_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.DATA_KEYWORD)
|
||||
|
||||
@JvmField
|
||||
val OPERATOR_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.OPERATOR_KEYWORD)
|
||||
|
||||
@JvmField
|
||||
val FOR_REDECLARATION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||
override fun mark(element: PsiElement): List<TextRange> {
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve;
|
||||
|
||||
import kotlin.collections.SetsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.builtins.UnsignedTypes;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.VariableDescriptor;
|
||||
import org.jetbrains.kotlin.name.FqNameUnsafe;
|
||||
import org.jetbrains.kotlin.psi.KtExpression;
|
||||
import org.jetbrains.kotlin.psi.KtParameter;
|
||||
import org.jetbrains.kotlin.psi.KtPsiUtil;
|
||||
@@ -39,33 +39,16 @@ import org.jetbrains.kotlin.types.TypeProjection;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.diagnostics.Errors.INVALID_TYPE_OF_ANNOTATION_MEMBER;
|
||||
import static org.jetbrains.kotlin.diagnostics.Errors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER;
|
||||
import static org.jetbrains.kotlin.resolve.ArrayFqNames.ARRAY_CALL_FQ_NAMES;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.VALUE_PARAMETER;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isAnnotationClass;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumClass;
|
||||
|
||||
public class CompileTimeConstantUtils {
|
||||
|
||||
private final static Set<String> ARRAY_CALL_NAMES = SetsKt.hashSetOf(
|
||||
"kotlin.arrayOf",
|
||||
"kotlin.doubleArrayOf",
|
||||
"kotlin.floatArrayOf",
|
||||
"kotlin.longArrayOf",
|
||||
"kotlin.intArrayOf",
|
||||
"kotlin.charArrayOf",
|
||||
"kotlin.shortArrayOf",
|
||||
"kotlin.byteArrayOf",
|
||||
"kotlin.booleanArrayOf",
|
||||
"kotlin.emptyArray",
|
||||
"kotlin.ubyteArrayOf",
|
||||
"kotlin.ushortArrayOf",
|
||||
"kotlin.uintArrayOf",
|
||||
"kotlin.ulongArrayOf"
|
||||
);
|
||||
|
||||
public static void checkConstructorParametersType(@NotNull List<KtParameter> parameters, @NotNull BindingTrace trace) {
|
||||
for (KtParameter parameter : parameters) {
|
||||
VariableDescriptor parameterDescriptor = trace.getBindingContext().get(VALUE_PARAMETER, parameter);
|
||||
@@ -121,7 +104,10 @@ public class CompileTimeConstantUtils {
|
||||
}
|
||||
|
||||
public static boolean isArrayFunctionCall(@NotNull ResolvedCall<?> resolvedCall) {
|
||||
return ARRAY_CALL_NAMES.contains(DescriptorUtils.getFqName(resolvedCall.getCandidateDescriptor()).asString());
|
||||
FqNameUnsafe unsafe = DescriptorUtils.getFqName(resolvedCall.getCandidateDescriptor());
|
||||
// If the fully qualified name is unsafe, i.e., contains < or >, it shouldn't be any of `arrayOf` calls.
|
||||
if (!unsafe.isSafe()) return false;
|
||||
return ARRAY_CALL_FQ_NAMES.contains(unsafe.toSafe());
|
||||
}
|
||||
|
||||
public static boolean canBeReducedToBooleanConstant(
|
||||
|
||||
@@ -13,55 +13,15 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
|
||||
import org.jetbrains.kotlin.psi.KtModifierList
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
import org.jetbrains.kotlin.resolve.KeywordType.*
|
||||
import org.jetbrains.kotlin.resolve.KeywordType.Annotation
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.checkCoroutinesFeature
|
||||
|
||||
object ModifierCheckerCore {
|
||||
private val ktKeywordToKeywordTypeMap: Map<KtKeywordToken, KeywordType> = mapOf(
|
||||
INNER_KEYWORD to Inner,
|
||||
OVERRIDE_KEYWORD to Override,
|
||||
PUBLIC_KEYWORD to Public,
|
||||
PROTECTED_KEYWORD to Protected,
|
||||
INTERNAL_KEYWORD to Internal,
|
||||
PRIVATE_KEYWORD to Private,
|
||||
COMPANION_KEYWORD to KeywordType.Companion,
|
||||
FINAL_KEYWORD to Final,
|
||||
VARARG_KEYWORD to Vararg,
|
||||
ENUM_KEYWORD to KeywordType.Enum,
|
||||
ABSTRACT_KEYWORD to Abstract,
|
||||
OPEN_KEYWORD to Open,
|
||||
SEALED_KEYWORD to Sealed,
|
||||
IN_KEYWORD to In,
|
||||
OUT_KEYWORD to Out,
|
||||
REIFIED_KEYWORD to Reified,
|
||||
LATEINIT_KEYWORD to Lateinit,
|
||||
DATA_KEYWORD to Data,
|
||||
INLINE_KEYWORD to Inline,
|
||||
NOINLINE_KEYWORD to Noinline,
|
||||
TAILREC_KEYWORD to Tailrec,
|
||||
SUSPEND_KEYWORD to Suspend,
|
||||
EXTERNAL_KEYWORD to External,
|
||||
ANNOTATION_KEYWORD to Annotation,
|
||||
CROSSINLINE_KEYWORD to Crossinline,
|
||||
CONST_KEYWORD to Const,
|
||||
OPERATOR_KEYWORD to Operator,
|
||||
INFIX_KEYWORD to Infix,
|
||||
HEADER_KEYWORD to Header,
|
||||
IMPL_KEYWORD to Impl,
|
||||
EXPECT_KEYWORD to Expect,
|
||||
ACTUAL_KEYWORD to Actual,
|
||||
FUN_KEYWORD to Fun,
|
||||
VALUE_KEYWORD to Value
|
||||
)
|
||||
|
||||
fun check(
|
||||
listOwner: KtModifierListOwner,
|
||||
trace: BindingTrace,
|
||||
@@ -123,10 +83,9 @@ object ModifierCheckerCore {
|
||||
owner: PsiElement,
|
||||
incorrectNodes: MutableSet<ASTNode>
|
||||
) {
|
||||
val (firstModifier, firstModifierType) = getModifierAndModifierType(firstNode)
|
||||
val (secondModifier, secondModifierType) = getModifierAndModifierType(secondNode)
|
||||
|
||||
when (val compatibility = compatibility(firstModifierType, secondModifierType)) {
|
||||
val firstModifier = firstNode.elementType as KtModifierKeywordToken
|
||||
val secondModifier = secondNode.elementType as KtModifierKeywordToken
|
||||
when (val compatibility = compatibility(firstModifier, secondModifier)) {
|
||||
Compatibility.COMPATIBLE -> {
|
||||
}
|
||||
Compatibility.REPEATED -> if (incorrectNodes.add(secondNode)) {
|
||||
@@ -156,19 +115,19 @@ object ModifierCheckerCore {
|
||||
|
||||
// Should return false if error is reported, true otherwise
|
||||
private fun checkTarget(trace: BindingTrace, node: ASTNode, actualTargets: List<KotlinTarget>): Boolean {
|
||||
val (modifier, modifierType) = getModifierAndModifierType(node)
|
||||
val modifier = node.elementType as KtModifierKeywordToken
|
||||
|
||||
val possibleTargets = possibleTargetMap[modifierType] ?: emptySet()
|
||||
val possibleTargets = possibleTargetMap[modifier] ?: emptySet()
|
||||
if (!actualTargets.any { it in possibleTargets }) {
|
||||
trace.report(Errors.WRONG_MODIFIER_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this"))
|
||||
return false
|
||||
}
|
||||
val deprecatedModifierReplacement = deprecatedModifierMap[modifierType]
|
||||
val deprecatedTargets = deprecatedTargetMap[modifierType] ?: emptySet()
|
||||
val redundantTargets = redundantTargetMap[modifierType] ?: emptySet()
|
||||
val deprecatedModifierReplacement = deprecatedModifierMap[modifier]
|
||||
val deprecatedTargets = deprecatedTargetMap[modifier] ?: emptySet()
|
||||
val redundantTargets = redundantTargetMap[modifier] ?: emptySet()
|
||||
when {
|
||||
deprecatedModifierReplacement != null ->
|
||||
trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement.render()))
|
||||
trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement))
|
||||
actualTargets.any { it in deprecatedTargets } ->
|
||||
trace.report(
|
||||
Errors.DEPRECATED_MODIFIER_FOR_TARGET.on(
|
||||
@@ -196,7 +155,7 @@ object ModifierCheckerCore {
|
||||
parentDescriptor: DeclarationDescriptor?,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): Boolean {
|
||||
val (modifier, modifierType) = getModifierAndModifierType(node)
|
||||
val modifier = node.elementType as KtModifierKeywordToken
|
||||
|
||||
val actualParents: List<KotlinTarget> = when (parentDescriptor) {
|
||||
is ClassDescriptor -> KotlinTarget.classActualTargets(
|
||||
@@ -210,7 +169,7 @@ object ModifierCheckerCore {
|
||||
is FunctionDescriptor -> KotlinTarget.FUNCTION_LIST
|
||||
else -> KotlinTarget.FILE_LIST
|
||||
}
|
||||
val deprecatedParents = deprecatedParentTargetMap[modifierType]
|
||||
val deprecatedParents = deprecatedParentTargetMap[modifier]
|
||||
if (deprecatedParents != null && actualParents.any { it in deprecatedParents }) {
|
||||
trace.report(
|
||||
Errors.DEPRECATED_MODIFIER_CONTAINING_DECLARATION.on(
|
||||
@@ -221,7 +180,7 @@ object ModifierCheckerCore {
|
||||
)
|
||||
return true
|
||||
}
|
||||
val possibleParentPredicate = possibleParentTargetPredicateMap[modifierType] ?: return true
|
||||
val possibleParentPredicate = possibleParentTargetPredicateMap[modifier] ?: return true
|
||||
if (actualParents.any { possibleParentPredicate.isAllowed(it, languageVersionSettings) }) return true
|
||||
trace.report(
|
||||
Errors.WRONG_MODIFIER_CONTAINING_DECLARATION.on(
|
||||
@@ -239,9 +198,9 @@ object ModifierCheckerCore {
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
actualTargets: List<KotlinTarget>
|
||||
): Boolean {
|
||||
val (_, modifierType) = getModifierAndModifierType(node)
|
||||
val modifier = node.elementType as KtModifierKeywordToken
|
||||
|
||||
val dependencies = featureDependencies[modifierType] ?: return true
|
||||
val dependencies = featureDependencies[modifier] ?: return true
|
||||
for (dependency in dependencies) {
|
||||
val restrictedTargets = featureDependenciesTargets[dependency]
|
||||
if (restrictedTargets != null && actualTargets.intersect(restrictedTargets).isEmpty()) {
|
||||
@@ -282,9 +241,4 @@ object ModifierCheckerCore {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun getModifierAndModifierType(node: ASTNode): Pair<KtModifierKeywordToken, KeywordType> {
|
||||
val modifier = node.elementType as KtModifierKeywordToken
|
||||
return Pair(modifier, ktKeywordToKeywordTypeMap[modifier]!!)
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.MemberDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI
|
||||
@@ -23,6 +25,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.OptionalAnnotationUtil
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
// `doRemove` means should expect-declaration be removed from IR
|
||||
@OptIn(ObsoleteDescriptorBasedAPI::class)
|
||||
@@ -100,10 +103,11 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va
|
||||
// the `actual fun` or `actual constructor` for this may be in a different module.
|
||||
// Nothing we can do with those.
|
||||
// TODO they may not actually have the defaults though -- may be a frontend bug.
|
||||
val expectFunction = function.findExpectForActual()
|
||||
val expectParameter = expectFunction?.valueParameters?.get(index) ?: return
|
||||
val expectFunction =
|
||||
function.descriptor.findExpectForActual().safeAs<FunctionDescriptor>()?.let { symbolTable.referenceFunction(it).owner }
|
||||
?: return
|
||||
|
||||
val defaultValue = expectParameter.defaultValue ?: return
|
||||
val defaultValue = expectFunction.valueParameters[index].defaultValue ?: return
|
||||
|
||||
val expectToActual = expectFunction to function
|
||||
if (expectToActual !in typeParameterSubstitutionMap) {
|
||||
@@ -129,30 +133,19 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.findActualForExpected(): IrFunction? =
|
||||
descriptor.findActualForExpect()?.let { symbolTable.referenceFunction(it).owner }
|
||||
|
||||
private fun IrFunction.findExpectForActual(): IrFunction? =
|
||||
descriptor.findExpectForActual()?.let { symbolTable.referenceFunction(it).owner }
|
||||
|
||||
private fun IrClass.findActualForExpected(): IrClass? =
|
||||
descriptor.findActualForExpect()?.let { symbolTable.referenceClass(it).owner }
|
||||
|
||||
private inline fun <reified T : MemberDescriptor> T.findActualForExpect() = with(ExpectedActualResolver) {
|
||||
val descriptor = this@findActualForExpect
|
||||
|
||||
if (!descriptor.isExpect) error(this)
|
||||
|
||||
findCompatibleActualForExpected(descriptor.module).singleOrNull()
|
||||
} as T?
|
||||
|
||||
private inline fun <reified T : MemberDescriptor> T.findExpectForActual() = with(ExpectedActualResolver) {
|
||||
val descriptor = this@findExpectForActual
|
||||
|
||||
if (!descriptor.isActual) error(this) else {
|
||||
findCompatibleExpectedForActual(descriptor.module).singleOrNull()
|
||||
private fun MemberDescriptor.findActualForExpect(): MemberDescriptor? {
|
||||
if (!isExpect) error(this)
|
||||
return with(ExpectedActualResolver) {
|
||||
findCompatibleActualForExpected(this@findActualForExpect.module).singleOrNull()
|
||||
}
|
||||
} as T?
|
||||
}
|
||||
|
||||
private fun MemberDescriptor.findExpectForActual(): MemberDescriptor? {
|
||||
if (!isActual) error(this)
|
||||
return with(ExpectedActualResolver) {
|
||||
findCompatibleExpectedForActual(this@findExpectForActual.module).singleOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrExpression.remapExpectValueSymbols(): IrExpression {
|
||||
return this.transform(object : IrElementTransformerVoid() {
|
||||
@@ -179,22 +172,25 @@ class ExpectDeclarationRemover(val symbolTable: ReferenceSymbolTable, private va
|
||||
}
|
||||
|
||||
val parameter = symbol.owner
|
||||
val parent = parameter.parent
|
||||
|
||||
return when (parent) {
|
||||
return when (val parent = parameter.parent) {
|
||||
is IrClass -> {
|
||||
assert(parameter == parent.thisReceiver)
|
||||
parent.findActualForExpected()!!.thisReceiver!!
|
||||
symbolTable.referenceClass(parent.descriptor.findActualForExpect() as ClassDescriptor).owner.thisReceiver!!
|
||||
}
|
||||
|
||||
is IrFunction -> when (parameter) {
|
||||
parent.dispatchReceiverParameter ->
|
||||
parent.findActualForExpected()!!.dispatchReceiverParameter!!
|
||||
parent.extensionReceiverParameter ->
|
||||
parent.findActualForExpected()!!.extensionReceiverParameter!!
|
||||
else -> {
|
||||
assert(parent.valueParameters[parameter.index] == parameter)
|
||||
parent.findActualForExpected()!!.valueParameters[parameter.index]
|
||||
is IrFunction -> {
|
||||
val actualFunction =
|
||||
symbolTable.referenceFunction(parent.descriptor.findActualForExpect() as FunctionDescriptor).owner
|
||||
when (parameter) {
|
||||
parent.dispatchReceiverParameter ->
|
||||
actualFunction.dispatchReceiverParameter!!
|
||||
parent.extensionReceiverParameter ->
|
||||
actualFunction.extensionReceiverParameter!!
|
||||
else -> {
|
||||
assert(parent.valueParameters[parameter.index] == parameter)
|
||||
actualFunction.valueParameters[parameter.index]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,8 +121,12 @@ private class PerformByIrFilePhase<Context : CommonBackendContext>(
|
||||
input.files.clear()
|
||||
input.files.addAll(filesAndStates.map { (irFile, _) -> irFile }.toMutableList())
|
||||
|
||||
// Some remappers in handleDeepCopy depend on entries in remappedFunctions inserted by adjustDefaultArgumentStubs.
|
||||
adjustDefaultArgumentStubs(context, remappedFunctions)
|
||||
context.handleDeepCopy(remappedFiles, remappedClasses, remappedFunctions)
|
||||
// and some entries in adjustDefaultArgumentStubs depend on those inserted by handleDeepCopy, so we need to repeat the call.
|
||||
adjustDefaultArgumentStubs(context, remappedFunctions)
|
||||
|
||||
input.transformChildrenVoid(CrossFileCallAdjuster(remappedFunctions))
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
import java.io.File
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
interface MetadataSerializer {
|
||||
fun serialize(metadata: MetadataSource): Pair<MessageLite, JvmStringTable>?
|
||||
@@ -335,7 +334,7 @@ class ClassCodegen private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private val generatedInlineMethods = ConcurrentHashMap<IrFunction, SMAPAndMethodNode>()
|
||||
private val generatedInlineMethods = mutableMapOf<IrFunction, SMAPAndMethodNode>()
|
||||
|
||||
fun generateMethodNode(method: IrFunction): SMAPAndMethodNode {
|
||||
if (!method.isInline && !method.isSuspendCapturingCrossinline()) {
|
||||
@@ -501,7 +500,7 @@ class ClassCodegen private constructor(
|
||||
it.origin == JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER
|
||||
},
|
||||
): ClassCodegen =
|
||||
context.classCodegens.getOrPut(irClass) { ClassCodegen(irClass, context, parentFunction) }.also {
|
||||
context.classCodegens.computeIfAbsent(irClass) { ClassCodegen(irClass, context, parentFunction) }.also {
|
||||
assert(parentFunction == null || it.parentFunction == parentFunction) {
|
||||
"inconsistent parent function for ${irClass.render()}:\n" +
|
||||
"New: ${parentFunction!!.render()}\n" +
|
||||
|
||||
@@ -1159,6 +1159,11 @@ class ExpressionCodegen(
|
||||
|
||||
override fun visitBreakContinue(jump: IrBreakContinue, data: BlockInfo): PromisedValue {
|
||||
jump.markLineNumber(startOffset = true)
|
||||
// Make sure that the line number has an instruction so that the debugger can always
|
||||
// break on the break/continue. As an example, unwindBlockStack could otherwise
|
||||
// generate a new line number immediately which would lead to the line number for
|
||||
// the break/continue being ignored.
|
||||
mv.nop()
|
||||
val endLabel = Label()
|
||||
val stackElement = unwindBlockStack(endLabel, data) { it.loop == jump.loop }
|
||||
if (stackElement == null) {
|
||||
|
||||
@@ -377,7 +377,7 @@ private class AddContinuationLowering(context: JvmBackendContext) : SuspendLower
|
||||
// the result is called 'view', just to be consistent with old backend.
|
||||
private fun IrSimpleFunction.suspendFunctionViewOrStub(context: JvmBackendContext): IrSimpleFunction {
|
||||
if (!isSuspend) return this
|
||||
return context.suspendFunctionOriginalToView.getOrPut(suspendFunctionOriginal()) { createSuspendFunctionStub(context) }
|
||||
return context.suspendFunctionOriginalToView.getOrPut(this) { createSuspendFunctionStub(context) }
|
||||
}
|
||||
|
||||
internal fun IrSimpleFunction.suspendFunctionOriginal(): IrSimpleFunction =
|
||||
|
||||
@@ -39,6 +39,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTransformerVoid(), ClassLoweringPass {
|
||||
|
||||
private val removedFunctions = hashMapOf<IrSimpleFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||
private val removedFunctionsWithoutRemapping = mutableSetOf<IrSimpleFunctionSymbol>()
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (!irClass.isJvmInterface) return
|
||||
@@ -50,7 +51,7 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
||||
}
|
||||
|
||||
irClass.declarations.removeAll {
|
||||
it is IrFunction && removedFunctions.containsKey(it.symbol)
|
||||
it is IrFunction && (removedFunctions.containsKey(it.symbol) || removedFunctionsWithoutRemapping.contains(it.symbol))
|
||||
}
|
||||
|
||||
val defaultImplsIrClass = context.cachedDeclarations.getDefaultImplsClass(irClass)
|
||||
@@ -131,9 +132,17 @@ internal class InterfaceLowering(val context: JvmBackendContext) : IrElementTran
|
||||
(function.origin == JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_PROPERTY_OR_TYPEALIAS_ANNOTATIONS &&
|
||||
(isCompatibilityMode || jvmDefaultMode == JvmDefaultMode.ENABLE) &&
|
||||
function.isCompiledToJvmDefault(jvmDefaultMode)) -> {
|
||||
val defaultImpl = createDefaultImpl(function)
|
||||
defaultImpl.body = function.moveBodyTo(defaultImpl)
|
||||
removedFunctions[function.symbol] = defaultImpl.symbol
|
||||
if (function.origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA || function.origin == IrDeclarationOrigin.LOCAL_FUNCTION) {
|
||||
//move as is
|
||||
val defaultImplsClass = context.cachedDeclarations.getDefaultImplsClass(irClass)
|
||||
defaultImplsClass.declarations.add(function)
|
||||
removedFunctionsWithoutRemapping.add(function.symbol)
|
||||
function.parent = defaultImplsClass
|
||||
} else {
|
||||
val defaultImpl = createDefaultImpl(function)
|
||||
defaultImpl.body = function.moveBodyTo(defaultImpl)
|
||||
removedFunctions[function.symbol] = defaultImpl.symbol
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,11 +39,15 @@ class FunctionGenerator(declarationGenerator: DeclarationGenerator) : Declaratio
|
||||
|
||||
constructor(context: GeneratorContext) : this(DeclarationGenerator(context))
|
||||
|
||||
fun generateFunctionDeclaration(ktFunction: KtNamedFunction): IrSimpleFunction =
|
||||
@JvmOverloads
|
||||
fun generateFunctionDeclaration(
|
||||
ktFunction: KtNamedFunction,
|
||||
origin: IrDeclarationOrigin = IrDeclarationOrigin.DEFINED
|
||||
): IrSimpleFunction =
|
||||
declareSimpleFunction(
|
||||
ktFunction,
|
||||
ktFunction.receiverTypeReference,
|
||||
IrDeclarationOrigin.DEFINED,
|
||||
origin,
|
||||
getOrFail(BindingContext.FUNCTION, ktFunction)
|
||||
) {
|
||||
ktFunction.bodyExpression?.let { generateFunctionBody(it) }
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.psi2ir.generators
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl
|
||||
import org.jetbrains.kotlin.psi.KtLambdaExpression
|
||||
@@ -53,5 +54,5 @@ class LocalFunctionGenerator(statementGenerator: StatementGenerator) : Statement
|
||||
}
|
||||
|
||||
private fun generateFunctionDeclaration(ktFun: KtNamedFunction) =
|
||||
FunctionGenerator(context).generateFunctionDeclaration(ktFun)
|
||||
FunctionGenerator(context).generateFunctionDeclaration(ktFun, IrDeclarationOrigin.LOCAL_FUNCTION)
|
||||
}
|
||||
@@ -49,6 +49,7 @@ interface IrDeclarationOrigin {
|
||||
object SCRIPT_RESULT_PROPERTY : IrDeclarationOriginImpl("SCRIPT_RESULT_PROPERTY")
|
||||
object GENERATED_DATA_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_DATA_CLASS_MEMBER")
|
||||
object GENERATED_INLINE_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_INLINE_CLASS_MEMBER")
|
||||
object LOCAL_FUNCTION : IrDeclarationOriginImpl("LOCAL_FUNCTION")
|
||||
object LOCAL_FUNCTION_FOR_LAMBDA : IrDeclarationOriginImpl("LOCAL_FUNCTION_FOR_LAMBDA")
|
||||
object CATCH_PARAMETER : IrDeclarationOriginImpl("CATCH_PARAMETER")
|
||||
object INSTANCE_RECEIVER : IrDeclarationOriginImpl("INSTANCE_RECEIVER")
|
||||
|
||||
@@ -67,6 +67,7 @@ class SignatureIdNotFoundInModuleWithDependencies(
|
||||
allModules = allModules,
|
||||
problemModuleIds = setOf(problemModuleId),
|
||||
problemCause = "This module requires symbol ${idSignature.render()}",
|
||||
sourceCodeModuleId = userVisibleIrModulesSupport.sourceCodeModuleId,
|
||||
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
|
||||
)
|
||||
}
|
||||
@@ -113,6 +114,7 @@ class SymbolTypeMismatch(
|
||||
potentiallyConflictingDependencies = findPotentiallyConflictingIncomingDependencies(
|
||||
problemModuleId = declaringModuleId,
|
||||
allModules = allModules,
|
||||
sourceCodeModuleId = userVisibleIrModulesSupport.sourceCodeModuleId,
|
||||
),
|
||||
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
|
||||
)
|
||||
@@ -125,6 +127,7 @@ class SymbolTypeMismatch(
|
||||
problemCause = "This module contains ${
|
||||
idSignature?.render()?.let { "symbol $it" } ?: "a symbol"
|
||||
} that is the cause of the conflict",
|
||||
sourceCodeModuleId = userVisibleIrModulesSupport.sourceCodeModuleId,
|
||||
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
|
||||
)
|
||||
}
|
||||
@@ -159,6 +162,7 @@ private fun StringBuilder.appendProjectDependencies(
|
||||
allModules: Map<ResolvedDependencyId, ResolvedDependency>,
|
||||
problemModuleIds: Set<ResolvedDependencyId>,
|
||||
problemCause: String,
|
||||
sourceCodeModuleId: ResolvedDependencyId,
|
||||
moduleIdComparator: Comparator<ResolvedDependencyId>
|
||||
) {
|
||||
append("\n\nProject dependencies:")
|
||||
@@ -195,8 +199,7 @@ private fun StringBuilder.appendProjectDependencies(
|
||||
append('\n').append(data.regularLinePrefix)
|
||||
append(module.id)
|
||||
|
||||
val incomingDependencyId: ResolvedDependencyId = parentData?.incomingDependencyId
|
||||
?: ResolvedDependencyId.SOURCE_CODE_MODULE_ID
|
||||
val incomingDependencyId: ResolvedDependencyId = parentData?.incomingDependencyId ?: sourceCodeModuleId
|
||||
val requestedVersion: ResolvedDependencyVersion = module.requestedVersionsByIncomingDependencies.getValue(incomingDependencyId)
|
||||
if (!requestedVersion.isEmpty() || !module.selectedVersion.isEmpty()) {
|
||||
append(": ")
|
||||
@@ -240,8 +243,7 @@ private fun StringBuilder.appendProjectDependencies(
|
||||
}
|
||||
|
||||
// Find first-level dependencies. I.e. the modules that the source code module directly depends on.
|
||||
val firstLevelDependencies: Collection<ResolvedDependency> =
|
||||
incomingDependencyIdToDependencies.getValue(ResolvedDependencyId.SOURCE_CODE_MODULE_ID)
|
||||
val firstLevelDependencies: Collection<ResolvedDependency> = incomingDependencyIdToDependencies.getValue(sourceCodeModuleId)
|
||||
|
||||
renderModules(firstLevelDependencies, parentData = null)
|
||||
|
||||
@@ -257,9 +259,9 @@ private class Data(val parent: Data?, val incomingDependencyId: ResolvedDependen
|
||||
get() {
|
||||
return generateSequence(this) { it.parent }.map {
|
||||
if (it === this) {
|
||||
if (it.isLast) "\u2514\u2500\u2500\u2500 " /* └─── */ else "\u251C\u2500\u2500\u2500 " /* ├─── */
|
||||
if (it.isLast) "\\--- " else "+--- "
|
||||
} else {
|
||||
if (it.isLast) " " else "\u2502 " /* │ */
|
||||
if (it.isLast) " " else "| "
|
||||
}
|
||||
}.toList().asReversed().joinToString(separator = "")
|
||||
}
|
||||
@@ -267,7 +269,7 @@ private class Data(val parent: Data?, val incomingDependencyId: ResolvedDependen
|
||||
val errorLinePrefix: String
|
||||
get() {
|
||||
return generateSequence(this) { it.parent }.map {
|
||||
if (it.isLast) " " else "\u2502 " /* │ */
|
||||
if (it.isLast) " " else "| "
|
||||
}.toList().asReversed().joinToString(separator = "")
|
||||
}
|
||||
}
|
||||
@@ -375,7 +377,8 @@ private fun findPotentiallyConflictingOutgoingDependencies(
|
||||
*/
|
||||
private fun findPotentiallyConflictingIncomingDependencies(
|
||||
problemModuleId: ResolvedDependencyId,
|
||||
allModules: Map<ResolvedDependencyId, ResolvedDependency>
|
||||
allModules: Map<ResolvedDependencyId, ResolvedDependency>,
|
||||
sourceCodeModuleId: ResolvedDependencyId
|
||||
): Map<ResolvedDependencyId, PotentialConflictDescription> {
|
||||
|
||||
val dependencyStatesMap: MutableMap<ResolvedDependencyId, MutableSet<DependencyState>> = mutableMapOf()
|
||||
@@ -384,7 +387,7 @@ private fun findPotentiallyConflictingIncomingDependencies(
|
||||
val module = allModules.findMatchingModule(moduleId)
|
||||
|
||||
module.requestedVersionsByIncomingDependencies.forEach { (incomingDependencyId, requestedVersion) ->
|
||||
if (incomingDependencyId == ResolvedDependencyId.SOURCE_CODE_MODULE_ID) return@forEach
|
||||
if (incomingDependencyId == sourceCodeModuleId) return@forEach
|
||||
|
||||
val dependencyState: DependencyState = when {
|
||||
aboveConflictingDependency -> {
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.uniqueName
|
||||
import org.jetbrains.kotlin.utils.*
|
||||
|
||||
open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader: ExternalDependenciesLoader) {
|
||||
open class UserVisibleIrModulesSupport(externalDependenciesLoader: ExternalDependenciesLoader) {
|
||||
/**
|
||||
* Load external [ResolvedDependency]s provided by the build system. These dependencies:
|
||||
* - all have [ResolvedDependency.selectedVersion] specified
|
||||
@@ -23,24 +23,24 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
||||
* not visible to the build system
|
||||
*/
|
||||
interface ExternalDependenciesLoader {
|
||||
fun load(): Collection<ResolvedDependency>
|
||||
fun load(): ResolvedDependencies
|
||||
|
||||
companion object {
|
||||
val EMPTY = object : ExternalDependenciesLoader {
|
||||
override fun load(): Collection<ResolvedDependency> = emptyList()
|
||||
override fun load(): ResolvedDependencies = ResolvedDependencies.EMPTY
|
||||
}
|
||||
|
||||
fun from(externalDependenciesFile: File?, onMalformedExternalDependencies: (String) -> Unit): ExternalDependenciesLoader =
|
||||
if (externalDependenciesFile != null)
|
||||
object : ExternalDependenciesLoader {
|
||||
override fun load(): Collection<ResolvedDependency> {
|
||||
override fun load(): ResolvedDependencies {
|
||||
return if (externalDependenciesFile.exists) {
|
||||
// Deserialize external dependencies from the [externalDependenciesFile].
|
||||
val externalDependenciesText = String(externalDependenciesFile.readBytes())
|
||||
ResolvedDependenciesSupport.deserialize(externalDependenciesText) { lineNo, line ->
|
||||
onMalformedExternalDependencies("Malformed external dependencies at $externalDependenciesFile:$lineNo: $line")
|
||||
}
|
||||
} else emptyList()
|
||||
} else ResolvedDependencies.EMPTY
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -48,6 +48,16 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
||||
}
|
||||
}
|
||||
|
||||
private val externalDependencies: ResolvedDependencies by lazy {
|
||||
externalDependenciesLoader.load()
|
||||
}
|
||||
|
||||
private val externalDependencyModules: Collection<ResolvedDependency>
|
||||
get() = externalDependencies.modules
|
||||
|
||||
val sourceCodeModuleId: ResolvedDependencyId
|
||||
get() = externalDependencies.sourceCodeModuleId
|
||||
|
||||
fun getUserVisibleModuleId(deserializer: IrModuleDeserializer): ResolvedDependencyId {
|
||||
val nameFromMetadataModuleHeader: String = deserializer.moduleFragment.name.asStringStripSpecialMarkers()
|
||||
val nameFromKlibManifest: String? = deserializer.kotlinLibrary?.uniqueName
|
||||
@@ -65,23 +75,30 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
||||
* (and therefore are missing in [ExternalDependenciesLoader.load]) but are provided by the compiler. For Kotlin/Native such
|
||||
* libraries are stdlib, endorsed and platform libraries.
|
||||
*/
|
||||
protected open fun modulesFromDeserializers(deserializers: Collection<IrModuleDeserializer>): Map<ResolvedDependencyId, ResolvedDependency> {
|
||||
val modules: Map<ResolvedDependencyId, ModuleWithUninitializedDependencies> = deserializers.associate { deserializer ->
|
||||
protected open fun modulesFromDeserializers(
|
||||
deserializers: Collection<IrModuleDeserializer>,
|
||||
excludedModuleIds: Set<ResolvedDependencyId>
|
||||
): Map<ResolvedDependencyId, ResolvedDependency> {
|
||||
val modules: Map<ResolvedDependencyId, ModuleWithUninitializedDependencies> = deserializers.mapNotNull { deserializer ->
|
||||
val moduleId = getUserVisibleModuleId(deserializer)
|
||||
if (moduleId in excludedModuleIds) return@mapNotNull null
|
||||
|
||||
val module = ResolvedDependency(
|
||||
id = moduleId,
|
||||
// TODO: support extracting all the necessary details for non-Native libs: selectedVersion, requestedVersions, artifacts
|
||||
selectedVersion = ResolvedDependencyVersion.EMPTY,
|
||||
// Assumption: As we don't know for sure which modules the source code module depends on directly and which modules
|
||||
// it depends on transitively, so let's assume it depends on all modules directly.
|
||||
requestedVersionsByIncomingDependencies = mutableMapOf(ResolvedDependencyId.SOURCE_CODE_MODULE_ID to ResolvedDependencyVersion.EMPTY),
|
||||
requestedVersionsByIncomingDependencies = mutableMapOf(
|
||||
ResolvedDependencyId.DEFAULT_SOURCE_CODE_MODULE_ID to ResolvedDependencyVersion.EMPTY
|
||||
),
|
||||
artifactPaths = mutableSetOf()
|
||||
)
|
||||
|
||||
val outgoingDependencyIds = deserializer.moduleDependencies.map { getUserVisibleModuleId(it) }
|
||||
|
||||
moduleId to ModuleWithUninitializedDependencies(module, outgoingDependencyIds)
|
||||
}
|
||||
}.toMap()
|
||||
|
||||
// Stamp dependencies.
|
||||
return modules.stampDependenciesWithRequestedVersionEqualToSelectedVersion()
|
||||
@@ -91,9 +108,6 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
||||
* The result of the merge of [ExternalDependenciesLoader.load] and [modulesFromDeserializers].
|
||||
*/
|
||||
protected fun mergedModules(deserializers: Collection<IrModuleDeserializer>): MutableMap<ResolvedDependencyId, ResolvedDependency> {
|
||||
// First, load external dependencies.
|
||||
val externalDependencyModules: Collection<ResolvedDependency> = externalDependenciesLoader.load()
|
||||
|
||||
val externalDependencyModulesByNames: Map</* unique name */ String, ResolvedDependency> =
|
||||
mutableMapOf<String, ResolvedDependency>().apply {
|
||||
externalDependencyModules.forEach { externalDependency ->
|
||||
@@ -118,7 +132,10 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
||||
val providedModules = mutableListOf<ResolvedDependency>()
|
||||
|
||||
// Next, merge external dependencies with dependencies from deserializers.
|
||||
modulesFromDeserializers(deserializers).forEach { (moduleId, module) ->
|
||||
modulesFromDeserializers(
|
||||
deserializers = deserializers,
|
||||
excludedModuleIds = setOf(sourceCodeModuleId)
|
||||
).forEach { (moduleId, module) ->
|
||||
val externalDependencyModule = findMatchingExternalDependencyModule(moduleId)
|
||||
if (externalDependencyModule != null) {
|
||||
// Just add missing dependencies to the same module in [mergedModules].
|
||||
@@ -146,7 +163,7 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
||||
// Just keep the module as is. If it has no incoming dependencies, then treat it as
|
||||
// the first-level dependency module (i.e. the module that only the source code module depends on).
|
||||
if (module.requestedVersionsByIncomingDependencies.isEmpty()) {
|
||||
module.requestedVersionsByIncomingDependencies[ResolvedDependencyId.SOURCE_CODE_MODULE_ID] = module.selectedVersion
|
||||
module.requestedVersionsByIncomingDependencies[sourceCodeModuleId] = module.selectedVersion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||
import java.util.*
|
||||
|
||||
enum class Compatibility {
|
||||
// modifier pair is compatible: ok (default)
|
||||
COMPATIBLE,
|
||||
|
||||
// second is redundant to first: warning
|
||||
REDUNDANT,
|
||||
|
||||
// first is redundant to second: warning
|
||||
REVERSE_REDUNDANT,
|
||||
|
||||
// error
|
||||
REPEATED,
|
||||
|
||||
// pair is deprecated, will become incompatible: warning
|
||||
DEPRECATED,
|
||||
|
||||
// pair is incompatible: error
|
||||
INCOMPATIBLE,
|
||||
|
||||
// same but only for functions / properties: error
|
||||
COMPATIBLE_FOR_CLASSES_ONLY
|
||||
}
|
||||
|
||||
val compatibilityTypeMap = hashMapOf<Pair<KtKeywordToken, KtKeywordToken>, Compatibility>()
|
||||
|
||||
fun compatibility(first: KtKeywordToken, second: KtKeywordToken): Compatibility {
|
||||
return if (first == second) {
|
||||
Compatibility.REPEATED
|
||||
} else {
|
||||
mutualCompatibility[Pair(first, second)] ?: Compatibility.COMPATIBLE
|
||||
}
|
||||
}
|
||||
|
||||
// First modifier in pair should be also first in declaration
|
||||
private val mutualCompatibility = buildCompatibilityMap()
|
||||
|
||||
private fun buildCompatibilityMap(): Map<Pair<KtKeywordToken, KtKeywordToken>, Compatibility> {
|
||||
val result = hashMapOf<Pair<KtKeywordToken, KtKeywordToken>, Compatibility>()
|
||||
// Variance: in + out are incompatible
|
||||
result += incompatibilityRegister(IN_KEYWORD, OUT_KEYWORD)
|
||||
// Visibilities: incompatible
|
||||
result += incompatibilityRegister(PRIVATE_KEYWORD, PROTECTED_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD)
|
||||
// Abstract + open + final + sealed: incompatible
|
||||
result += incompatibilityRegister(ABSTRACT_KEYWORD, OPEN_KEYWORD, FINAL_KEYWORD, SEALED_KEYWORD)
|
||||
// data + open, data + inner, data + abstract, data + sealed, data + inline, data + value
|
||||
result += incompatibilityRegister(DATA_KEYWORD, OPEN_KEYWORD)
|
||||
result += incompatibilityRegister(DATA_KEYWORD, INNER_KEYWORD)
|
||||
result += incompatibilityRegister(DATA_KEYWORD, ABSTRACT_KEYWORD)
|
||||
result += incompatibilityRegister(DATA_KEYWORD, SEALED_KEYWORD)
|
||||
result += incompatibilityRegister(DATA_KEYWORD, INLINE_KEYWORD)
|
||||
result += incompatibilityRegister(DATA_KEYWORD, VALUE_KEYWORD)
|
||||
// open is redundant to abstract & override
|
||||
result += redundantRegister(ABSTRACT_KEYWORD, OPEN_KEYWORD)
|
||||
// abstract is redundant to sealed
|
||||
result += redundantRegister(SEALED_KEYWORD, ABSTRACT_KEYWORD)
|
||||
|
||||
// const is incompatible with abstract, open, override
|
||||
result += incompatibilityRegister(CONST_KEYWORD, ABSTRACT_KEYWORD)
|
||||
result += incompatibilityRegister(CONST_KEYWORD, OPEN_KEYWORD)
|
||||
result += incompatibilityRegister(CONST_KEYWORD, OVERRIDE_KEYWORD)
|
||||
|
||||
// private is incompatible with override
|
||||
result += incompatibilityRegister(PRIVATE_KEYWORD, OVERRIDE_KEYWORD)
|
||||
// private is compatible with open / abstract only for classes
|
||||
result += compatibilityForClassesRegister(PRIVATE_KEYWORD, OPEN_KEYWORD)
|
||||
result += compatibilityForClassesRegister(PRIVATE_KEYWORD, ABSTRACT_KEYWORD)
|
||||
|
||||
result += incompatibilityRegister(CROSSINLINE_KEYWORD, NOINLINE_KEYWORD)
|
||||
|
||||
// 1. subclasses contained inside a sealed class can not be instantiated, because their constructors needs
|
||||
// an instance of an outer sealed (effectively abstract) class
|
||||
// 2. subclasses of a non-top-level sealed class must be declared inside the class
|
||||
// (see the KEEP https://github.com/Kotlin/KEEP/blob/master/proposals/sealed-class-inheritance.md)
|
||||
result += incompatibilityRegister(SEALED_KEYWORD, INNER_KEYWORD)
|
||||
|
||||
// header / expect / impl / actual are all incompatible
|
||||
result += incompatibilityRegister(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD, ACTUAL_KEYWORD)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun incompatibilityRegister(vararg list: KtKeywordToken): Map<Pair<KtKeywordToken, KtKeywordToken>, Compatibility> {
|
||||
return compatibilityRegister(Compatibility.INCOMPATIBLE, *list)
|
||||
}
|
||||
|
||||
private fun redundantRegister(
|
||||
sufficient: KtKeywordToken,
|
||||
redundant: KtKeywordToken
|
||||
): Map<Pair<KtKeywordToken, KtKeywordToken>, Compatibility> {
|
||||
return mapOf(
|
||||
Pair(sufficient, redundant) to Compatibility.REDUNDANT,
|
||||
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT
|
||||
)
|
||||
}
|
||||
|
||||
private fun compatibilityForClassesRegister(vararg list: KtKeywordToken) =
|
||||
compatibilityRegister(Compatibility.COMPATIBLE_FOR_CLASSES_ONLY, *list)
|
||||
|
||||
private fun compatibilityRegister(
|
||||
compatibility: Compatibility, vararg list: KtKeywordToken
|
||||
): Map<Pair<KtKeywordToken, KtKeywordToken>, Compatibility> {
|
||||
val result = hashMapOf<Pair<KtKeywordToken, KtKeywordToken>, Compatibility>()
|
||||
for (first in list) {
|
||||
for (second in list) {
|
||||
if (first != second) {
|
||||
result[Pair(first, second)] = compatibility
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
val featureDependencies = mapOf(
|
||||
SUSPEND_KEYWORD to listOf(LanguageFeature.Coroutines),
|
||||
INLINE_KEYWORD to listOf(LanguageFeature.InlineProperties, LanguageFeature.InlineClasses),
|
||||
HEADER_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
IMPL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
EXPECT_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
ACTUAL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
LATEINIT_KEYWORD to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables),
|
||||
FUN_KEYWORD to listOf(LanguageFeature.FunctionalInterfaceConversion)
|
||||
)
|
||||
|
||||
val featureDependenciesTargets = mapOf(
|
||||
LanguageFeature.InlineProperties to setOf(KotlinTarget.PROPERTY, KotlinTarget.PROPERTY_GETTER, KotlinTarget.PROPERTY_SETTER),
|
||||
LanguageFeature.LateinitLocalVariables to setOf(KotlinTarget.LOCAL_VARIABLE),
|
||||
LanguageFeature.LateinitTopLevelProperties to setOf(KotlinTarget.TOP_LEVEL_PROPERTY),
|
||||
LanguageFeature.InlineClasses to setOf(KotlinTarget.CLASS_ONLY),
|
||||
LanguageFeature.JvmInlineValueClasses to setOf(KotlinTarget.CLASS_ONLY),
|
||||
LanguageFeature.FunctionalInterfaceConversion to setOf(KotlinTarget.INTERFACE)
|
||||
)
|
||||
|
||||
val defaultVisibilityTargets: EnumSet<KotlinTarget> = EnumSet.of(
|
||||
KotlinTarget.CLASS_ONLY, KotlinTarget.OBJECT, KotlinTarget.INTERFACE, KotlinTarget.ENUM_CLASS, KotlinTarget.ANNOTATION_CLASS,
|
||||
KotlinTarget.MEMBER_FUNCTION, KotlinTarget.TOP_LEVEL_FUNCTION, KotlinTarget.PROPERTY_GETTER, KotlinTarget.PROPERTY_SETTER,
|
||||
KotlinTarget.MEMBER_PROPERTY, KotlinTarget.TOP_LEVEL_PROPERTY, KotlinTarget.CONSTRUCTOR, KotlinTarget.TYPEALIAS
|
||||
)
|
||||
|
||||
val possibleTargetMap = mapOf(
|
||||
ENUM_KEYWORD to EnumSet.of(KotlinTarget.ENUM_CLASS),
|
||||
ABSTRACT_KEYWORD to EnumSet.of(
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.LOCAL_CLASS,
|
||||
KotlinTarget.INTERFACE,
|
||||
KotlinTarget.MEMBER_PROPERTY,
|
||||
KotlinTarget.MEMBER_FUNCTION
|
||||
),
|
||||
OPEN_KEYWORD to EnumSet.of(
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.LOCAL_CLASS,
|
||||
KotlinTarget.INTERFACE,
|
||||
KotlinTarget.MEMBER_PROPERTY,
|
||||
KotlinTarget.MEMBER_FUNCTION
|
||||
),
|
||||
FINAL_KEYWORD to EnumSet.of(
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.LOCAL_CLASS,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.OBJECT,
|
||||
KotlinTarget.MEMBER_PROPERTY,
|
||||
KotlinTarget.MEMBER_FUNCTION
|
||||
),
|
||||
SEALED_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.INTERFACE),
|
||||
INNER_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY),
|
||||
OVERRIDE_KEYWORD to EnumSet.of(KotlinTarget.MEMBER_PROPERTY, KotlinTarget.MEMBER_FUNCTION),
|
||||
PRIVATE_KEYWORD to defaultVisibilityTargets,
|
||||
PUBLIC_KEYWORD to defaultVisibilityTargets,
|
||||
INTERNAL_KEYWORD to defaultVisibilityTargets,
|
||||
PROTECTED_KEYWORD to EnumSet.of(
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.OBJECT,
|
||||
KotlinTarget.INTERFACE,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.ANNOTATION_CLASS,
|
||||
KotlinTarget.MEMBER_FUNCTION,
|
||||
KotlinTarget.PROPERTY_GETTER,
|
||||
KotlinTarget.PROPERTY_SETTER,
|
||||
KotlinTarget.MEMBER_PROPERTY,
|
||||
KotlinTarget.CONSTRUCTOR,
|
||||
KotlinTarget.TYPEALIAS
|
||||
),
|
||||
IN_KEYWORD to EnumSet.of(KotlinTarget.TYPE_PARAMETER, KotlinTarget.TYPE_PROJECTION),
|
||||
OUT_KEYWORD to EnumSet.of(KotlinTarget.TYPE_PARAMETER, KotlinTarget.TYPE_PROJECTION),
|
||||
REIFIED_KEYWORD to EnumSet.of(KotlinTarget.TYPE_PARAMETER),
|
||||
VARARG_KEYWORD to EnumSet.of(KotlinTarget.VALUE_PARAMETER, KotlinTarget.PROPERTY_PARAMETER),
|
||||
COMPANION_KEYWORD to EnumSet.of(KotlinTarget.OBJECT),
|
||||
LATEINIT_KEYWORD to EnumSet.of(KotlinTarget.MEMBER_PROPERTY, KotlinTarget.TOP_LEVEL_PROPERTY, KotlinTarget.LOCAL_VARIABLE),
|
||||
DATA_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS),
|
||||
INLINE_KEYWORD to EnumSet.of(
|
||||
KotlinTarget.FUNCTION,
|
||||
KotlinTarget.PROPERTY,
|
||||
KotlinTarget.PROPERTY_GETTER,
|
||||
KotlinTarget.PROPERTY_SETTER,
|
||||
KotlinTarget.CLASS_ONLY
|
||||
),
|
||||
NOINLINE_KEYWORD to EnumSet.of(KotlinTarget.VALUE_PARAMETER),
|
||||
TAILREC_KEYWORD to EnumSet.of(KotlinTarget.FUNCTION),
|
||||
SUSPEND_KEYWORD to EnumSet.of(KotlinTarget.MEMBER_FUNCTION, KotlinTarget.TOP_LEVEL_FUNCTION, KotlinTarget.LOCAL_FUNCTION),
|
||||
EXTERNAL_KEYWORD to EnumSet.of(
|
||||
KotlinTarget.FUNCTION,
|
||||
KotlinTarget.PROPERTY,
|
||||
KotlinTarget.PROPERTY_GETTER,
|
||||
KotlinTarget.PROPERTY_SETTER,
|
||||
KotlinTarget.CLASS
|
||||
),
|
||||
ANNOTATION_KEYWORD to EnumSet.of(KotlinTarget.ANNOTATION_CLASS),
|
||||
CROSSINLINE_KEYWORD to EnumSet.of(KotlinTarget.VALUE_PARAMETER),
|
||||
CONST_KEYWORD to EnumSet.of(KotlinTarget.MEMBER_PROPERTY, KotlinTarget.TOP_LEVEL_PROPERTY),
|
||||
OPERATOR_KEYWORD to EnumSet.of(KotlinTarget.FUNCTION),
|
||||
INFIX_KEYWORD to EnumSet.of(KotlinTarget.FUNCTION),
|
||||
HEADER_KEYWORD to EnumSet.of(
|
||||
KotlinTarget.TOP_LEVEL_FUNCTION,
|
||||
KotlinTarget.TOP_LEVEL_PROPERTY,
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.OBJECT,
|
||||
KotlinTarget.INTERFACE,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.ANNOTATION_CLASS
|
||||
),
|
||||
IMPL_KEYWORD to EnumSet.of(
|
||||
KotlinTarget.TOP_LEVEL_FUNCTION,
|
||||
KotlinTarget.MEMBER_FUNCTION,
|
||||
KotlinTarget.TOP_LEVEL_PROPERTY,
|
||||
KotlinTarget.MEMBER_PROPERTY,
|
||||
KotlinTarget.CONSTRUCTOR,
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.OBJECT,
|
||||
KotlinTarget.INTERFACE,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.ANNOTATION_CLASS,
|
||||
KotlinTarget.TYPEALIAS
|
||||
),
|
||||
EXPECT_KEYWORD to EnumSet.of(
|
||||
KotlinTarget.TOP_LEVEL_FUNCTION,
|
||||
KotlinTarget.TOP_LEVEL_PROPERTY,
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.OBJECT,
|
||||
KotlinTarget.INTERFACE,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.ANNOTATION_CLASS
|
||||
),
|
||||
ACTUAL_KEYWORD to EnumSet.of(
|
||||
KotlinTarget.TOP_LEVEL_FUNCTION,
|
||||
KotlinTarget.MEMBER_FUNCTION,
|
||||
KotlinTarget.TOP_LEVEL_PROPERTY,
|
||||
KotlinTarget.MEMBER_PROPERTY,
|
||||
KotlinTarget.CONSTRUCTOR,
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.OBJECT,
|
||||
KotlinTarget.INTERFACE,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.ANNOTATION_CLASS,
|
||||
KotlinTarget.TYPEALIAS
|
||||
),
|
||||
FUN_KEYWORD to EnumSet.of(KotlinTarget.INTERFACE),
|
||||
VALUE_KEYWORD to EnumSet.of(KotlinTarget.CLASS_ONLY)
|
||||
)
|
||||
|
||||
// NOTE: deprecated targets must be possible!
|
||||
val deprecatedTargetMap = mapOf<KtKeywordToken, Set<KotlinTarget>>()
|
||||
|
||||
val deprecatedParentTargetMap = mapOf<KtKeywordToken, Set<KotlinTarget>>()
|
||||
|
||||
val deprecatedModifierMap = mapOf(
|
||||
HEADER_KEYWORD to EXPECT_KEYWORD,
|
||||
IMPL_KEYWORD to ACTUAL_KEYWORD
|
||||
)
|
||||
|
||||
// NOTE: redundant targets must be possible!
|
||||
val redundantTargetMap = mapOf<KtKeywordToken, Set<KotlinTarget>>(
|
||||
OPEN_KEYWORD to EnumSet.of(KotlinTarget.INTERFACE)
|
||||
)
|
||||
|
||||
interface TargetAllowedPredicate {
|
||||
fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings): Boolean
|
||||
}
|
||||
|
||||
fun always(target: KotlinTarget, vararg targets: KotlinTarget) = object : TargetAllowedPredicate {
|
||||
private val targetSet = EnumSet.of(target, *targets)
|
||||
|
||||
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
||||
target in targetSet
|
||||
}
|
||||
|
||||
fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) =
|
||||
object : TargetAllowedPredicate {
|
||||
private val targetSet = EnumSet.of(target, *targets)
|
||||
|
||||
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
||||
languageVersionSettings.supportsFeature(languageFeature) && target in targetSet
|
||||
}
|
||||
|
||||
fun or(p1: TargetAllowedPredicate, p2: TargetAllowedPredicate) = object : TargetAllowedPredicate {
|
||||
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
||||
p1.isAllowed(target, languageVersionSettings) ||
|
||||
p2.isAllowed(target, languageVersionSettings)
|
||||
}
|
||||
|
||||
val possibleParentTargetPredicateMap = mapOf(
|
||||
INNER_KEYWORD to or(
|
||||
always(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS, KotlinTarget.ENUM_CLASS),
|
||||
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, KotlinTarget.ENUM_ENTRY)
|
||||
),
|
||||
OVERRIDE_KEYWORD to always(
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.LOCAL_CLASS,
|
||||
KotlinTarget.OBJECT,
|
||||
KotlinTarget.OBJECT_LITERAL,
|
||||
KotlinTarget.INTERFACE,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.ENUM_ENTRY
|
||||
),
|
||||
PROTECTED_KEYWORD to always(KotlinTarget.CLASS_ONLY, KotlinTarget.LOCAL_CLASS, KotlinTarget.ENUM_CLASS, KotlinTarget.COMPANION_OBJECT),
|
||||
INTERNAL_KEYWORD to always(
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.LOCAL_CLASS,
|
||||
KotlinTarget.OBJECT,
|
||||
KotlinTarget.OBJECT_LITERAL,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.ENUM_ENTRY,
|
||||
KotlinTarget.FILE
|
||||
),
|
||||
PRIVATE_KEYWORD to always(
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.LOCAL_CLASS,
|
||||
KotlinTarget.OBJECT,
|
||||
KotlinTarget.OBJECT_LITERAL,
|
||||
KotlinTarget.INTERFACE,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.ENUM_ENTRY,
|
||||
KotlinTarget.FILE
|
||||
),
|
||||
COMPANION_KEYWORD to always(
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.INTERFACE,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.ANNOTATION_CLASS
|
||||
),
|
||||
FINAL_KEYWORD to always(
|
||||
KotlinTarget.CLASS_ONLY,
|
||||
KotlinTarget.LOCAL_CLASS,
|
||||
KotlinTarget.OBJECT,
|
||||
KotlinTarget.OBJECT_LITERAL,
|
||||
KotlinTarget.ENUM_CLASS,
|
||||
KotlinTarget.ENUM_ENTRY,
|
||||
KotlinTarget.ANNOTATION_CLASS,
|
||||
KotlinTarget.FILE
|
||||
),
|
||||
VARARG_KEYWORD to always(KotlinTarget.CONSTRUCTOR, KotlinTarget.FUNCTION, KotlinTarget.CLASS)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,400 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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;
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.*
|
||||
import java.util.*
|
||||
import org.jetbrains.kotlin.resolve.KeywordType.*
|
||||
|
||||
enum class KeywordType {
|
||||
Inner,
|
||||
Override,
|
||||
Public,
|
||||
Protected,
|
||||
Internal,
|
||||
Private,
|
||||
Companion,
|
||||
Final,
|
||||
Vararg,
|
||||
Enum,
|
||||
Abstract,
|
||||
Open,
|
||||
Sealed,
|
||||
In,
|
||||
Out,
|
||||
Reified,
|
||||
Lateinit,
|
||||
Data,
|
||||
Inline,
|
||||
Noinline,
|
||||
Tailrec,
|
||||
Suspend,
|
||||
External,
|
||||
Annotation,
|
||||
Crossinline,
|
||||
Const,
|
||||
Operator,
|
||||
Infix,
|
||||
Header,
|
||||
Impl,
|
||||
Expect,
|
||||
Actual,
|
||||
Fun,
|
||||
Value
|
||||
}
|
||||
|
||||
fun KeywordType.render(): String {
|
||||
return toString().lowercase()
|
||||
}
|
||||
|
||||
enum class Compatibility {
|
||||
// modifier pair is compatible: ok (default)
|
||||
COMPATIBLE,
|
||||
|
||||
// second is redundant to first: warning
|
||||
REDUNDANT,
|
||||
|
||||
// first is redundant to second: warning
|
||||
REVERSE_REDUNDANT,
|
||||
|
||||
// error
|
||||
REPEATED,
|
||||
|
||||
// pair is deprecated, will become incompatible: warning
|
||||
DEPRECATED,
|
||||
|
||||
// pair is incompatible: error
|
||||
INCOMPATIBLE,
|
||||
|
||||
// same but only for functions / properties: error
|
||||
COMPATIBLE_FOR_CLASSES_ONLY
|
||||
}
|
||||
|
||||
val compatibilityTypeMap = hashMapOf<Pair<KeywordType, KeywordType>, Compatibility>()
|
||||
|
||||
fun compatibility(first: KeywordType, second: KeywordType): Compatibility {
|
||||
return if (first == second) {
|
||||
Compatibility.REPEATED
|
||||
} else {
|
||||
mutualCompatibility[Pair(first, second)] ?: Compatibility.COMPATIBLE
|
||||
}
|
||||
}
|
||||
|
||||
// First modifier in pair should be also first in declaration
|
||||
private val mutualCompatibility = buildCompatibilityMap()
|
||||
|
||||
private fun buildCompatibilityMap(): Map<Pair<KeywordType, KeywordType>, Compatibility> {
|
||||
val result = hashMapOf<Pair<KeywordType, KeywordType>, Compatibility>()
|
||||
// Variance: in + out are incompatible
|
||||
result += incompatibilityRegister(In, Out)
|
||||
// Visibilities: incompatible
|
||||
result += incompatibilityRegister(Private, Protected, Public, Internal)
|
||||
// Abstract + open + final + sealed: incompatible
|
||||
result += incompatibilityRegister(Abstract, Open, Final, Sealed)
|
||||
// data + open, data + inner, data + abstract, data + sealed, data + inline, data + value
|
||||
result += incompatibilityRegister(Data, Open)
|
||||
result += incompatibilityRegister(Data, Inner)
|
||||
result += incompatibilityRegister(Data, Abstract)
|
||||
result += incompatibilityRegister(Data, Sealed)
|
||||
result += incompatibilityRegister(Data, Inline)
|
||||
result += incompatibilityRegister(Data, Value)
|
||||
// open is redundant to abstract & override
|
||||
result += redundantRegister(Abstract, Open)
|
||||
// abstract is redundant to sealed
|
||||
result += redundantRegister(Sealed, Abstract)
|
||||
|
||||
// const is incompatible with abstract, open, override
|
||||
result += incompatibilityRegister(Const, Abstract)
|
||||
result += incompatibilityRegister(Const, Open)
|
||||
result += incompatibilityRegister(Const, Override)
|
||||
|
||||
// private is incompatible with override
|
||||
result += incompatibilityRegister(Private, Override)
|
||||
// private is compatible with open / abstract only for classes
|
||||
result += compatibilityForClassesRegister(Private, Open)
|
||||
result += compatibilityForClassesRegister(Private, Abstract)
|
||||
|
||||
result += incompatibilityRegister(Crossinline, Noinline)
|
||||
|
||||
// 1. subclasses contained inside a sealed class can not be instantiated, because their constructors needs
|
||||
// an instance of an outer sealed (effectively abstract) class
|
||||
// 2. subclasses of a non-top-level sealed class must be declared inside the class
|
||||
// (see the KEEP https://github.com/Kotlin/KEEP/blob/master/proposals/sealed-class-inheritance.md)
|
||||
result += incompatibilityRegister(Sealed, Inner)
|
||||
|
||||
// header / expect / impl / actual are all incompatible
|
||||
result += incompatibilityRegister(Header, Expect, Impl, Actual)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun incompatibilityRegister(vararg list: KeywordType): Map<Pair<KeywordType, KeywordType>, Compatibility> {
|
||||
return compatibilityRegister(Compatibility.INCOMPATIBLE, *list)
|
||||
}
|
||||
|
||||
private fun redundantRegister(
|
||||
sufficient: KeywordType,
|
||||
redundant: KeywordType
|
||||
): Map<Pair<KeywordType, KeywordType>, Compatibility> {
|
||||
return mapOf(
|
||||
Pair(sufficient, redundant) to Compatibility.REDUNDANT,
|
||||
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT
|
||||
)
|
||||
}
|
||||
|
||||
private fun compatibilityForClassesRegister(vararg list: KeywordType) =
|
||||
compatibilityRegister(Compatibility.COMPATIBLE_FOR_CLASSES_ONLY, *list)
|
||||
|
||||
private fun compatibilityRegister(
|
||||
compatibility: Compatibility, vararg list: KeywordType
|
||||
): Map<Pair<KeywordType, KeywordType>, Compatibility> {
|
||||
val result = hashMapOf<Pair<KeywordType, KeywordType>, Compatibility>()
|
||||
for (first in list) {
|
||||
for (second in list) {
|
||||
if (first != second) {
|
||||
result[Pair(first, second)] = compatibility
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
val featureDependencies = mapOf(
|
||||
Suspend to listOf(LanguageFeature.Coroutines),
|
||||
Inline to listOf(LanguageFeature.InlineProperties, LanguageFeature.InlineClasses),
|
||||
Header to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
Impl to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
Expect to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
Actual to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
Lateinit to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables),
|
||||
Fun to listOf(LanguageFeature.FunctionalInterfaceConversion)
|
||||
)
|
||||
|
||||
val featureDependenciesTargets = mapOf(
|
||||
LanguageFeature.InlineProperties to setOf(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
|
||||
LanguageFeature.LateinitLocalVariables to setOf(LOCAL_VARIABLE),
|
||||
LanguageFeature.LateinitTopLevelProperties to setOf(TOP_LEVEL_PROPERTY),
|
||||
LanguageFeature.InlineClasses to setOf(CLASS_ONLY),
|
||||
LanguageFeature.JvmInlineValueClasses to setOf(CLASS_ONLY),
|
||||
LanguageFeature.FunctionalInterfaceConversion to setOf(INTERFACE)
|
||||
)
|
||||
|
||||
val defaultVisibilityTargets: EnumSet<KotlinTarget> = EnumSet.of(
|
||||
CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
||||
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
|
||||
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS
|
||||
)
|
||||
|
||||
val possibleTargetMap = mapOf(
|
||||
KeywordType.Enum to EnumSet.of(ENUM_CLASS),
|
||||
Abstract to EnumSet.of(
|
||||
CLASS_ONLY,
|
||||
LOCAL_CLASS,
|
||||
INTERFACE,
|
||||
MEMBER_PROPERTY,
|
||||
MEMBER_FUNCTION
|
||||
),
|
||||
Open to EnumSet.of(
|
||||
CLASS_ONLY,
|
||||
LOCAL_CLASS,
|
||||
INTERFACE,
|
||||
MEMBER_PROPERTY,
|
||||
MEMBER_FUNCTION
|
||||
),
|
||||
Final to EnumSet.of(
|
||||
CLASS_ONLY,
|
||||
LOCAL_CLASS,
|
||||
ENUM_CLASS,
|
||||
OBJECT,
|
||||
MEMBER_PROPERTY,
|
||||
MEMBER_FUNCTION
|
||||
),
|
||||
Sealed to EnumSet.of(CLASS_ONLY, INTERFACE),
|
||||
Inner to EnumSet.of(CLASS_ONLY),
|
||||
Override to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
Private to defaultVisibilityTargets,
|
||||
Public to defaultVisibilityTargets,
|
||||
Internal to defaultVisibilityTargets,
|
||||
Protected to EnumSet.of(
|
||||
CLASS_ONLY,
|
||||
OBJECT,
|
||||
INTERFACE,
|
||||
ENUM_CLASS,
|
||||
ANNOTATION_CLASS,
|
||||
MEMBER_FUNCTION,
|
||||
PROPERTY_GETTER,
|
||||
PROPERTY_SETTER,
|
||||
MEMBER_PROPERTY,
|
||||
CONSTRUCTOR,
|
||||
TYPEALIAS
|
||||
),
|
||||
In to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
||||
Out to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
||||
Reified to EnumSet.of(TYPE_PARAMETER),
|
||||
Vararg to EnumSet.of(VALUE_PARAMETER, PROPERTY_PARAMETER),
|
||||
KeywordType.Companion to EnumSet.of(OBJECT),
|
||||
Lateinit to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, LOCAL_VARIABLE),
|
||||
Data to EnumSet.of(CLASS_ONLY, LOCAL_CLASS),
|
||||
Inline to EnumSet.of(
|
||||
FUNCTION,
|
||||
PROPERTY,
|
||||
PROPERTY_GETTER,
|
||||
PROPERTY_SETTER,
|
||||
CLASS_ONLY
|
||||
),
|
||||
Noinline to EnumSet.of(VALUE_PARAMETER),
|
||||
Tailrec to EnumSet.of(FUNCTION),
|
||||
Suspend to EnumSet.of(MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, LOCAL_FUNCTION),
|
||||
External to EnumSet.of(
|
||||
FUNCTION,
|
||||
PROPERTY,
|
||||
PROPERTY_GETTER,
|
||||
PROPERTY_SETTER,
|
||||
CLASS
|
||||
),
|
||||
KeywordType.Annotation to EnumSet.of(ANNOTATION_CLASS), // TODO: Workaround for FIR, https://youtrack.jetbrains.com/issue/KT-48157
|
||||
Crossinline to EnumSet.of(VALUE_PARAMETER),
|
||||
Const to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
|
||||
Operator to EnumSet.of(FUNCTION),
|
||||
Infix to EnumSet.of(FUNCTION),
|
||||
Header to EnumSet.of(
|
||||
TOP_LEVEL_FUNCTION,
|
||||
TOP_LEVEL_PROPERTY,
|
||||
CLASS_ONLY,
|
||||
OBJECT,
|
||||
INTERFACE,
|
||||
ENUM_CLASS,
|
||||
ANNOTATION_CLASS
|
||||
),
|
||||
Impl to EnumSet.of(
|
||||
TOP_LEVEL_FUNCTION,
|
||||
MEMBER_FUNCTION,
|
||||
TOP_LEVEL_PROPERTY,
|
||||
MEMBER_PROPERTY,
|
||||
CONSTRUCTOR,
|
||||
CLASS_ONLY,
|
||||
OBJECT,
|
||||
INTERFACE,
|
||||
ENUM_CLASS,
|
||||
ANNOTATION_CLASS,
|
||||
TYPEALIAS
|
||||
),
|
||||
Expect to EnumSet.of(
|
||||
TOP_LEVEL_FUNCTION,
|
||||
TOP_LEVEL_PROPERTY,
|
||||
CLASS_ONLY,
|
||||
OBJECT,
|
||||
INTERFACE,
|
||||
ENUM_CLASS,
|
||||
ANNOTATION_CLASS
|
||||
),
|
||||
Actual to EnumSet.of(
|
||||
TOP_LEVEL_FUNCTION,
|
||||
MEMBER_FUNCTION,
|
||||
TOP_LEVEL_PROPERTY,
|
||||
MEMBER_PROPERTY,
|
||||
CONSTRUCTOR,
|
||||
CLASS_ONLY,
|
||||
OBJECT,
|
||||
INTERFACE,
|
||||
ENUM_CLASS,
|
||||
ANNOTATION_CLASS,
|
||||
TYPEALIAS
|
||||
),
|
||||
Fun to EnumSet.of(INTERFACE),
|
||||
Value to EnumSet.of(CLASS_ONLY)
|
||||
)
|
||||
|
||||
// NOTE: deprecated targets must be possible!
|
||||
val deprecatedTargetMap = mapOf<KeywordType, Set<KotlinTarget>>()
|
||||
|
||||
val deprecatedParentTargetMap = mapOf<KeywordType, Set<KotlinTarget>>()
|
||||
|
||||
val deprecatedModifierMap = mapOf(
|
||||
Header to Expect,
|
||||
Impl to Actual
|
||||
)
|
||||
|
||||
// NOTE: redundant targets must be possible!
|
||||
val redundantTargetMap = mapOf<KeywordType, Set<KotlinTarget>>(
|
||||
Open to EnumSet.of(INTERFACE)
|
||||
)
|
||||
|
||||
interface TargetAllowedPredicate {
|
||||
fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings): Boolean
|
||||
}
|
||||
|
||||
fun always(target: KotlinTarget, vararg targets: KotlinTarget) = object : TargetAllowedPredicate {
|
||||
private val targetSet = EnumSet.of(target, *targets)
|
||||
|
||||
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
||||
target in targetSet
|
||||
}
|
||||
|
||||
fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) =
|
||||
object : TargetAllowedPredicate {
|
||||
private val targetSet = EnumSet.of(target, *targets)
|
||||
|
||||
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
||||
languageVersionSettings.supportsFeature(languageFeature) && target in targetSet
|
||||
}
|
||||
|
||||
fun or(p1: TargetAllowedPredicate, p2: TargetAllowedPredicate) = object : TargetAllowedPredicate {
|
||||
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
||||
p1.isAllowed(target, languageVersionSettings) ||
|
||||
p2.isAllowed(target, languageVersionSettings)
|
||||
}
|
||||
|
||||
val possibleParentTargetPredicateMap = mapOf(
|
||||
Inner to or(
|
||||
always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS),
|
||||
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, ENUM_ENTRY)
|
||||
),
|
||||
Override to always(
|
||||
CLASS_ONLY,
|
||||
LOCAL_CLASS,
|
||||
OBJECT,
|
||||
OBJECT_LITERAL,
|
||||
INTERFACE,
|
||||
ENUM_CLASS,
|
||||
ENUM_ENTRY
|
||||
),
|
||||
Protected to always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, COMPANION_OBJECT),
|
||||
Internal to always(
|
||||
CLASS_ONLY,
|
||||
LOCAL_CLASS,
|
||||
OBJECT,
|
||||
OBJECT_LITERAL,
|
||||
ENUM_CLASS,
|
||||
ENUM_ENTRY,
|
||||
FILE
|
||||
),
|
||||
Private to always(
|
||||
CLASS_ONLY,
|
||||
LOCAL_CLASS,
|
||||
OBJECT,
|
||||
OBJECT_LITERAL,
|
||||
INTERFACE,
|
||||
ENUM_CLASS,
|
||||
ENUM_ENTRY,
|
||||
FILE
|
||||
),
|
||||
KeywordType.Companion to always(CLASS_ONLY, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
|
||||
Final to always(
|
||||
CLASS_ONLY,
|
||||
LOCAL_CLASS,
|
||||
OBJECT,
|
||||
OBJECT_LITERAL,
|
||||
ENUM_CLASS,
|
||||
ENUM_ENTRY,
|
||||
ANNOTATION_CLASS,
|
||||
FILE
|
||||
),
|
||||
Vararg to always(CONSTRUCTOR, FUNCTION, CLASS)
|
||||
)
|
||||
6
compiler/testData/cli/jvm/firVsClassicAnnotation.args
vendored
Normal file
6
compiler/testData/cli/jvm/firVsClassicAnnotation.args
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
$TESTDATA_DIR$/firVsClassicAnnotation.kt
|
||||
-classpath
|
||||
$TESTDATA_DIR$/firVsClassicAnnotation
|
||||
-Xuse-fir
|
||||
-d
|
||||
$TEMP_DIR$
|
||||
24
compiler/testData/cli/jvm/firVsClassicAnnotation.kt
vendored
Normal file
24
compiler/testData/cli/jvm/firVsClassicAnnotation.kt
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
// Library part (build by FE 1.0)
|
||||
|
||||
//package lib
|
||||
//
|
||||
//@Target(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD)
|
||||
//annotation class Property(
|
||||
// val description: String = "",
|
||||
// val ignore: Boolean = false,
|
||||
//
|
||||
// val externalName: String = ""
|
||||
//)
|
||||
//
|
||||
//open class LocatableRunConfigurationOptions {
|
||||
// @Property(ignore = true)
|
||||
// val isNameGenerated by lazy { false }
|
||||
//}
|
||||
|
||||
// Main part
|
||||
|
||||
package use
|
||||
|
||||
import lib.LocatableRunConfigurationOptions
|
||||
|
||||
class JvmMainMethodRunConfigurationOptions : LocatableRunConfigurationOptions()
|
||||
4
compiler/testData/cli/jvm/firVsClassicAnnotation.out
vendored
Normal file
4
compiler/testData/cli/jvm/firVsClassicAnnotation.out
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
warning: ATTENTION!
|
||||
This build uses in-dev FIR:
|
||||
-Xuse-fir
|
||||
OK
|
||||
Binary file not shown.
BIN
compiler/testData/cli/jvm/firVsClassicAnnotation/lib/LocatableRunConfigurationOptions.class
vendored
Normal file
BIN
compiler/testData/cli/jvm/firVsClassicAnnotation/lib/LocatableRunConfigurationOptions.class
vendored
Normal file
Binary file not shown.
BIN
compiler/testData/cli/jvm/firVsClassicAnnotation/lib/Property.class
vendored
Normal file
BIN
compiler/testData/cli/jvm/firVsClassicAnnotation/lib/Property.class
vendored
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user