mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-05-08 15:53:19 +00:00
Compare commits
412 Commits
push/yakov
...
rr/pdn_inl
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e80744ee08 | ||
|
|
a691ddc477 | ||
|
|
99cdb7a9cc | ||
|
|
9f9b5174cd | ||
|
|
27edf2f294 | ||
|
|
77c1dd2ddf | ||
|
|
3119e04bf8 | ||
|
|
567e6a21ab | ||
|
|
a447a7188f | ||
|
|
6e6d6fec21 | ||
|
|
b2d271a3ac | ||
|
|
8d8c4416b2 | ||
|
|
1d2599767f | ||
|
|
64de6cb305 | ||
|
|
3acb96e474 | ||
|
|
c57302abba | ||
|
|
1338675833 | ||
|
|
06001fc091 | ||
|
|
d3905fd763 | ||
|
|
3ec9599bc4 | ||
|
|
445e5122c1 | ||
|
|
ebe96ec79a | ||
|
|
a8f7bf5fbc | ||
|
|
2e3b576342 | ||
|
|
aef45f0997 | ||
|
|
d7f5015faa | ||
|
|
cd487efbe9 | ||
|
|
623b289616 | ||
|
|
58110709f3 | ||
|
|
28c473074c | ||
|
|
cd26ef2bb5 | ||
|
|
608b88996a | ||
|
|
1760befa37 | ||
|
|
81ce59cf48 | ||
|
|
e159392d22 | ||
|
|
5455800de4 | ||
|
|
747cc7d55d | ||
|
|
784273ac5b | ||
|
|
493fdbd418 | ||
|
|
8ad368e990 | ||
|
|
40d19b50c5 | ||
|
|
bfcd954dd3 | ||
|
|
b8330deefa | ||
|
|
5ec19c2417 | ||
|
|
1a1f6b0c0b | ||
|
|
017448e359 | ||
|
|
d3ddeef67f | ||
|
|
b3dbca7ea6 | ||
|
|
06ee84f809 | ||
|
|
5b9ce7e823 | ||
|
|
280c445783 | ||
|
|
bcf6202863 | ||
|
|
45d31fdba2 | ||
|
|
3bc0eaff59 | ||
|
|
0d1380c232 | ||
|
|
2ca3adbcb2 | ||
|
|
c19598c2fc | ||
|
|
9736cc162b | ||
|
|
fd92b851a2 | ||
|
|
1c678be0d3 | ||
|
|
cfc4e715e4 | ||
|
|
c1fb40a436 | ||
|
|
672b972b38 | ||
|
|
ac387b1f26 | ||
|
|
2c31d2e67d | ||
|
|
8c51c3c5c3 | ||
|
|
512a851c65 | ||
|
|
85a2a3255d | ||
|
|
cdc0f36859 | ||
|
|
33251f6d50 | ||
|
|
5873511f64 | ||
|
|
e2e0358505 | ||
|
|
1607a8231a | ||
|
|
927723c766 | ||
|
|
cc531149e5 | ||
|
|
eb94167ff2 | ||
|
|
170184dce4 | ||
|
|
206457d9ff | ||
|
|
7e04bb4bf1 | ||
|
|
766857881a | ||
|
|
2f0f88062a | ||
|
|
a28138eb72 | ||
|
|
b6c3132614 | ||
|
|
627af332b1 | ||
|
|
e6af3ff6a8 | ||
|
|
a70fc99130 | ||
|
|
22d202e657 | ||
|
|
755f847ab9 | ||
|
|
3c9dcdbbee | ||
|
|
8a812996dd | ||
|
|
1d913a6bf0 | ||
|
|
3b8cb4b00d | ||
|
|
13cf9329b2 | ||
|
|
7e71bd8f1c | ||
|
|
307de0be89 | ||
|
|
eccbf38061 | ||
|
|
fb801bdc33 | ||
|
|
54957ead5c | ||
|
|
1d2d1f9e8d | ||
|
|
afacff326d | ||
|
|
cb37a05b79 | ||
|
|
e64f7ffb98 | ||
|
|
75c76e2b57 | ||
|
|
f7f51cf38e | ||
|
|
4396482fed | ||
|
|
46a0c4be4b | ||
|
|
fba480875f | ||
|
|
edc134ef2d | ||
|
|
ba8f2e6bf3 | ||
|
|
c1afb6354b | ||
|
|
d670743a2f | ||
|
|
1b81018b69 | ||
|
|
cd99c35649 | ||
|
|
bcf6582af7 | ||
|
|
758859f198 | ||
|
|
eec5f99e35 | ||
|
|
552a012e65 | ||
|
|
3625c953ae | ||
|
|
9a39b1f4d1 | ||
|
|
c07dcb27df | ||
|
|
5485a6d6cd | ||
|
|
b1c5c10233 | ||
|
|
37d25a58e8 | ||
|
|
6c7f04ffc6 | ||
|
|
a97b4ea4ae | ||
|
|
dac4fe7507 | ||
|
|
3d81eba32b | ||
|
|
bc5a79ffcc | ||
|
|
209c0fe819 | ||
|
|
f8af127a4e | ||
|
|
89b3013294 | ||
|
|
c821aba3bd | ||
|
|
45ffe58b9c | ||
|
|
069e040af9 | ||
|
|
11902c7f8f | ||
|
|
ca7334acb9 | ||
|
|
376b420d1a | ||
|
|
e0643a4185 | ||
|
|
1599a049aa | ||
|
|
b9dd73220c | ||
|
|
1d491fdce6 | ||
|
|
684ef871ee | ||
|
|
263b876e6e | ||
|
|
c7272f6986 | ||
|
|
4726dcce40 | ||
|
|
7e2f15f532 | ||
|
|
e495c722c7 | ||
|
|
0026560bd7 | ||
|
|
f737d8002e | ||
|
|
e242ad955b | ||
|
|
b5ea811b9f | ||
|
|
20afb268d1 | ||
|
|
3d4186bdb1 | ||
|
|
e949a0d38d | ||
|
|
2574c00dd9 | ||
|
|
5a7298808e | ||
|
|
3dcee8fda8 | ||
|
|
7add820f0d | ||
|
|
398b545801 | ||
|
|
67f814c99f | ||
|
|
d174e8c3d2 | ||
|
|
9bfe502afd | ||
|
|
15648da2b4 | ||
|
|
11f70412e7 | ||
|
|
297e0a9f43 | ||
|
|
6ca87dc43f | ||
|
|
aeea7147fe | ||
|
|
28cf9898ef | ||
|
|
6cd0d81561 | ||
|
|
b1eeb1fb27 | ||
|
|
b1251c1716 | ||
|
|
4a601ebf95 | ||
|
|
74d8e16d09 | ||
|
|
a0449892b2 | ||
|
|
3d3c70141c | ||
|
|
6aed492703 | ||
|
|
bcf08e3293 | ||
|
|
d375c52830 | ||
|
|
331681b40b | ||
|
|
5db8ec6551 | ||
|
|
4ffed54f76 | ||
|
|
18bb287d3b | ||
|
|
d64cb24643 | ||
|
|
3a210f6c81 | ||
|
|
cbef031780 | ||
|
|
a4a1d35021 | ||
|
|
afd9b4935a | ||
|
|
4f15bd4817 | ||
|
|
44e1b61e6c | ||
|
|
3932acf843 | ||
|
|
0ce3dd117e | ||
|
|
0af918be4f | ||
|
|
1002d076b3 | ||
|
|
3cf4b8b108 | ||
|
|
3fc5405d57 | ||
|
|
09c31b0900 | ||
|
|
6482abc602 | ||
|
|
524189132b | ||
|
|
fe74dd2689 | ||
|
|
295638b26e | ||
|
|
1978bfcd85 | ||
|
|
a9abf3b9b6 | ||
|
|
334d518aba | ||
|
|
f815f63fc5 | ||
|
|
0c5fca31ec | ||
|
|
96cc74a752 | ||
|
|
668bb4fd71 | ||
|
|
b9decc3b30 | ||
|
|
4ad88679fd | ||
|
|
6ce2f8eb14 | ||
|
|
10efbeb0c9 | ||
|
|
7852d01da6 | ||
|
|
d41c6e900a | ||
|
|
e5ca646de4 | ||
|
|
1af1a3c84e | ||
|
|
c8cd000563 | ||
|
|
8972fc5158 | ||
|
|
78475a5d9c | ||
|
|
b10fdb919f | ||
|
|
cc56acc2c2 | ||
|
|
b150cc9537 | ||
|
|
42ea17b151 | ||
|
|
15808cb376 | ||
|
|
4f3d47eed3 | ||
|
|
0716c557fe | ||
|
|
574c607f1c | ||
|
|
9638af042d | ||
|
|
c2fc017d96 | ||
|
|
b44fd1a6fe | ||
|
|
06a8156376 | ||
|
|
3326cbd9c0 | ||
|
|
59fefb6214 | ||
|
|
af67e950c4 | ||
|
|
23392b73a9 | ||
|
|
cf20e64c61 | ||
|
|
6fe8dd1254 | ||
|
|
a9882a86c0 | ||
|
|
cd09c8ba51 | ||
|
|
1966915e92 | ||
|
|
dbdc6176f0 | ||
|
|
6dd4164f1e | ||
|
|
32426da625 | ||
|
|
06b23d5937 | ||
|
|
7b6dddf012 | ||
|
|
c3344549a8 | ||
|
|
cb92413cd8 | ||
|
|
f16b1c2d69 | ||
|
|
395b2119a1 | ||
|
|
11f951e6d1 | ||
|
|
8d27f102e7 | ||
|
|
469b3b9d02 | ||
|
|
22ccb7a943 | ||
|
|
e924ee3150 | ||
|
|
ee0b64cb29 | ||
|
|
e897c60ef1 | ||
|
|
79565da904 | ||
|
|
82a70a205b | ||
|
|
a22ef02e47 | ||
|
|
4abbac1ff1 | ||
|
|
02d8c7527e | ||
|
|
6f0bf766f2 | ||
|
|
c8386ad1c7 | ||
|
|
13b5f87f3a | ||
|
|
d7368c341e | ||
|
|
adbeda12a6 | ||
|
|
79ff02fd97 | ||
|
|
0925e1b497 | ||
|
|
29ac9b33ca | ||
|
|
5004735366 | ||
|
|
d7b10f31b4 | ||
|
|
e691de6e4c | ||
|
|
126f6eff28 | ||
|
|
8578f0beea | ||
|
|
60195114c1 | ||
|
|
4c58954967 | ||
|
|
13cb3c138a | ||
|
|
b6cb393796 | ||
|
|
cf3bd016be | ||
|
|
dc8dbad0bc | ||
|
|
7567597be6 | ||
|
|
93f9d9dacd | ||
|
|
3eaa452f9e | ||
|
|
6ab632f6ad | ||
|
|
c46a393a19 | ||
|
|
e56deb4525 | ||
|
|
b2f3485d7c | ||
|
|
dabc983f6a | ||
|
|
efce3fc2e0 | ||
|
|
46d1b63f70 | ||
|
|
38cecf8b12 | ||
|
|
29dbaa4ae1 | ||
|
|
d8b7b7b2dc | ||
|
|
4e06814bc5 | ||
|
|
015c2d1875 | ||
|
|
28344c8530 | ||
|
|
bc75a21852 | ||
|
|
4e66fd29e0 | ||
|
|
6cd3d84e74 | ||
|
|
f81f28569f | ||
|
|
d46f7738c6 | ||
|
|
d8569b6a03 | ||
|
|
af865544ff | ||
|
|
c526145a48 | ||
|
|
80140207b5 | ||
|
|
468fe4196d | ||
|
|
0eba74a9d2 | ||
|
|
f34a079699 | ||
|
|
2538caa84f | ||
|
|
ebde1e5491 | ||
|
|
fc0ae851a2 | ||
|
|
d90e3618f9 | ||
|
|
0f84525bdc | ||
|
|
9ccdffe8ad | ||
|
|
59ad7e0e04 | ||
|
|
c597ee0e34 | ||
|
|
c559adc0fb | ||
|
|
5b40f291bd | ||
|
|
d4e1ecd9d3 | ||
|
|
748a2d2e7c | ||
|
|
e9a2997f7e | ||
|
|
cea6081d36 | ||
|
|
ec4cbfef59 | ||
|
|
dcd61c292d | ||
|
|
d5e2ac0efc | ||
|
|
3c3e51c6de | ||
|
|
5291648d39 | ||
|
|
bd71fbe982 | ||
|
|
37050e0616 | ||
|
|
32b380e187 | ||
|
|
872b6b7e81 | ||
|
|
a7961a4a45 | ||
|
|
97bfc49ed6 | ||
|
|
1188d311b3 | ||
|
|
77f0bd3834 | ||
|
|
bb718f2e0b | ||
|
|
fa9f0d588d | ||
|
|
2266a348c3 | ||
|
|
42b2605c2a | ||
|
|
1a262c9c31 | ||
|
|
920d57563b | ||
|
|
cd51264940 | ||
|
|
979f5e8443 | ||
|
|
edf9f5e647 | ||
|
|
956bf22191 | ||
|
|
1654824467 | ||
|
|
73bb6d5d34 | ||
|
|
6bbfe0d503 | ||
|
|
2656c94535 | ||
|
|
ba5bd0b069 | ||
|
|
ad2fabb7cb | ||
|
|
afa8e16c25 | ||
|
|
5338705402 | ||
|
|
cbe0de6111 | ||
|
|
ca9cbf7eb7 | ||
|
|
0a5991d6e7 | ||
|
|
fb27459b2e | ||
|
|
e177cecd50 | ||
|
|
b37cdae966 | ||
|
|
84d06f35e9 | ||
|
|
7d8360f38b | ||
|
|
adc1ca76f4 | ||
|
|
bfc3f35d94 | ||
|
|
8803a69c9d | ||
|
|
922fcc4049 | ||
|
|
c7c78e0e1a | ||
|
|
6e093b0beb | ||
|
|
a525f3f357 | ||
|
|
66ddd15798 | ||
|
|
a78fcd6b64 | ||
|
|
fbbbc1c092 | ||
|
|
a783ee9ae7 | ||
|
|
0d39442a5e | ||
|
|
1c7a27ce42 | ||
|
|
e8b025f267 | ||
|
|
572f08151a | ||
|
|
02aebd6565 | ||
|
|
601465fa81 | ||
|
|
493fa1c1e3 | ||
|
|
023c775188 | ||
|
|
7dda04a1c9 | ||
|
|
44256db824 | ||
|
|
017c8d8211 | ||
|
|
0923d13d55 | ||
|
|
6c49a18770 | ||
|
|
0ac96b4973 | ||
|
|
b584fed93d | ||
|
|
adfeab1bd0 | ||
|
|
d17f984edf | ||
|
|
7c73840e4a | ||
|
|
ff9643b70e | ||
|
|
153df1dd1a | ||
|
|
db10732d6c | ||
|
|
4ae51e1d02 | ||
|
|
02d4c866ca | ||
|
|
a7e81d5154 | ||
|
|
bbd21da835 | ||
|
|
0f3f56f676 | ||
|
|
8fd2ddad12 | ||
|
|
c0949fbc18 | ||
|
|
9fdd3dc53f | ||
|
|
71def0666e | ||
|
|
afb85026c4 | ||
|
|
b264a2e5dd | ||
|
|
17bbedbc50 | ||
|
|
ca40cbede5 | ||
|
|
d43d0071a4 | ||
|
|
08a1134fff | ||
|
|
90e06bf403 | ||
|
|
a66f3d26fd | ||
|
|
ba48f80e53 | ||
|
|
b42d6a3e85 | ||
|
|
4c3fb8697b |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -12,7 +12,7 @@
|
||||
/android-studio/sdk
|
||||
out/
|
||||
/tmp
|
||||
kotlin-ide/
|
||||
/intellij
|
||||
workspace.xml
|
||||
*.versionsBackup
|
||||
/idea/testData/debugger/tinyApp/classes*
|
||||
@@ -68,3 +68,4 @@ distTmp/
|
||||
outTmp/
|
||||
/test.output
|
||||
/kotlin-native/dist
|
||||
kotlin-ide/
|
||||
|
||||
1
.idea/dictionaries/igor.xml
generated
1
.idea/dictionaries/igor.xml
generated
@@ -1,6 +1,7 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="igor">
|
||||
<words>
|
||||
<w>addr</w>
|
||||
<w>descr</w>
|
||||
<w>exprs</w>
|
||||
</words>
|
||||
|
||||
2
.idea/runConfigurations/Test__Commonizer.xml
generated
2
.idea/runConfigurations/Test__Commonizer.xml
generated
@@ -4,7 +4,7 @@
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="--tests "org.jetbrains.kotlin.gradle.CommonizerHierarchicalIT" --tests "org.jetbrains.kotlin.gradle.CommonizerIT" --tests "org.jetbrains.kotlin.commonizer.**"" />
|
||||
<option name="scriptParameters" value="--tests "org.jetbrains.kotlin.gradle.CommonizerHierarchicalIT" --tests "org.jetbrains.kotlin.gradle.CommonizerIT" --tests "org.jetbrains.kotlin.commonizer.**" --tests "org.jetbrains.kotlin.gradle.native.CocoaPodsIT.testCinteropCommonization*"" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.build.GeneratedJvmClass
|
||||
import org.jetbrains.kotlin.incremental.storage.*
|
||||
import org.jetbrains.kotlin.inline.inlineFunctionsJvmNames
|
||||
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.JvmPackagePartProto
|
||||
@@ -113,7 +114,7 @@ open class IncrementalJvmCache(
|
||||
}
|
||||
|
||||
open fun saveFileToCache(generatedClass: GeneratedJvmClass, changesCollector: ChangesCollector) {
|
||||
saveClassToCache(KotlinClassInfo(generatedClass.outputClass), generatedClass.sourceFiles, changesCollector)
|
||||
saveClassToCache(KotlinClassInfo.createFrom(generatedClass.outputClass), generatedClass.sourceFiles, changesCollector)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -612,16 +613,6 @@ class KotlinClassInfo private constructor(
|
||||
val inlineFunctionsMap: LinkedHashMap<String, Long>
|
||||
) {
|
||||
|
||||
constructor(kotlinClass: LocalFileKotlinClass) : this(
|
||||
kotlinClass.classId,
|
||||
kotlinClass.classHeader.kind,
|
||||
kotlinClass.classHeader.data,
|
||||
kotlinClass.classHeader.strings,
|
||||
kotlinClass.classHeader.multifileClassName,
|
||||
getConstantsMap(kotlinClass.fileContents),
|
||||
getInlineFunctionsMap(kotlinClass.classHeader, kotlinClass.fileContents)
|
||||
)
|
||||
|
||||
val className: JvmClassName by lazy { JvmClassName.byClassId(classId) }
|
||||
|
||||
fun scopeFqName(companion: Boolean = false) = when (classKind) {
|
||||
@@ -630,6 +621,36 @@ class KotlinClassInfo private constructor(
|
||||
}
|
||||
else -> className.packageFqName
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun createFrom(kotlinClass: LocalFileKotlinClass): KotlinClassInfo {
|
||||
return KotlinClassInfo(
|
||||
kotlinClass.classId,
|
||||
kotlinClass.classHeader.kind,
|
||||
kotlinClass.classHeader.data,
|
||||
kotlinClass.classHeader.strings,
|
||||
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. */
|
||||
fun tryCreateFrom(classContents: ByteArray): KotlinClassInfo? {
|
||||
return FileBasedKotlinClass.create(classContents) { classId, _, classHeader, _ ->
|
||||
KotlinClassInfo(
|
||||
classId,
|
||||
classHeader.kind,
|
||||
classHeader.data,
|
||||
classHeader.strings,
|
||||
classHeader.multifileClassName,
|
||||
getConstantsMap(classContents),
|
||||
getInlineFunctionsMap(classHeader, classContents)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getConstantsMap(bytes: ByteArray): LinkedHashMap<String, Any> {
|
||||
@@ -694,4 +715,4 @@ private fun getInlineFunctionsMap(header: KotlinClassHeader, bytes: ByteArray):
|
||||
}, 0)
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,13 +48,18 @@ open class LookupStorage(
|
||||
|
||||
@Volatile
|
||||
private var size: Int = 0
|
||||
private var oldSize: Int = 0
|
||||
|
||||
init {
|
||||
try {
|
||||
if (countersFile.exists()) {
|
||||
val lines = countersFile.readLines()
|
||||
size = lines[0].toInt()
|
||||
size = lines.firstOrNull()?.toIntOrNull() ?: throw IOException("$countersFile exists, but it is empty. " +
|
||||
"Counters file is corrupted")
|
||||
oldSize = size
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
throw IOException("Could not read $countersFile", e)
|
||||
}
|
||||
@@ -120,13 +125,15 @@ open class LookupStorage(
|
||||
@Synchronized
|
||||
override fun flush(memoryCachesOnly: Boolean) {
|
||||
try {
|
||||
if (size > 0) {
|
||||
if (!countersFile.exists()) {
|
||||
countersFile.parentFile.mkdirs()
|
||||
countersFile.createNewFile()
|
||||
}
|
||||
if (size != oldSize) {
|
||||
if (size > 0) {
|
||||
if (!countersFile.exists()) {
|
||||
countersFile.parentFile.mkdirs()
|
||||
countersFile.createNewFile()
|
||||
}
|
||||
|
||||
countersFile.writeText("$size\n0")
|
||||
countersFile.writeText("$size\n0")
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
super.flush(memoryCachesOnly)
|
||||
|
||||
@@ -33,15 +33,19 @@ class CachingLazyStorage<K, V>(
|
||||
private val valueExternalizer: DataExternalizer<V>
|
||||
) : LazyStorage<K, V> {
|
||||
private var storage: PersistentHashMap<K, V>? = null
|
||||
private var isStorageFileExist = true
|
||||
|
||||
private fun getStorageIfExists(): PersistentHashMap<K, V>? {
|
||||
if (storage != null) return storage
|
||||
|
||||
if (!isStorageFileExist) return null
|
||||
|
||||
if (storageFile.exists()) {
|
||||
storage = createMap()
|
||||
return storage
|
||||
}
|
||||
|
||||
isStorageFileExist = false
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.incremental.storage
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.util.io.DataExternalizer
|
||||
import com.intellij.util.io.EnumeratorStringDescriptor
|
||||
import com.intellij.util.io.IOUtil
|
||||
@@ -26,7 +27,6 @@ import org.jetbrains.kotlin.cli.common.toBooleanLenient
|
||||
import java.io.DataInput
|
||||
import java.io.DataInputStream
|
||||
import java.io.DataOutput
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@@ -162,7 +162,7 @@ object ConstantsMapExternalizer : DataExternalizer<Map<String, Any>> {
|
||||
}
|
||||
}
|
||||
|
||||
override fun read(input: DataInput): Map<String, Any>? {
|
||||
override fun read(input: DataInput): Map<String, Any> {
|
||||
val size = input.readInt()
|
||||
val map = HashMap<String, Any>(size)
|
||||
|
||||
@@ -197,15 +197,33 @@ object IntExternalizer : DataExternalizer<Int> {
|
||||
}
|
||||
}
|
||||
|
||||
object PathStringDescriptor : EnumeratorStringDescriptor() {
|
||||
override fun getHashCode(value: String) = FileUtil.pathHashCode(value)
|
||||
|
||||
override fun isEqual(val1: String, val2: String?) = FileUtil.pathsEqual(val1, val2)
|
||||
// Should be consistent with org.jetbrains.jps.incremental.storage.PathStringDescriptor for correct work of portable caches
|
||||
object PathStringDescriptor : EnumeratorStringDescriptor() {
|
||||
private const val PORTABLE_CACHES_PROPERTY = "org.jetbrains.jps.portable.caches"
|
||||
private val PORTABLE_CACHES = java.lang.Boolean.getBoolean(PORTABLE_CACHES_PROPERTY)
|
||||
|
||||
override fun getHashCode(path: String): Int {
|
||||
if (!PORTABLE_CACHES) return FileUtil.pathHashCode(path)
|
||||
// On case insensitive OS hash calculated from value converted to lower case
|
||||
return if (StringUtil.isEmpty(path)) 0 else FileUtil.toCanonicalPath(path).hashCode()
|
||||
}
|
||||
|
||||
override fun isEqual(val1: String, val2: String?): Boolean {
|
||||
if (!PORTABLE_CACHES) return FileUtil.pathsEqual(val1, val2)
|
||||
// On case insensitive OS hash calculated from path converted to lower case
|
||||
if (val1 == val2) return true
|
||||
if (val2 == null) return false
|
||||
|
||||
val path1 = FileUtil.toCanonicalPath(val1)
|
||||
val path2 = FileUtil.toCanonicalPath(val2)
|
||||
return path1 == path2
|
||||
}
|
||||
}
|
||||
|
||||
open class CollectionExternalizer<T>(
|
||||
private val elementExternalizer: DataExternalizer<T>,
|
||||
private val newCollection: () -> MutableCollection<T>
|
||||
private val elementExternalizer: DataExternalizer<T>,
|
||||
private val newCollection: () -> MutableCollection<T>
|
||||
) : DataExternalizer<Collection<T>> {
|
||||
override fun read(input: DataInput): Collection<T> {
|
||||
val result = newCollection()
|
||||
|
||||
@@ -29,7 +29,7 @@ buildscript {
|
||||
dependencies {
|
||||
bootstrapCompilerClasspath(kotlin("compiler-embeddable", bootstrapKotlinVersion))
|
||||
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.31")
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.32")
|
||||
classpath(kotlin("gradle-plugin", bootstrapKotlinVersion))
|
||||
classpath(kotlin("serialization", bootstrapKotlinVersion))
|
||||
classpath("org.jetbrains.dokka:dokka-gradle-plugin:0.9.17")
|
||||
@@ -443,6 +443,12 @@ allprojects {
|
||||
project.configureShadowJarSubstitutionInCompileClasspath()
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.compilerArgs.add("-Xlint:deprecation")
|
||||
options.compilerArgs.add("-Xlint:unchecked")
|
||||
options.compilerArgs.add("-Werror")
|
||||
}
|
||||
|
||||
val commonCompilerArgs = listOfNotNull(
|
||||
"-Xopt-in=kotlin.RequiresOptIn",
|
||||
"-progressive".takeIf { hasProperty("test.progressive.mode") }
|
||||
@@ -460,6 +466,7 @@ allprojects {
|
||||
"-Xjvm-default=compatibility",
|
||||
"-Xno-optimized-callable-references",
|
||||
"-Xno-kotlin-nothing-value-exception",
|
||||
"-Xskip-runtime-version-check",
|
||||
"-Xsuppress-deprecated-jvm-target-warning" // Remove as soon as there are no modules for JDK 1.6 & 1.7
|
||||
)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.31")
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.32")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.bootstrapKotlinVersion}")
|
||||
classpath("org.jetbrains.kotlin:kotlin-sam-with-receiver:${project.bootstrapKotlinVersion}")
|
||||
}
|
||||
@@ -143,7 +143,7 @@ java {
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib", embeddedKotlinVersion))
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.bootstrapKotlinVersion}")
|
||||
implementation("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.31")
|
||||
implementation("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.32")
|
||||
implementation("com.gradle.publish:plugin-publish-plugin:0.14.0")
|
||||
|
||||
implementation("net.rubygrapefruit:native-platform:${property("versions.native-platform")}")
|
||||
|
||||
@@ -22,5 +22,14 @@ val KotlinBuildProperties.ignoreTestFailures: Boolean get() = getBoolean("ignore
|
||||
val KotlinBuildProperties.disableWerror: Boolean
|
||||
get() = getBoolean("kotlin.build.disable.werror") || useFir || isInJpsBuildIdeaSync || getBoolean("test.progressive.mode")
|
||||
|
||||
val KotlinBuildProperties.pathToKotlinModularizedTestData: String?
|
||||
get() = getOrNull("kotlin.fir.modularized.testdata.kotlin") as? String
|
||||
|
||||
val KotlinBuildProperties.pathToIntellijModularizedTestData: String?
|
||||
get() = getOrNull("kotlin.fir.modularized.testdata.intellij") as? String
|
||||
|
||||
val KotlinBuildProperties.pathToYoutrackModularizedTestData: String?
|
||||
get() = getOrNull("kotlin.fir.modularized.testdata.youtrack") as? String
|
||||
|
||||
val KotlinBuildProperties.isObsoleteJdkOverrideEnabled: Boolean
|
||||
get() = getBoolean("kotlin.build.isObsoleteJdkOverrideEnabled", false)
|
||||
|
||||
@@ -89,4 +89,4 @@ val Project.isIdeaActive
|
||||
get() = providers.systemProperty("idea.active").forUseAtConfigurationTime().isPresent
|
||||
|
||||
val Project.intellijCommunityDir: File
|
||||
get() = rootDir.resolve("kotlin-ide/intellij/community").takeIf { it.isDirectory } ?: rootDir.resolve("kotlin-ide/intellij")
|
||||
get() = rootDir.resolve("intellij/community").takeIf { it.isDirectory } ?: rootDir.resolve("intellij")
|
||||
@@ -41,7 +41,6 @@ tasks.withType<KotlinCompile> {
|
||||
kotlinOptions.apiVersion = "1.4"
|
||||
kotlinOptions.freeCompilerArgs += listOf(
|
||||
"-Xskip-prerelease-check",
|
||||
"-Xskip-runtime-version-check",
|
||||
"-Xsuppress-version-warnings",
|
||||
"-Xuse-ir" // Needed as long as languageVersion is less than 1.5.
|
||||
)
|
||||
|
||||
@@ -171,16 +171,18 @@ fun Project.configureDefaultPublishing() {
|
||||
.all { configureRepository() }
|
||||
}
|
||||
|
||||
private fun Project.getSensitiveProperty(name: String): String? {
|
||||
return project.findProperty(name) as? String ?: System.getenv(name)
|
||||
}
|
||||
|
||||
private fun Project.configureSigning() {
|
||||
configure<SigningExtension> {
|
||||
sign(extensions.getByType<PublishingExtension>().publications) // all publications
|
||||
|
||||
val signKeyId = project.findProperty("signKeyId") as? String
|
||||
val signKeyId = project.getSensitiveProperty("signKeyId")
|
||||
if (!signKeyId.isNullOrBlank()) {
|
||||
val signKeyPrivate = project.findProperty("signKeyPrivate") as? String
|
||||
?: error("Parameter `signKeyPrivate` not found")
|
||||
val signKeyPassphrase = project.findProperty("signKeyPassphrase") as? String
|
||||
?: error("Parameter `signKeyPassphrase` not found")
|
||||
val signKeyPrivate = project.getSensitiveProperty("signKeyPrivate") ?: error("Parameter `signKeyPrivate` not found")
|
||||
val signKeyPassphrase = project.getSensitiveProperty("signKeyPassphrase") ?: error("Parameter `signKeyPassphrase` not found")
|
||||
useInMemoryPgpKeys(signKeyId, signKeyPrivate, signKeyPassphrase)
|
||||
} else {
|
||||
useGpgCmd()
|
||||
|
||||
@@ -15,7 +15,10 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||
import org.jetbrains.kotlin.codegen.CodegenTestFiles
|
||||
import org.jetbrains.kotlin.codegen.GenerationUtils
|
||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
@@ -23,11 +26,11 @@ import org.jetbrains.kotlin.test.*
|
||||
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
|
||||
import org.jetbrains.kotlin.test.model.DependencyKind
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
import org.jetbrains.kotlin.test.model.ResultingArtifact
|
||||
import org.jetbrains.kotlin.test.runners.AbstractKotlinCompilerTest
|
||||
import org.jetbrains.kotlin.test.services.*
|
||||
import org.jetbrains.kotlin.test.services.configuration.CommonEnvironmentConfigurator
|
||||
import org.jetbrains.kotlin.test.services.configuration.JvmEnvironmentConfigurator
|
||||
import org.jetbrains.kotlin.test.services.impl.BackendKindExtractorImpl
|
||||
import org.jetbrains.kotlin.test.services.impl.TemporaryDirectoryManagerImpl
|
||||
import org.jetbrains.kotlin.test.services.sourceProviders.AdditionalDiagnosticsSourceFilesProvider
|
||||
import org.jetbrains.kotlin.test.services.sourceProviders.CodegenHelpersSourceFilesProvider
|
||||
@@ -382,6 +385,7 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
|
||||
"test${testDataFile.nameWithoutExtension.replaceFirstChar(Char::uppercaseChar)}",
|
||||
emptySet()
|
||||
)
|
||||
startingArtifactFactory = { ResultingArtifact.Source() }
|
||||
}.build(testDataFile.path)
|
||||
}
|
||||
|
||||
@@ -406,7 +410,6 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
|
||||
|
||||
assertions = JUnit5Assertions
|
||||
useAdditionalService<TemporaryDirectoryManager>(::TemporaryDirectoryManagerImpl)
|
||||
useAdditionalService<BackendKindExtractor>(::BackendKindExtractorImpl)
|
||||
useSourcePreprocessor(*AbstractKotlinCompilerTest.defaultPreprocessors.toTypedArray())
|
||||
useDirectives(*AbstractKotlinCompilerTest.defaultDirectiveContainers.toTypedArray())
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
|
||||
@@ -26,7 +26,7 @@ class AccessorForConstructorDescriptor(
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
override val superCallTarget: ClassDescriptor?,
|
||||
override val accessorKind: AccessorKind
|
||||
) : AbstractAccessorForFunctionDescriptor(containingDeclaration, Name.special("<init>")),
|
||||
) : AbstractAccessorForFunctionDescriptor(containingDeclaration, SpecialNames.INIT),
|
||||
ClassConstructorDescriptor,
|
||||
AccessorForCallableDescriptor<ConstructorDescriptor> {
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.sam.JavaSingleAbstractMethodUtils;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.name.SpecialNames;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.psi.stubs.KotlinFileStub;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
@@ -298,7 +299,7 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
||||
|
||||
private String getName(ClassDescriptor classDescriptor) {
|
||||
String base = peekFromStack(nameStack);
|
||||
Name descriptorName = safeIdentifier(classDescriptor.getName());
|
||||
Name descriptorName = SpecialNames.safeIdentifier(classDescriptor.getName());
|
||||
if (DescriptorUtils.isTopLevelDeclaration(classDescriptor)) {
|
||||
return base.isEmpty() ? descriptorName.asString() : base + '/' + descriptorName;
|
||||
}
|
||||
|
||||
@@ -1288,8 +1288,8 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
|
||||
fun nextLabel(node: AbstractInsnNode?): LabelNode? {
|
||||
var current = node
|
||||
while (current != null) {
|
||||
if (current is LabelNode) return current
|
||||
current = current.next
|
||||
if (current is LabelNode) return current as LabelNode
|
||||
current = current!!.next
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -1302,6 +1302,8 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
|
||||
oldLvt += record
|
||||
}
|
||||
method.localVariables.clear()
|
||||
|
||||
val oldLvtNodeToLatestNewLvtNode = mutableMapOf<LocalVariableNode, LocalVariableNode>()
|
||||
// Skip `this` for suspend lambda
|
||||
val start = if (isForNamedFunction) 0 else 1
|
||||
for (variableIndex in start until method.maxLocals) {
|
||||
@@ -1341,33 +1343,41 @@ private fun updateLvtAccordingToLiveness(method: MethodNode, isForNamedFunction:
|
||||
val endLabel = nextLabel(insn.next)?.let { min(lvtRecord.end, it) } ?: lvtRecord.end
|
||||
// startLabel can be null in case of parameters
|
||||
@Suppress("NAME_SHADOWING") val startLabel = startLabel ?: lvtRecord.start
|
||||
val node = LocalVariableNode(lvtRecord.name, lvtRecord.desc, lvtRecord.signature, startLabel, endLabel, lvtRecord.index)
|
||||
method.localVariables.add(node)
|
||||
|
||||
// Attempt to extend existing local variable node corresponding to the record in
|
||||
// the original local variable table, if there is no back-edge
|
||||
val recordToExtend: LocalVariableNode? = oldLvtNodeToLatestNewLvtNode[lvtRecord]
|
||||
var recordExtended = false
|
||||
if (recordToExtend != null) {
|
||||
var hasBackEdgeOrStore = false
|
||||
var current: AbstractInsnNode? = recordToExtend.end
|
||||
while (current != null && current != endLabel) {
|
||||
if (current is JumpInsnNode) {
|
||||
if (method.instructions.indexOf((current as JumpInsnNode).label) < method.instructions.indexOf(current)) {
|
||||
hasBackEdgeOrStore = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (current!!.isStoreOperation() && (current as VarInsnNode).`var` == recordToExtend.index) {
|
||||
hasBackEdgeOrStore = true
|
||||
break
|
||||
}
|
||||
current = current!!.next
|
||||
}
|
||||
if (!hasBackEdgeOrStore) {
|
||||
recordToExtend.end = endLabel
|
||||
recordExtended = true
|
||||
}
|
||||
}
|
||||
if (!recordExtended) {
|
||||
val node = LocalVariableNode(lvtRecord.name, lvtRecord.desc, lvtRecord.signature, startLabel, endLabel, lvtRecord.index)
|
||||
method.localVariables.add(node)
|
||||
oldLvtNodeToLatestNewLvtNode[lvtRecord] = node
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge consequent LVT records, otherwise, atomicfu goes crazy (KT-47749)
|
||||
val toRemove = arrayListOf<LocalVariableNode>()
|
||||
val sortedLVT = method.localVariables.sortedBy { method.instructions.indexOf(it.start) }
|
||||
for (i in sortedLVT.indices) {
|
||||
var endIndex = method.instructions.indexOf(sortedLVT[i].end)
|
||||
for (j in (i + 1) until sortedLVT.size) {
|
||||
val startIndex = method.instructions.indexOf(sortedLVT[j].start)
|
||||
if (endIndex < startIndex) break
|
||||
if (endIndex != startIndex ||
|
||||
sortedLVT[i].index != sortedLVT[j].index ||
|
||||
sortedLVT[i].name != sortedLVT[j].name ||
|
||||
sortedLVT[i].desc != sortedLVT[j].desc
|
||||
) continue
|
||||
sortedLVT[i].end = sortedLVT[j].end
|
||||
endIndex = method.instructions.indexOf(sortedLVT[j].end)
|
||||
toRemove += sortedLVT[j]
|
||||
}
|
||||
}
|
||||
|
||||
method.localVariables.removeAll(toRemove)
|
||||
|
||||
for (variable in oldLvt) {
|
||||
// $continuation and $result are dead, but they are used by debugger, as well as fake inliner variables
|
||||
// For example, $continuation is used to create async stack trace
|
||||
|
||||
@@ -320,7 +320,8 @@ class AnonymousObjectTransformer(
|
||||
inliningContext.callSiteInfo.isInlineOrInsideInline,
|
||||
inliningContext.callSiteInfo.file,
|
||||
inliningContext.callSiteInfo.lineNumber
|
||||
), null
|
||||
),
|
||||
null
|
||||
).doInline(deferringVisitor, LocalVarRemapper(parameters, 0), false, mapOf())
|
||||
reifiedTypeParametersUsages?.let(result.reifiedTypeParametersUsages::mergeAll)
|
||||
deferringVisitor.visitMaxs(-1, -1)
|
||||
|
||||
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* 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.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.isMethodInsnWith
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.removeUnusedLocalVariables
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.updateMaxStack
|
||||
import org.jetbrains.kotlin.codegen.optimization.transformer.MethodTransformer
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
class InplaceArgumentsMethodTransformer : MethodTransformer() {
|
||||
override fun transform(internalClassName: String, methodNode: MethodNode) {
|
||||
val methodContext = parseMethodOrNull(methodNode)
|
||||
if (methodContext != null) {
|
||||
if (methodContext.calls.isEmpty()) return
|
||||
|
||||
collectStartToEnd(methodContext)
|
||||
collectLvtEntryInstructions(methodContext)
|
||||
collectSuspensionPoints(methodContext)
|
||||
|
||||
transformMethod(methodContext)
|
||||
updateLvtEntriesForMovedInstructions(methodContext)
|
||||
|
||||
methodNode.removeUnusedLocalVariables()
|
||||
methodNode.updateMaxStack()
|
||||
}
|
||||
stripMarkers(methodNode)
|
||||
}
|
||||
|
||||
private class MethodContext(
|
||||
val methodNode: MethodNode,
|
||||
val calls: List<CallContext>
|
||||
) {
|
||||
val startArgToEndArg = HashMap<AbstractInsnNode, AbstractInsnNode>()
|
||||
val lvtEntryForInstruction = HashMap<AbstractInsnNode, LocalVariableNode>()
|
||||
val varInstructionMoved = HashMap<AbstractInsnNode, CallContext>()
|
||||
val suspensionJumpLabels = HashSet<LabelNode>()
|
||||
}
|
||||
|
||||
private class CallContext(
|
||||
val callStartMarker: AbstractInsnNode,
|
||||
val callEndMarker: AbstractInsnNode,
|
||||
val args: List<ArgContext>,
|
||||
val calls: List<CallContext>,
|
||||
val endLabel: LabelNode
|
||||
)
|
||||
|
||||
private class ArgContext(
|
||||
val argStartMarker: AbstractInsnNode,
|
||||
val argEndMarker: AbstractInsnNode,
|
||||
val calls: List<CallContext>,
|
||||
val storeInsn: VarInsnNode
|
||||
) {
|
||||
val loadOpcode = storeInsn.opcode - Opcodes.ISTORE + Opcodes.ILOAD
|
||||
|
||||
val varIndex = storeInsn.`var`
|
||||
}
|
||||
|
||||
private fun parseMethodOrNull(methodNode: MethodNode): MethodContext? {
|
||||
// We assume that the method body structure follows this grammar:
|
||||
// METHOD ::= insn* (CALL insn*)*
|
||||
// CALL ::= callStartMarker insn* (ARG insn*)* (CALL insn*)* callEndMarker
|
||||
// ARG ::= argStartMarker insn* (CALL insn*)* argEndMarker storeInsn
|
||||
|
||||
val iter = methodNode.instructions.iterator()
|
||||
val calls = ArrayList<CallContext>()
|
||||
try {
|
||||
while (iter.hasNext()) {
|
||||
val insn = iter.next()
|
||||
when {
|
||||
insn.isInplaceCallStartMarker() ->
|
||||
calls.add(parseCall(methodNode, insn, iter))
|
||||
insn.isInplaceCallEndMarker() || insn.isInplaceArgumentStartMarker() || insn.isInplaceArgumentEndMarker() ->
|
||||
throw ParseErrorException()
|
||||
}
|
||||
}
|
||||
} catch (e: ParseErrorException) {
|
||||
return null
|
||||
}
|
||||
return MethodContext(methodNode, calls)
|
||||
}
|
||||
|
||||
private fun parseCall(methodNode: MethodNode, start: AbstractInsnNode, iter: ListIterator<AbstractInsnNode>): CallContext {
|
||||
// CALL ::= callStartMarker insn* (ARG insn*)* (CALL insn*)* callEndMarker
|
||||
val args = ArrayList<ArgContext>()
|
||||
val calls = ArrayList<CallContext>()
|
||||
while (iter.hasNext()) {
|
||||
val insn = iter.next()
|
||||
when {
|
||||
insn.isInplaceCallStartMarker() ->
|
||||
calls.add(parseCall(methodNode, insn, iter))
|
||||
insn.isInplaceCallEndMarker() -> {
|
||||
val previous = insn.previous
|
||||
val endLabel =
|
||||
if (previous.type == AbstractInsnNode.LABEL)
|
||||
previous as LabelNode
|
||||
else
|
||||
LabelNode(Label()).also {
|
||||
// Make sure each call with inplace arguments has an endLabel
|
||||
// (we need it to update LVT after transformation).
|
||||
methodNode.instructions.insertBefore(insn, it)
|
||||
}
|
||||
return CallContext(start, insn, args, calls, endLabel)
|
||||
}
|
||||
insn.isInplaceArgumentStartMarker() ->
|
||||
args.add(parseArg(methodNode, insn, iter))
|
||||
insn.isInplaceArgumentEndMarker() ->
|
||||
throw ParseErrorException()
|
||||
}
|
||||
}
|
||||
// Reached instruction list end, didn't find inplace-call-end marker
|
||||
throw ParseErrorException()
|
||||
}
|
||||
|
||||
private fun parseArg(methodNode: MethodNode, start: AbstractInsnNode, iter: ListIterator<AbstractInsnNode>): ArgContext {
|
||||
// ARG ::= argStartMarker insn* (CALL insn*)* argEndMarker storeInsn
|
||||
val calls = ArrayList<CallContext>()
|
||||
while (iter.hasNext()) {
|
||||
val insn = iter.next()
|
||||
when {
|
||||
insn.isInplaceCallStartMarker() ->
|
||||
calls.add(parseCall(methodNode, insn, iter))
|
||||
insn.isInplaceArgumentEndMarker() -> {
|
||||
val next = insn.next
|
||||
if (next is VarInsnNode && next.opcode in Opcodes.ISTORE..Opcodes.ASTORE) {
|
||||
iter.next()
|
||||
return ArgContext(start, insn, calls, next)
|
||||
} else {
|
||||
throw ParseErrorException()
|
||||
}
|
||||
}
|
||||
insn.isInplaceCallEndMarker() || insn.isInplaceArgumentStartMarker() ->
|
||||
throw ParseErrorException()
|
||||
}
|
||||
}
|
||||
// Reached instruction list end, didn't find inplace-argument-end marker
|
||||
throw ParseErrorException()
|
||||
}
|
||||
|
||||
private class ParseErrorException : RuntimeException() {
|
||||
override fun fillInStackTrace(): Throwable = this
|
||||
}
|
||||
|
||||
private fun collectStartToEnd(methodContext: MethodContext) {
|
||||
for (call in methodContext.calls) {
|
||||
collectStartToEnd(methodContext, call)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectStartToEnd(methodContext: MethodContext, callContext: CallContext) {
|
||||
for (arg in callContext.args) {
|
||||
collectStartToEnd(methodContext, arg)
|
||||
}
|
||||
for (call in callContext.calls) {
|
||||
collectStartToEnd(methodContext, call)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectStartToEnd(methodContext: MethodContext, argContext: ArgContext) {
|
||||
methodContext.startArgToEndArg[argContext.argStartMarker] = argContext.argEndMarker
|
||||
for (call in argContext.calls) {
|
||||
collectStartToEnd(methodContext, call)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectLvtEntryInstructions(methodContext: MethodContext) {
|
||||
val insnList = methodContext.methodNode.instructions
|
||||
val insnArray = insnList.toArray()
|
||||
for (lv in methodContext.methodNode.localVariables) {
|
||||
val lvStartIndex = insnList.indexOf(lv.start)
|
||||
val lvEndIndex = insnList.indexOf(lv.end)
|
||||
for (i in lvStartIndex until lvEndIndex) {
|
||||
val insn = insnArray[i]
|
||||
if (insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD || insn.opcode in Opcodes.ISTORE..Opcodes.ASTORE) {
|
||||
if ((insn as VarInsnNode).`var` == lv.index) {
|
||||
methodContext.lvtEntryForInstruction[insn] = lv
|
||||
}
|
||||
} else if (insn.opcode == Opcodes.IINC) {
|
||||
if ((insn as IincInsnNode).`var` == lv.index) {
|
||||
methodContext.lvtEntryForInstruction[insn] = lv
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectSuspensionPoints(methodContext: MethodContext) {
|
||||
val insnList = methodContext.methodNode.instructions
|
||||
var insn = insnList.first
|
||||
while (
|
||||
!insn.isMethodInsnWith(Opcodes.INVOKESTATIC) {
|
||||
owner == "kotlin/coroutines/intrinsics/IntrinsicsKt" &&
|
||||
name == "getCOROUTINE_SUSPENDED" &&
|
||||
desc == "()Ljava/lang/Object;"
|
||||
}
|
||||
) {
|
||||
insn = insn.next ?: return
|
||||
}
|
||||
|
||||
// Find a first TABLESWITCH and record its jump destinations
|
||||
while (insn != null) {
|
||||
if (insn.opcode != Opcodes.TABLESWITCH || insn.previous.opcode != Opcodes.GETFIELD) {
|
||||
insn = insn.next
|
||||
continue
|
||||
}
|
||||
val getFiendInsn = insn.previous as FieldInsnNode
|
||||
if (getFiendInsn.name != "label" || getFiendInsn.desc != "I") {
|
||||
insn = insn.next
|
||||
continue
|
||||
}
|
||||
val tableSwitchInsn = insn as TableSwitchInsnNode
|
||||
methodContext.suspensionJumpLabels.addAll(tableSwitchInsn.labels)
|
||||
methodContext.suspensionJumpLabels.add(tableSwitchInsn.dflt)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformMethod(methodContext: MethodContext) {
|
||||
for (call in methodContext.calls) {
|
||||
transformCall(methodContext, call)
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformCall(methodContext: MethodContext, callContext: CallContext) {
|
||||
// Transform nested calls
|
||||
for (arg in callContext.args) {
|
||||
for (nestedCall in arg.calls) {
|
||||
transformCall(methodContext, nestedCall)
|
||||
}
|
||||
}
|
||||
for (call in callContext.calls) {
|
||||
transformCall(methodContext, call)
|
||||
}
|
||||
|
||||
// If an inplace argument contains a non-local jump,
|
||||
// moving such argument inside inline function body can interfere with stack normalization.
|
||||
// TODO investigate complex cases
|
||||
if (callContext.args.any { it.isUnsafeToMove(methodContext) }) {
|
||||
// Do not transform such call, just strip call and argument markers.
|
||||
val insnList = methodContext.methodNode.instructions
|
||||
for (arg in callContext.args) {
|
||||
insnList.remove(arg.argStartMarker)
|
||||
insnList.remove(arg.argEndMarker)
|
||||
}
|
||||
insnList.remove(callContext.callStartMarker)
|
||||
insnList.remove(callContext.callEndMarker)
|
||||
return
|
||||
}
|
||||
|
||||
moveInplaceArgumentsFromStoresToLoads(methodContext, callContext)
|
||||
}
|
||||
|
||||
private fun ArgContext.isUnsafeToMove(methodContext: MethodContext): Boolean {
|
||||
val argInsns = InsnSequence(this.argStartMarker, this.argEndMarker)
|
||||
val localLabels = argInsns.filterTo(HashSet()) { it is LabelNode }
|
||||
return argInsns.any { insn ->
|
||||
insn in methodContext.suspensionJumpLabels ||
|
||||
insn.opcode == Opcodes.GOTO && (insn as JumpInsnNode).label !in localLabels
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveInplaceArgumentsFromStoresToLoads(methodContext: MethodContext, callContext: CallContext) {
|
||||
// Transform call
|
||||
val insnList = methodContext.methodNode.instructions
|
||||
val args = callContext.args.associateBy { it.varIndex }
|
||||
var argsProcessed = 0
|
||||
|
||||
var insn: AbstractInsnNode = callContext.callStartMarker
|
||||
while (insn != callContext.callEndMarker) {
|
||||
when {
|
||||
insn.isInplaceArgumentStartMarker() -> {
|
||||
// Skip argument body
|
||||
insn = methodContext.startArgToEndArg[insn]!!
|
||||
}
|
||||
|
||||
insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD -> {
|
||||
// Load instruction
|
||||
val loadInsn = insn as VarInsnNode
|
||||
val varIndex = loadInsn.`var`
|
||||
val arg = args[varIndex]
|
||||
|
||||
if (arg == null || arg.loadOpcode != insn.opcode) {
|
||||
// Not an argument load
|
||||
insn = insn.next
|
||||
} else {
|
||||
// For each argument within this call we have
|
||||
// <inplaceArgStartMarker>
|
||||
// <argumentBody>
|
||||
// <inplaceArgEndMarker>
|
||||
// store [arg]
|
||||
// ...
|
||||
// load [arg]
|
||||
// Replace 'load [arg]' with '<argumentBody>', drop 'store [arg]' and argument markers.
|
||||
|
||||
var argInsn = arg.argStartMarker.next
|
||||
while (argInsn != arg.argEndMarker) {
|
||||
// If a LOAD/STORE/IINC instruction was moved,
|
||||
// record it so that we can update corresponding LVT entry if needed.
|
||||
// NB it's better to do so after all transformations, so that we don't recalculate node indices.
|
||||
if (argInsn.opcode in Opcodes.ILOAD..Opcodes.ALOAD ||
|
||||
argInsn.opcode in Opcodes.ISTORE..Opcodes.ASTORE ||
|
||||
argInsn.opcode == Opcodes.IINC
|
||||
) {
|
||||
methodContext.varInstructionMoved[argInsn] = callContext
|
||||
}
|
||||
|
||||
val argInsnNext = argInsn.next
|
||||
insnList.remove(argInsn)
|
||||
insnList.insertBefore(loadInsn, argInsn)
|
||||
argInsn = argInsnNext
|
||||
}
|
||||
|
||||
// Remove argument load and corresponding argument store instructions
|
||||
insnList.remove(arg.storeInsn)
|
||||
insn = loadInsn.next
|
||||
insnList.remove(loadInsn)
|
||||
|
||||
// Replace subsequent argument loads with DUP instructions of appropriate size
|
||||
while (insn.opcode == loadInsn.opcode && (insn as VarInsnNode).`var` == varIndex) {
|
||||
if (insn.opcode == Opcodes.LLOAD || insn.opcode == Opcodes.DLOAD) {
|
||||
insnList.insertBefore(insn, InsnNode(Opcodes.DUP2))
|
||||
} else {
|
||||
insnList.insertBefore(insn, InsnNode(Opcodes.DUP))
|
||||
}
|
||||
val next = insn.next
|
||||
insnList.remove(insn)
|
||||
insn = next
|
||||
}
|
||||
|
||||
// Remove argument markers
|
||||
insnList.remove(arg.argStartMarker)
|
||||
insnList.remove(arg.argEndMarker)
|
||||
|
||||
// If there are no more inplace arguments left to process, we are done
|
||||
++argsProcessed
|
||||
if (argsProcessed >= callContext.args.size)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
else ->
|
||||
insn = insn.next
|
||||
}
|
||||
}
|
||||
|
||||
// Remove call start and call end markers
|
||||
insnList.remove(callContext.callStartMarker)
|
||||
insnList.remove(callContext.callEndMarker)
|
||||
}
|
||||
|
||||
private fun updateLvtEntriesForMovedInstructions(methodContext: MethodContext) {
|
||||
val insnList = methodContext.methodNode.instructions
|
||||
for ((insn, callContext) in methodContext.varInstructionMoved.entries) {
|
||||
// Extend local variable interval to call end label if needed
|
||||
val lv = methodContext.lvtEntryForInstruction[insn] ?: continue
|
||||
val lvEndIndex = insnList.indexOf(lv.end)
|
||||
val endLabelIndex = insnList.indexOf(callContext.endLabel)
|
||||
if (endLabelIndex > lvEndIndex) {
|
||||
lv.end = callContext.endLabel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun stripMarkers(methodNode: MethodNode) {
|
||||
var insn = methodNode.instructions.first
|
||||
while (insn != null) {
|
||||
if (insn.isInplaceCallStartMarker() ||
|
||||
insn.isInplaceCallEndMarker() ||
|
||||
insn.isInplaceArgumentStartMarker() ||
|
||||
insn.isInplaceArgumentEndMarker()
|
||||
) {
|
||||
val next = insn.next
|
||||
methodNode.instructions.remove(insn)
|
||||
insn = next
|
||||
continue
|
||||
}
|
||||
insn = insn.next
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,8 @@ import org.jetbrains.kotlin.codegen.inline.coroutines.markNoinlineLambdaIfSuspen
|
||||
import org.jetbrains.kotlin.codegen.inline.coroutines.surroundInvokesWithSuspendMarkersIfNeeded
|
||||
import org.jetbrains.kotlin.codegen.optimization.ApiVersionCallsPreprocessingMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.FixStackWithLabelNormalizationMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.ControlFlowGraph
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InsnSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.isMeaningful
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.*
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.*
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.FastStackAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
@@ -737,6 +733,7 @@ class MethodInliner(
|
||||
|
||||
private fun preprocessNodeBeforeInline(node: MethodNode, returnLabels: Map<String, Label?>) {
|
||||
try {
|
||||
InplaceArgumentsMethodTransformer().transform("fake", node)
|
||||
FixStackWithLabelNormalizationMethodTransformer().transform("fake", node)
|
||||
} catch (e: Throwable) {
|
||||
throw wrapException(e, node, "couldn't inline method call")
|
||||
@@ -747,6 +744,8 @@ class MethodInliner(
|
||||
ApiVersionCallsPreprocessingMethodTransformer(targetApiVersion).transform("fake", node)
|
||||
}
|
||||
|
||||
removeFakeVariablesInitializationIfPresent(node)
|
||||
|
||||
val frames = FastStackAnalyzer("<fake>", node, FixStackInterpreter()).analyze()
|
||||
|
||||
val localReturnsNormalizer = LocalReturnsNormalizer()
|
||||
@@ -769,6 +768,73 @@ class MethodInliner(
|
||||
localReturnsNormalizer.transform(node)
|
||||
}
|
||||
|
||||
private fun removeFakeVariablesInitializationIfPresent(node: MethodNode) {
|
||||
// Before 1.6, we generated fake variable initialization instructions
|
||||
// ICONST_0
|
||||
// ISTORE x
|
||||
// for all inline functions. Original intent was to mark inline function body for the debugger with corresponding LVT entry.
|
||||
// However, for @InlineOnly functions corresponding LVT entries were not copied (assuming that nobody is actually debugging
|
||||
// @InlineOnly functions).
|
||||
// Since 1.6, we no longer generate fake variables for @InlineOnly functions
|
||||
// Here we erase fake variable initialization for @InlineOnly functions inlined into existing bytecode (e.g., inline function
|
||||
// inside third-party library).
|
||||
// We consider a sequence of instructions 'ICONST_0; ISTORE x' a fake variable initialization if the corresponding variable 'x'
|
||||
// is not used in the bytecode (see below).
|
||||
|
||||
val insnArray = node.instructions.toArray()
|
||||
|
||||
// Very conservative variable usage check.
|
||||
// Here we look at integer variables only (this includes integral primitive types: byte, char, short, boolean).
|
||||
// Variable is considered "used" if:
|
||||
// - it's loaded with ILOAD instruction
|
||||
// - it's incremented with IINC instruction
|
||||
// - there's a local variable table entry for this variable
|
||||
val usedIntegerVar = BooleanArray(node.maxLocals)
|
||||
for (insn in insnArray) {
|
||||
if (insn.type == AbstractInsnNode.VAR_INSN && insn.opcode == Opcodes.ILOAD) {
|
||||
usedIntegerVar[(insn as VarInsnNode).`var`] = true
|
||||
} else if (insn.type == AbstractInsnNode.IINC_INSN) {
|
||||
usedIntegerVar[(insn as IincInsnNode).`var`] = true
|
||||
}
|
||||
}
|
||||
for (localVariable in node.localVariables) {
|
||||
val d0 = localVariable.desc[0]
|
||||
// byte || char || short || int || boolean
|
||||
if (d0 == 'B' || d0 == 'C' || d0 == 'S' || d0 == 'I' || d0 == 'Z') {
|
||||
usedIntegerVar[localVariable.index] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Looking for sequences of instructions:
|
||||
// p0: ICONST_0
|
||||
// p1: ISTORE x
|
||||
// p2: <label>
|
||||
// If variable 'x' is not "used" (see above), remove p0 and p1 instructions.
|
||||
var changes = false
|
||||
for (p0 in insnArray) {
|
||||
if (p0.opcode != Opcodes.ICONST_0) continue
|
||||
|
||||
val p1 = p0.next ?: break
|
||||
if (p1.opcode != Opcodes.ISTORE) continue
|
||||
|
||||
val p2 = p1.next ?: break
|
||||
if (p2.type != AbstractInsnNode.LABEL) continue
|
||||
|
||||
val varIndex = (p1 as VarInsnNode).`var`
|
||||
if (!usedIntegerVar[varIndex]) {
|
||||
changes = true
|
||||
node.instructions.remove(p0)
|
||||
node.instructions.remove(p1)
|
||||
}
|
||||
}
|
||||
|
||||
if (changes) {
|
||||
// If we removed some instructions, some TCBs could (in theory) become empty.
|
||||
// Remove empty TCBs if there are any.
|
||||
node.removeEmptyCatchBlocks()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isAnonymousClassThatMustBeRegenerated(type: Type?): Boolean {
|
||||
if (type == null || type.sort != Type.OBJECT) return false
|
||||
return inliningContext.isRegeneratedAnonymousObject(type.internalName)
|
||||
|
||||
@@ -23,13 +23,11 @@ import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.isInlineClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.isCallableMemberCompiledToJvmDefault
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import org.jetbrains.kotlin.types.expressions.LabelResolver
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* 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.codegen.inline
|
||||
|
||||
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isParameterCheckedForNull
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
|
||||
|
||||
fun canInlineArgumentsInPlace(methodNode: MethodNode): Boolean {
|
||||
// Usual inline functions are inlined in the following way:
|
||||
// <evaluate argument #1>
|
||||
// <store argument to an argument variable V1>
|
||||
// ...
|
||||
// <evaluate argument #N>
|
||||
// <store argument to an argument variable VN>
|
||||
// <inline function method body with parameter variables Pi remapped to argument variables Vi>
|
||||
// If an argument #k is already stored in a local variable W, this variable W is reused.
|
||||
// When inlining arguments in-place, we instead replace corresponding variable load instructions in the inline function method body
|
||||
// with bytecode for evaluating a given argument.
|
||||
// We can do so if such transformation keeps the evaluation order intact, possibly disregarding class initialization.
|
||||
//
|
||||
// This is true for many simple @InlineOnly functions from Kotlin standard library.
|
||||
// For example, bytecode for 'inline fun println(message: Any?)' is:
|
||||
// GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
// ALOAD 0
|
||||
// INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
|
||||
// Basic inlining for 'println("Hello, world!")' would produce (skipping labels and line numbers):
|
||||
// // evaluate arguments, storing them to local variables
|
||||
// LDC "Hello, world!"
|
||||
// ASTORE 0
|
||||
// GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
// ALOAD 0
|
||||
// INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
|
||||
// With argument "Hello, world!" inlined in-place it would be:
|
||||
// GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
|
||||
// LDC "Hello, world!"
|
||||
// INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
|
||||
// Such inlining is possible because we consider it OK to reorder 'GETSTATIC java/lang/System.out : Ljava/io/PrintStream;' instruction
|
||||
// with any argument evaluation instructions ('LDC "Hello, world!"' in this case).
|
||||
|
||||
val tcbStartLabels = methodNode.tryCatchBlocks.mapTo(HashSet()) { it.start }
|
||||
|
||||
val methodParameterTypes = Type.getArgumentTypes(methodNode.desc)
|
||||
|
||||
val jvmArgumentTypes = ArrayList<Type>(methodParameterTypes.size + 1)
|
||||
if (methodNode.access and Opcodes.ACC_STATIC == 0) {
|
||||
// Here we don't care much about the exact 'this' type,
|
||||
// it's only important to remember that variable slot #0 holds an object reference.
|
||||
jvmArgumentTypes.add(AsmTypes.OBJECT_TYPE)
|
||||
}
|
||||
jvmArgumentTypes.addAll(methodParameterTypes)
|
||||
|
||||
val argumentVarEnd = jvmArgumentTypes.sumOf { it.size }
|
||||
var expectedArgumentVar = 0
|
||||
var lastArgIndex = 0
|
||||
|
||||
var insn = methodNode.instructions.first
|
||||
|
||||
// During arguments evaluation, make sure that all arguments are loaded in expected order
|
||||
// and there are no unexpected side effects in-between.
|
||||
while (insn != null && expectedArgumentVar < argumentVarEnd) {
|
||||
// Entering a try-catch block before all arguments are loaded breaks evaluation order.
|
||||
if (insn in tcbStartLabels)
|
||||
return false
|
||||
|
||||
// Some instructions break evaluation order.
|
||||
if (insn.isProhibitedDuringArgumentsEvaluation())
|
||||
return false
|
||||
|
||||
// Allow a limited list of 'GETSTATIC <owner> <name> <desc>' instructions.
|
||||
if (insn.opcode == Opcodes.GETSTATIC) {
|
||||
val fieldInsn = insn as FieldInsnNode
|
||||
val fieldSignature = FieldSignature(fieldInsn.owner, fieldInsn.name, fieldInsn.desc)
|
||||
if (fieldSignature !in whitelistedStaticFields)
|
||||
return false
|
||||
}
|
||||
|
||||
// Writing to or incrementing an argument variable forbids in-place argument inlining.
|
||||
if (insn.opcode in Opcodes.ISTORE..Opcodes.ASTORE && (insn as VarInsnNode).`var` < argumentVarEnd)
|
||||
return false
|
||||
if (insn.opcode == Opcodes.IINC && (insn as IincInsnNode).`var` < argumentVarEnd)
|
||||
return false
|
||||
|
||||
// Analyze variable loads.
|
||||
if (insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD) {
|
||||
// Skip parameter null check: 'aload x; ldc "..."; invokestatic <check>'
|
||||
if (insn.opcode == Opcodes.ALOAD && insn.isParameterCheckedForNull()) {
|
||||
// Go directly to the instruction after 'invokestatic <check>'
|
||||
insn = insn.next.next.next
|
||||
continue
|
||||
}
|
||||
|
||||
val varInsn = insn as VarInsnNode
|
||||
val varIndex = (varInsn).`var`
|
||||
if (varIndex == expectedArgumentVar) {
|
||||
// Expected argument variable loaded.
|
||||
expectedArgumentVar += jvmArgumentTypes[lastArgIndex].size
|
||||
++lastArgIndex
|
||||
// Skip a sequence of load instructions referring to the same argument variable
|
||||
// (such sequence is present in functions like 'Array.copyOf' and can be replaced with DUP instructions).
|
||||
do {
|
||||
insn = insn.next
|
||||
} while (insn != null && insn.opcode == varInsn.opcode && (insn as VarInsnNode).`var` == varIndex)
|
||||
continue
|
||||
} else if (varIndex < argumentVarEnd) {
|
||||
// Loaded an argument variable, but not an expected one => broken evaluation order
|
||||
return false
|
||||
} else {
|
||||
// It's OK to load any non-argument variable during argument evaluation.
|
||||
insn = insn.next
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Anything else is fine.
|
||||
insn = insn.next
|
||||
}
|
||||
|
||||
// Method body is over, but not all arguments were loaded on stack.
|
||||
if (expectedArgumentVar < argumentVarEnd)
|
||||
return false
|
||||
|
||||
// After arguments evaluation make sure that argument variables are no longer accessed
|
||||
// (we are not going to store anything to those variables anyway).
|
||||
while (insn != null) {
|
||||
if (insn.opcode in Opcodes.ILOAD..Opcodes.ALOAD || insn.opcode in Opcodes.ISTORE..Opcodes.ASTORE) {
|
||||
if ((insn as VarInsnNode).`var` < argumentVarEnd)
|
||||
return false
|
||||
} else if (insn.opcode == Opcodes.IINC) {
|
||||
if ((insn as IincInsnNode).`var` < argumentVarEnd)
|
||||
return false
|
||||
}
|
||||
insn = insn.next
|
||||
}
|
||||
|
||||
// Didn't encounter anything suspicious.
|
||||
return true
|
||||
}
|
||||
|
||||
internal data class FieldSignature(
|
||||
val owner: String,
|
||||
val name: String,
|
||||
val desc: String
|
||||
)
|
||||
|
||||
private val whitelistedStaticFields: Set<FieldSignature> =
|
||||
hashSetOf(
|
||||
FieldSignature("java/lang/System", "out", "Ljava/io/PrintStream;"),
|
||||
FieldSignature("kotlin/Result", "Companion", "Lkotlin/Result\$Companion;"),
|
||||
FieldSignature("kotlin/_Assertions", "ENABLED", "Z")
|
||||
)
|
||||
|
||||
private fun AbstractInsnNode.isProhibitedDuringArgumentsEvaluation() =
|
||||
opcode in opcodeProhibitedDuringArgumentsEvaluation.indices &&
|
||||
opcodeProhibitedDuringArgumentsEvaluation[opcode]
|
||||
|
||||
private val opcodeProhibitedDuringArgumentsEvaluation = BooleanArray(256).also { a ->
|
||||
// Any kind of jump during arguments evaluation is a hazard.
|
||||
// This includes all conditional jump instructions, switch instructions, return and throw instructions.
|
||||
// Very conservative, but enough for practical cases.
|
||||
for (i in Opcodes.IFEQ..Opcodes.RETURN) a[i] = true
|
||||
a[Opcodes.IFNULL] = true
|
||||
a[Opcodes.IFNONNULL] = true
|
||||
a[Opcodes.ATHROW] = true
|
||||
|
||||
// Instruction with non-trivial side effects is a hazard.
|
||||
// NB GETSTATIC is taken care of separately.
|
||||
a[Opcodes.PUTSTATIC] = true
|
||||
a[Opcodes.PUTFIELD] = true
|
||||
a[Opcodes.INVOKEVIRTUAL] = true
|
||||
a[Opcodes.INVOKESPECIAL] = true
|
||||
a[Opcodes.INVOKESTATIC] = true
|
||||
a[Opcodes.INVOKEINTERFACE] = true
|
||||
a[Opcodes.INVOKEDYNAMIC] = true
|
||||
a[Opcodes.MONITORENTER] = true
|
||||
a[Opcodes.MONITOREXIT] = true
|
||||
|
||||
// Integer division instructions can throw exception
|
||||
a[Opcodes.IDIV] = true
|
||||
a[Opcodes.LDIV] = true
|
||||
a[Opcodes.IREM] = true
|
||||
a[Opcodes.LREM] = true
|
||||
|
||||
// CHECKCAST can throw exception
|
||||
a[Opcodes.CHECKCAST] = true
|
||||
|
||||
// Array creation can throw exception (in case of negative array size)
|
||||
a[Opcodes.NEWARRAY] = true
|
||||
a[Opcodes.ANEWARRAY] = true
|
||||
a[Opcodes.MULTIANEWARRAY] = true
|
||||
|
||||
// Array access instructions can throw exception
|
||||
for (i in Opcodes.IALOAD..Opcodes.SALOAD) a[i] = true
|
||||
for (i in Opcodes.IASTORE..Opcodes.SASTORE) a[i] = true
|
||||
}
|
||||
|
||||
|
||||
private const val MARKER_INPLACE_CALL_START = "<INPLACE-CALL-START>"
|
||||
private const val MARKER_INPLACE_ARGUMENT_START = "<INPLACE-ARGUMENT-START>"
|
||||
private const val MARKER_INPLACE_ARGUMENT_END = "<INPLACE-ARGUMENT-END>"
|
||||
private const val MARKER_INPLACE_CALL_END = "<INPLACE-CALL-END>"
|
||||
|
||||
|
||||
private fun InstructionAdapter.addMarker(name: String) {
|
||||
visitMethodInsn(Opcodes.INVOKESTATIC, INLINE_MARKER_CLASS_NAME, name, "()V", false)
|
||||
}
|
||||
|
||||
fun InstructionAdapter.addInplaceCallStartMarker() = addMarker(MARKER_INPLACE_CALL_START)
|
||||
fun InstructionAdapter.addInplaceCallEndMarker() = addMarker(MARKER_INPLACE_CALL_END)
|
||||
fun InstructionAdapter.addInplaceArgumentStartMarker() = addMarker(MARKER_INPLACE_ARGUMENT_START)
|
||||
fun InstructionAdapter.addInplaceArgumentEndMarker() = addMarker(MARKER_INPLACE_ARGUMENT_END)
|
||||
|
||||
internal fun AbstractInsnNode.isInplaceCallStartMarker() = isInlineMarker(this, MARKER_INPLACE_CALL_START)
|
||||
internal fun AbstractInsnNode.isInplaceCallEndMarker() = isInlineMarker(this, MARKER_INPLACE_CALL_END)
|
||||
internal fun AbstractInsnNode.isInplaceArgumentStartMarker() = isInlineMarker(this, MARKER_INPLACE_ARGUMENT_START)
|
||||
internal fun AbstractInsnNode.isInplaceArgumentEndMarker() = isInlineMarker(this, MARKER_INPLACE_ARGUMENT_END)
|
||||
@@ -60,7 +60,7 @@ const val INLINE_FUN_VAR_SUFFIX = "\$iv"
|
||||
internal const val FIRST_FUN_LABEL = "$$$$\$ROOT$$$$$"
|
||||
internal const val SPECIAL_TRANSFORMATION_NAME = "\$special"
|
||||
const val INLINE_TRANSFORMATION_SUFFIX = "\$inlined"
|
||||
internal const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$" + INLINE_TRANSFORMATION_SUFFIX
|
||||
internal const val INLINE_CALL_TRANSFORMATION_SUFFIX = "$$INLINE_TRANSFORMATION_SUFFIX"
|
||||
internal const val INLINE_FUN_THIS_0_SUFFIX = "\$inline_fun"
|
||||
internal const val DEFAULT_LAMBDA_FAKE_CALL = "$$\$DEFAULT_LAMBDA_FAKE_CALL$$$"
|
||||
internal const val CAPTURED_FIELD_FOLD_PREFIX = "$$$"
|
||||
@@ -68,11 +68,10 @@ internal const val CAPTURED_FIELD_FOLD_PREFIX = "$$$"
|
||||
private const val NON_LOCAL_RETURN = "$$$$\$NON_LOCAL_RETURN$$$$$"
|
||||
const val CAPTURED_FIELD_PREFIX = "$"
|
||||
private const val NON_CAPTURED_FIELD_PREFIX = "$$"
|
||||
private const val INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker"
|
||||
internal const val INLINE_MARKER_CLASS_NAME = "kotlin/jvm/internal/InlineMarker"
|
||||
private const val INLINE_MARKER_BEFORE_METHOD_NAME = "beforeInlineCall"
|
||||
private const val INLINE_MARKER_AFTER_METHOD_NAME = "afterInlineCall"
|
||||
private const val INLINE_MARKER_FINALLY_START = "finallyStart"
|
||||
|
||||
private const val INLINE_MARKER_FINALLY_END = "finallyEnd"
|
||||
private const val INLINE_MARKER_BEFORE_SUSPEND_ID = 0
|
||||
private const val INLINE_MARKER_AFTER_SUSPEND_ID = 1
|
||||
@@ -302,7 +301,7 @@ internal fun firstLabelInChain(node: LabelNode): LabelNode {
|
||||
internal fun areLabelsBeforeSameInsn(first: LabelNode, second: LabelNode): Boolean =
|
||||
firstLabelInChain(first) == firstLabelInChain(second)
|
||||
|
||||
internal val MethodNode?.nodeText: String
|
||||
val MethodNode?.nodeText: String
|
||||
get() {
|
||||
if (this == null) {
|
||||
return "Not generated"
|
||||
@@ -535,17 +534,15 @@ internal fun isInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||
return isInlineMarker(insn, null)
|
||||
}
|
||||
|
||||
private fun isInlineMarker(insn: AbstractInsnNode, name: String?): Boolean {
|
||||
if (insn !is MethodInsnNode) {
|
||||
return false
|
||||
}
|
||||
internal fun isInlineMarker(insn: AbstractInsnNode, name: String?): Boolean {
|
||||
if (insn.opcode != Opcodes.INVOKESTATIC) return false
|
||||
|
||||
return insn.getOpcode() == Opcodes.INVOKESTATIC &&
|
||||
insn.owner == INLINE_MARKER_CLASS_NAME &&
|
||||
val methodInsn = insn as MethodInsnNode
|
||||
return methodInsn.owner == INLINE_MARKER_CLASS_NAME &&
|
||||
if (name != null)
|
||||
insn.name == name
|
||||
methodInsn.name == name
|
||||
else
|
||||
insn.name == INLINE_MARKER_BEFORE_METHOD_NAME || insn.name == INLINE_MARKER_AFTER_METHOD_NAME
|
||||
methodInsn.name == INLINE_MARKER_BEFORE_METHOD_NAME || methodInsn.name == INLINE_MARKER_AFTER_METHOD_NAME
|
||||
}
|
||||
|
||||
internal fun isBeforeInlineMarker(insn: AbstractInsnNode): Boolean {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.TransformationMethodVisitor
|
||||
import org.jetbrains.kotlin.codegen.inline.InplaceArgumentsMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.PopBackwardPropagationTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.RedundantBoxingMethodTransformer
|
||||
import org.jetbrains.kotlin.codegen.optimization.boxing.StackPeepholeOptimizationsTransformer
|
||||
@@ -40,6 +41,7 @@ class OptimizationMethodVisitor(
|
||||
UninitializedStoresMethodTransformer(generationState.constructorCallNormalizationMode)
|
||||
|
||||
val normalizationMethodTransformer = CompositeMethodTransformer(
|
||||
InplaceArgumentsMethodTransformer(),
|
||||
FixStackWithLabelNormalizationMethodTransformer(),
|
||||
MethodVerifier("AFTER mandatory stack transformations", generationState)
|
||||
)
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.codegen.optimization.removeNodeGetNext
|
||||
import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsn
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.tree.*
|
||||
@@ -36,7 +35,7 @@ val AbstractInsnNode.isMeaningful: Boolean
|
||||
|
||||
val AbstractInsnNode.isBranchOrCall: Boolean
|
||||
get() =
|
||||
when(this.type) {
|
||||
when (this.type) {
|
||||
AbstractInsnNode.JUMP_INSN,
|
||||
AbstractInsnNode.TABLESWITCH_INSN,
|
||||
AbstractInsnNode.LOOKUPSWITCH_INSN,
|
||||
@@ -85,13 +84,17 @@ fun MethodNode.prepareForEmitting() {
|
||||
|
||||
current = prev
|
||||
}
|
||||
updateMaxStack()
|
||||
}
|
||||
|
||||
fun MethodNode.updateMaxStack() {
|
||||
maxStack = -1
|
||||
accept(
|
||||
MaxStackFrameSizeAndLocalsCalculator(
|
||||
Opcodes.API_VERSION, access, desc,
|
||||
object : MethodVisitor(Opcodes.API_VERSION) {
|
||||
API_VERSION, access, desc,
|
||||
object : MethodVisitor(API_VERSION) {
|
||||
override fun visitMaxs(maxStack: Int, maxLocals: Int) {
|
||||
this@prepareForEmitting.maxStack = maxStack
|
||||
this@updateMaxStack.maxStack = maxStack
|
||||
}
|
||||
})
|
||||
)
|
||||
@@ -100,10 +103,10 @@ fun MethodNode.prepareForEmitting() {
|
||||
fun MethodNode.stripOptimizationMarkers() {
|
||||
var insn = instructions.first
|
||||
while (insn != null) {
|
||||
if (isOptimizationMarker(insn)) {
|
||||
insn = instructions.removeNodeGetNext(insn)
|
||||
insn = if (isOptimizationMarker(insn)) {
|
||||
instructions.removeNodeGetNext(insn)
|
||||
} else {
|
||||
insn = insn.next
|
||||
insn.next
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,7 +126,7 @@ fun MethodNode.removeUnusedLocalVariables() {
|
||||
// Arguments are always used whether or not they are in the local variable table
|
||||
// or used by instructions.
|
||||
var argumentIndex = 0
|
||||
val isStatic = (access and Opcodes.ACC_STATIC) != 0
|
||||
val isStatic = (access and ACC_STATIC) != 0
|
||||
if (!isStatic) {
|
||||
used[argumentIndex++] = true
|
||||
}
|
||||
@@ -230,8 +233,8 @@ val AbstractInsnNode.intConstant: Int?
|
||||
|
||||
fun insnListOf(vararg insns: AbstractInsnNode) = InsnList().apply { insns.forEach { add(it) } }
|
||||
|
||||
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in Opcodes.ISTORE..Opcodes.ASTORE
|
||||
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in Opcodes.ILOAD..Opcodes.ALOAD
|
||||
fun AbstractInsnNode.isStoreOperation(): Boolean = opcode in ISTORE..ASTORE
|
||||
fun AbstractInsnNode.isLoadOperation(): Boolean = opcode in ILOAD..ALOAD
|
||||
|
||||
val AbstractInsnNode?.debugText
|
||||
get() =
|
||||
|
||||
@@ -441,7 +441,7 @@ fun MethodNode.usesLocalExceptParameterNullCheck(index: Int): Boolean =
|
||||
it is VarInsnNode && it.opcode == Opcodes.ALOAD && it.`var` == index && !it.isParameterCheckedForNull()
|
||||
}
|
||||
|
||||
internal fun AbstractInsnNode.isParameterCheckedForNull(): Boolean =
|
||||
fun AbstractInsnNode.isParameterCheckedForNull(): Boolean =
|
||||
next?.takeIf { it.opcode == Opcodes.LDC }?.next?.isCheckParameterIsNotNull() == true
|
||||
|
||||
internal fun AbstractInsnNode.isCheckParameterIsNotNull() =
|
||||
|
||||
@@ -381,6 +381,12 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
|
||||
)
|
||||
var unrestrictedBuilderInference: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(
|
||||
value = "-Xself-upper-bound-inference",
|
||||
description = "Support inferring type arguments based on only self upper bounds of the corresponding type parameters"
|
||||
)
|
||||
var selfUpperBoundInference: Boolean by FreezableVar(false)
|
||||
|
||||
open fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> {
|
||||
return HashMap<AnalysisFlag<*>, Any>().apply {
|
||||
put(AnalysisFlags.skipMetadataVersionCheck, skipMetadataVersionCheck)
|
||||
@@ -423,6 +429,10 @@ abstract class CommonCompilerArguments : CommonToolArguments() {
|
||||
put(LanguageFeature.UnrestrictedBuilderInference, LanguageFeature.State.ENABLED)
|
||||
}
|
||||
|
||||
if (selfUpperBoundInference) {
|
||||
put(LanguageFeature.TypeInferenceOnCallsWithSelfTypes, LanguageFeature.State.ENABLED)
|
||||
}
|
||||
|
||||
if (newInference) {
|
||||
put(LanguageFeature.NewInference, LanguageFeature.State.ENABLED)
|
||||
put(LanguageFeature.SamConversionPerArgument, LanguageFeature.State.ENABLED)
|
||||
|
||||
@@ -278,7 +278,7 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
val runner = """
|
||||
const wasmBinary = read(String.raw`${outputWasmFile.absoluteFile}`, 'binary');
|
||||
const wasmModule = new WebAssembly.Module(wasmBinary);
|
||||
const wasmInstance = new WebAssembly.Instance(wasmModule, { runtime, js_code });
|
||||
wasmInstance = new WebAssembly.Instance(wasmModule, { runtime, js_code });
|
||||
wasmInstance.exports.main();
|
||||
""".trimIndent()
|
||||
|
||||
|
||||
@@ -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.cli.jvm.compiler.jarfs
|
||||
|
||||
class ByteArrayCharSequence(
|
||||
private val bytes: ByteArray,
|
||||
private val start: Int = 0,
|
||||
private val end: Int = bytes.size
|
||||
) : CharSequence {
|
||||
|
||||
override fun hashCode(): Int {
|
||||
error("Do not try computing hashCode ByteArrayCharSequence")
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
error("Do not try comparing ByteArrayCharSequence")
|
||||
}
|
||||
|
||||
override val length get() = end - start
|
||||
|
||||
override fun get(index: Int): Char = bytes[index + start].toChar()
|
||||
|
||||
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
|
||||
if (startIndex == 0 && endIndex == length) return this
|
||||
return ByteArrayCharSequence(bytes, start + startIndex, start + endIndex)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
val chars = CharArray(length)
|
||||
|
||||
for (i in 0 until length) {
|
||||
chars[i] = bytes[i + start].toChar()
|
||||
}
|
||||
|
||||
return String(chars)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,26 +6,26 @@ package org.jetbrains.kotlin.cli.jvm.compiler.jarfs
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.impl.ZipHandler
|
||||
import com.intellij.util.containers.FactoryMap
|
||||
import com.intellij.util.text.ByteArrayCharSequence
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.IOException
|
||||
import java.io.RandomAccessFile
|
||||
import java.nio.channels.FileChannel
|
||||
|
||||
class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) : ZipHandler(path) {
|
||||
class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) {
|
||||
private val myRoot: VirtualFile?
|
||||
internal val file = File(path)
|
||||
|
||||
private val ourEntryMap: Map<String, ZipEntryDescription>
|
||||
private val cachedManifest: ByteArray?
|
||||
|
||||
init {
|
||||
val entries: List<ZipEntryDescription>
|
||||
RandomAccessFile(file, "r").use { randomAccessFile ->
|
||||
val mappedByteBuffer = randomAccessFile.channel.map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length())
|
||||
try {
|
||||
ourEntryMap = mappedByteBuffer.parseCentralDirectory().associateBy { it.relativePath }
|
||||
cachedManifest = ourEntryMap[MANIFEST_PATH]?.let(mappedByteBuffer::contentsToByteArray)
|
||||
entries = mappedByteBuffer.parseCentralDirectory()
|
||||
cachedManifest =
|
||||
entries.singleOrNull { StringUtil.equals(MANIFEST_PATH, it.relativePath) }
|
||||
?.let(mappedByteBuffer::contentsToByteArray)
|
||||
} finally {
|
||||
with(fileSystem) {
|
||||
mappedByteBuffer.unmapBuffer()
|
||||
@@ -33,114 +33,69 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) : ZipHandl
|
||||
}
|
||||
}
|
||||
|
||||
val entries: MutableMap<EntryInfo, FastJarVirtualFile> = HashMap()
|
||||
val entriesMap = entriesMap
|
||||
val childrenMap = FactoryMap.create<FastJarVirtualFile, MutableList<VirtualFile>> { ArrayList() }
|
||||
for (info in entriesMap.values) {
|
||||
val file = getOrCreateFile(info, entries)
|
||||
val parent = file.parent
|
||||
if (parent != null) {
|
||||
childrenMap[parent]?.add(file)
|
||||
myRoot = FastJarVirtualFile(this, "", -1, parent = null, entryDescription = null)
|
||||
|
||||
// ByteArrayCharSequence should not be used instead of String
|
||||
// because the former class does not support equals/hashCode properly
|
||||
val filesByRelativePath = HashMap<String, FastJarVirtualFile>(entries.size)
|
||||
filesByRelativePath[""] = myRoot
|
||||
|
||||
for (entryDescription in entries) {
|
||||
if (!entryDescription.isDirectory) {
|
||||
createFile(entryDescription, filesByRelativePath)
|
||||
} else {
|
||||
getOrCreateDirectory(entryDescription.relativePath, filesByRelativePath)
|
||||
}
|
||||
}
|
||||
|
||||
val rootInfo = getEntryInfo("")
|
||||
myRoot = rootInfo?.let { getOrCreateFile(it, entries) }
|
||||
|
||||
for ((key, childList) in childrenMap) {
|
||||
key.children = childList.toTypedArray()
|
||||
for (node in filesByRelativePath.values) {
|
||||
node.initChildrenArrayFromList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOrCreateFile(info: EntryInfo, entries: MutableMap<EntryInfo, FastJarVirtualFile>): FastJarVirtualFile {
|
||||
var file = entries[info]
|
||||
if (file == null) {
|
||||
val parent = info.parent
|
||||
file = FastJarVirtualFile(this, info.shortName,
|
||||
if (info.isDirectory) -1 else info.length,
|
||||
info.timestamp,
|
||||
parent?.let { getOrCreateFile(it, entries) })
|
||||
entries[info] = file
|
||||
private fun createFile(entry: ZipEntryDescription, directories: MutableMap<String, FastJarVirtualFile>): FastJarVirtualFile {
|
||||
val (parentName, shortName) = entry.relativePath.splitPath()
|
||||
|
||||
val parentFile = getOrCreateDirectory(parentName, directories)
|
||||
if ("." == shortName) {
|
||||
return parentFile
|
||||
}
|
||||
return file
|
||||
|
||||
return FastJarVirtualFile(
|
||||
this, shortName,
|
||||
if (entry.isDirectory) -1 else entry.uncompressedSize,
|
||||
parentFile,
|
||||
entry,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getOrCreateDirectory(entryName: CharSequence, directories: MutableMap<String, FastJarVirtualFile>): FastJarVirtualFile {
|
||||
return directories.getOrPut(entryName.toString()) {
|
||||
val (parentPath, shortName) = entryName.splitPath()
|
||||
val parentFile = getOrCreateDirectory(parentPath, directories)
|
||||
|
||||
FastJarVirtualFile(this, shortName, -1, parentFile, entryDescription = null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun CharSequence.splitPath(): Pair<CharSequence, CharSequence> {
|
||||
var slashIndex = this.length - 1
|
||||
|
||||
while (slashIndex >= 0 && this[slashIndex] != '/') {
|
||||
slashIndex--
|
||||
}
|
||||
|
||||
if (slashIndex == -1) return Pair("", this)
|
||||
return Pair(subSequence(0, slashIndex), subSequence(slashIndex + 1, this.length))
|
||||
}
|
||||
|
||||
fun findFileByPath(pathInJar: String): VirtualFile? {
|
||||
return myRoot?.findFileByRelativePath(pathInJar)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun createEntriesMap(): Map<String, EntryInfo> {
|
||||
val mapToEntryInfo = mutableMapOf<String, EntryInfo>()
|
||||
mapToEntryInfo[""] = EntryInfo("", true, DEFAULT_LENGTH, DEFAULT_TIMESTAMP, null)
|
||||
for (zipEntry in ourEntryMap.values) {
|
||||
getOrCreate(zipEntry, mapToEntryInfo)
|
||||
}
|
||||
|
||||
return mapToEntryInfo
|
||||
}
|
||||
|
||||
private fun getOrCreate(entry: ZipEntryDescription, map: MutableMap<String, EntryInfo>): EntryInfo {
|
||||
var isDirectory = entry.isDirectory
|
||||
var entryName = entry.relativePath
|
||||
if (StringUtil.endsWithChar(entryName, '/')) {
|
||||
entryName = entryName.substring(0, entryName.length - 1)
|
||||
isDirectory = true
|
||||
}
|
||||
if (StringUtil.startsWithChar(entryName, '/') || StringUtil.startsWithChar(entryName, '\\')) {
|
||||
entryName = entryName.substring(1)
|
||||
}
|
||||
|
||||
var info = map[entryName]
|
||||
if (info != null) return info
|
||||
|
||||
val path = splitPathAndFix(entryName)
|
||||
|
||||
val parentInfo = getOrCreateDirectory(path.first, map)
|
||||
if ("." == path.second) {
|
||||
return parentInfo
|
||||
}
|
||||
info = store(map, parentInfo, path.second, isDirectory, entry.uncompressedSize.toLong(), 0, path.third)
|
||||
return info
|
||||
}
|
||||
|
||||
private fun getOrCreateDirectory(entryName: String, map: MutableMap<String, EntryInfo>): EntryInfo {
|
||||
var info = map[entryName]
|
||||
|
||||
if (info == null) {
|
||||
val entry = ourEntryMap["$entryName/"]
|
||||
if (entry != null) {
|
||||
return getOrCreate(entry, map)
|
||||
}
|
||||
val path = splitPathAndFix(entryName)
|
||||
require(entryName != path.first) {
|
||||
"invalid entry name: '" + entryName + "' in " + this.file.absolutePath + "; after split: " + path
|
||||
}
|
||||
val parentInfo = getOrCreateDirectory(path.first, map)
|
||||
info = store(map, parentInfo, path.second, true, DEFAULT_LENGTH, DEFAULT_TIMESTAMP, path.third)
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
private fun store(
|
||||
map: MutableMap<String, EntryInfo>,
|
||||
parentInfo: EntryInfo?,
|
||||
shortName: CharSequence,
|
||||
isDirectory: Boolean,
|
||||
size: Long,
|
||||
time: Long,
|
||||
entryName: String
|
||||
): EntryInfo {
|
||||
val sequence = ByteArrayCharSequence.convertToBytesIfPossible(shortName)
|
||||
val info = EntryInfo(sequence, isDirectory, size, time, parentInfo)
|
||||
map[entryName] = info
|
||||
return info
|
||||
}
|
||||
|
||||
override fun contentsToByteArray(relativePath: String): ByteArray {
|
||||
if (relativePath == MANIFEST_PATH) return cachedManifest ?: throw FileNotFoundException("$file!/$relativePath")
|
||||
val zipEntryDescription = ourEntryMap[relativePath] ?: throw FileNotFoundException("$file!/$relativePath")
|
||||
fun contentsToByteArray(zipEntryDescription: ZipEntryDescription): ByteArray {
|
||||
val relativePath = zipEntryDescription.relativePath
|
||||
if (StringUtil.equals(relativePath, MANIFEST_PATH)) return cachedManifest ?: throw FileNotFoundException("$file!/$relativePath")
|
||||
return fileSystem.cachedOpenFileHandles[file].use {
|
||||
synchronized(it) {
|
||||
it.get().second.contentsToByteArray(zipEntryDescription)
|
||||
@@ -150,5 +105,3 @@ class FastJarHandler(val fileSystem: FastJarFileSystem, path: String) : ZipHandl
|
||||
}
|
||||
|
||||
private const val MANIFEST_PATH = "META-INF/MANIFEST.MF"
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
package org.jetbrains.kotlin.cli.jvm.compiler.jarfs
|
||||
|
||||
import com.intellij.openapi.util.Couple
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayInputStream
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
@@ -14,41 +13,48 @@ import java.io.InputStream
|
||||
import java.io.OutputStream
|
||||
|
||||
internal class FastJarVirtualFile(
|
||||
private val myHandler: FastJarHandler,
|
||||
private val myName: CharSequence,
|
||||
private val myLength: Long,
|
||||
private val myTimestamp: Long,
|
||||
parent: FastJarVirtualFile?
|
||||
private val handler: FastJarHandler,
|
||||
private val name: CharSequence,
|
||||
private val length: Int,
|
||||
private val parent: FastJarVirtualFile?,
|
||||
private val entryDescription: ZipEntryDescription?,
|
||||
) : VirtualFile() {
|
||||
private val myParent: VirtualFile? = parent
|
||||
private var myChildren = EMPTY_ARRAY
|
||||
fun setChildren(children: Array<VirtualFile>) {
|
||||
myChildren = children
|
||||
|
||||
private var myChildrenArray = EMPTY_ARRAY
|
||||
private val myChildrenList: MutableList<VirtualFile> = mutableListOf()
|
||||
|
||||
init {
|
||||
parent?.myChildrenList?.add(this)
|
||||
}
|
||||
|
||||
fun initChildrenArrayFromList() {
|
||||
myChildrenArray = myChildrenList.toTypedArray()
|
||||
myChildrenList.clear()
|
||||
}
|
||||
|
||||
override fun getName(): String {
|
||||
return myName.toString()
|
||||
return name.toString()
|
||||
}
|
||||
|
||||
override fun getNameSequence(): CharSequence {
|
||||
return myName
|
||||
return name
|
||||
}
|
||||
|
||||
override fun getFileSystem(): VirtualFileSystem {
|
||||
return myHandler.fileSystem
|
||||
return handler.fileSystem
|
||||
}
|
||||
|
||||
override fun getPath(): String {
|
||||
if (myParent == null) {
|
||||
return FileUtil.toSystemIndependentName(myHandler.file.path) + "!/"
|
||||
if (parent == null) {
|
||||
return FileUtil.toSystemIndependentName(handler.file.path) + "!/"
|
||||
}
|
||||
val parentPath = myParent.path
|
||||
val answer = StringBuilder(parentPath.length + 1 + myName.length)
|
||||
val parentPath = parent.path
|
||||
val answer = StringBuilder(parentPath.length + 1 + name.length)
|
||||
answer.append(parentPath)
|
||||
if (answer[answer.length - 1] != '/') {
|
||||
answer.append('/')
|
||||
}
|
||||
answer.append(myName)
|
||||
answer.append(name)
|
||||
return answer.toString()
|
||||
}
|
||||
|
||||
@@ -57,7 +63,7 @@ internal class FastJarVirtualFile(
|
||||
}
|
||||
|
||||
override fun isDirectory(): Boolean {
|
||||
return myLength < 0
|
||||
return length < 0
|
||||
}
|
||||
|
||||
override fun isValid(): Boolean {
|
||||
@@ -65,11 +71,11 @@ internal class FastJarVirtualFile(
|
||||
}
|
||||
|
||||
override fun getParent(): VirtualFile? {
|
||||
return myParent
|
||||
return parent
|
||||
}
|
||||
|
||||
override fun getChildren(): Array<VirtualFile> {
|
||||
return myChildren
|
||||
return myChildrenArray
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
@@ -79,21 +85,16 @@ internal class FastJarVirtualFile(
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun contentsToByteArray(): ByteArray {
|
||||
val pair: Couple<String> = FastJarFileSystem.splitPath(
|
||||
path
|
||||
)
|
||||
return myHandler.contentsToByteArray(pair.second)
|
||||
if (entryDescription == null) return EMPTY_BYTE_ARRAY
|
||||
return handler.contentsToByteArray(entryDescription)
|
||||
}
|
||||
|
||||
override fun getTimeStamp(): Long {
|
||||
return myTimestamp
|
||||
}
|
||||
override fun getTimeStamp(): Long = 0
|
||||
|
||||
override fun getLength(): Long {
|
||||
return myLength
|
||||
}
|
||||
override fun getLength(): Long = length.toLong()
|
||||
|
||||
override fun refresh(asynchronous: Boolean, recursive: Boolean, postRunnable: Runnable?) {}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun getInputStream(): InputStream {
|
||||
return BufferExposingByteArrayInputStream(contentsToByteArray())
|
||||
@@ -103,3 +104,5 @@ internal class FastJarVirtualFile(
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
private val EMPTY_BYTE_ARRAY = ByteArray(0)
|
||||
|
||||
@@ -12,12 +12,12 @@ import java.util.zip.Inflater
|
||||
|
||||
|
||||
class ZipEntryDescription(
|
||||
val relativePath: String,
|
||||
val relativePath: CharSequence,
|
||||
val compressedSize: Int,
|
||||
val uncompressedSize: Int,
|
||||
val offsetInFile: Int,
|
||||
val compressionKind: CompressionKind,
|
||||
val fileNameSize: Int
|
||||
val fileNameSize: Int,
|
||||
) {
|
||||
|
||||
enum class CompressionKind {
|
||||
@@ -62,9 +62,11 @@ fun MappedByteBuffer.contentsToByteArray(
|
||||
fun MappedByteBuffer.parseCentralDirectory(): List<ZipEntryDescription> {
|
||||
order(ByteOrder.LITTLE_ENDIAN)
|
||||
|
||||
val endOfCentralDirectoryOffset = (capacity() - END_OF_CENTRAL_DIR_SIZE downTo 0).first { offset ->
|
||||
var endOfCentralDirectoryOffset = capacity() - END_OF_CENTRAL_DIR_SIZE
|
||||
while (endOfCentralDirectoryOffset >= 0) {
|
||||
// header of "End of central directory"
|
||||
getInt(offset) == 0x06054b50
|
||||
if (getInt(endOfCentralDirectoryOffset) == 0x06054b50) break
|
||||
endOfCentralDirectoryOffset--
|
||||
}
|
||||
|
||||
val entriesNumber = getUnsignedShort(endOfCentralDirectoryOffset + 10)
|
||||
@@ -97,7 +99,11 @@ fun MappedByteBuffer.parseCentralDirectory(): List<ZipEntryDescription> {
|
||||
position(currentOffset + 46)
|
||||
get(bytesForName)
|
||||
|
||||
val name = String(bytesForName)
|
||||
val name =
|
||||
if (bytesForName.all { it >= 0 })
|
||||
ByteArrayCharSequence(bytesForName)
|
||||
else
|
||||
String(bytesForName, Charsets.UTF_8)
|
||||
|
||||
currentOffset += 46 + fileNameLength + extraLength + fileCommentLength
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.daemon.client.experimental
|
||||
|
||||
import io.ktor.network.sockets.Socket
|
||||
import io.ktor.network.sockets.*
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.async
|
||||
@@ -438,6 +438,7 @@ class KotlinCompilerClient : KotlinCompilerDaemonClient {
|
||||
.thenBy(FileAgeComparator()) { it.runFile }
|
||||
val optsCopy = daemonJVMOptions.copy()
|
||||
// if required options fit into fattest running daemon - return the daemon and required options with memory params set to actual ones in the daemon
|
||||
@Suppress("DEPRECATION") // TODO: replace with maxWithOrNull as soon as minimal version of Gradle that we support has Kotlin 1.4+.
|
||||
aliveWithMetadata.maxWith(comparator)
|
||||
?.takeIf { daemonJVMOptions memorywiseFitsInto it.jvmOptions }
|
||||
?.let {
|
||||
|
||||
@@ -359,6 +359,7 @@ object KotlinCompilerClient {
|
||||
.thenBy(FileAgeComparator()) { it.runFile }
|
||||
val optsCopy = daemonJVMOptions.copy()
|
||||
// if required options fit into fattest running daemon - return the daemon and required options with memory params set to actual ones in the daemon
|
||||
@Suppress("DEPRECATION") // TODO: replace with maxWithOrNull as soon as minimal version of Gradle that we support has Kotlin 1.4+.
|
||||
return aliveWithMetadata.maxWith(comparator)?.takeIf { daemonJVMOptions memorywiseFitsInto it.jvmOptions }?.let {
|
||||
Pair(it.daemon, optsCopy.updateMemoryUpperBounds(it.jvmOptions))
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:OptIn(ExperimentalPathApi::class)
|
||||
@file:OptIn(ExperimentalPathApi::class, DelicateCoroutinesApi::class)
|
||||
|
||||
package org.jetbrains.kotlin.daemon.experimental.integration
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.daemon.experimental.unit
|
||||
|
||||
import io.ktor.network.sockets.aSocket
|
||||
import io.ktor.util.*
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.runBlocking
|
||||
@@ -31,6 +32,7 @@ class TestServer(val serverPort: Int = 6999) {
|
||||
private val serverSocket = aSocket(selectorMgr).tcp().bind(InetSocketAddress(serverPort))
|
||||
private val log = Logger.getLogger("TestServer")
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
fun awaitClient() = GlobalScope.async {
|
||||
log.info("accepting clientSocket...")
|
||||
val client = serverSocket.accept()
|
||||
@@ -61,7 +63,7 @@ class ClientSerializationTest : KotlinIntegrationTestBase() {
|
||||
}
|
||||
}
|
||||
log.info("printed")
|
||||
var client2: T? = null
|
||||
var client2: T?
|
||||
var connected = false
|
||||
runBlocking {
|
||||
val clientAwait = testServer.awaitClient()
|
||||
|
||||
@@ -621,6 +621,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/namedArrayInAnnotation.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedClassInAnnotationArgument.kt")
|
||||
public void testNestedClassInAnnotationArgument() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/nestedClassInAnnotationArgument.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noParameterForName.kt")
|
||||
public void testNoParameterForName() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/noParameterForName.kt");
|
||||
@@ -2696,6 +2701,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/overrides/protobufExt.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sameValueParametersDifferentReceiver.kt")
|
||||
public void testSameValueParametersDifferentReceiver() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/overrides/sameValueParametersDifferentReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/overrides/simple.kt");
|
||||
@@ -3059,6 +3069,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/equalsAndIdentity.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("incorrectSmartcastToNothing.kt")
|
||||
public void testIncorrectSmartcastToNothing() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/incorrectSmartcastToNothing.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt10240.kt")
|
||||
public void testKt10240() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/kt10240.kt");
|
||||
|
||||
26
compiler/fir/analysis-tests/testData/resolve/arguments/nestedClassInAnnotationArgument.fir.txt
vendored
Normal file
26
compiler/fir/analysis-tests/testData/resolve/arguments/nestedClassInAnnotationArgument.fir.txt
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
FILE: nestedClassInAnnotationArgument.kt
|
||||
public final annotation class Ann : R|kotlin/Annotation| {
|
||||
public constructor(kClass: R|kotlin/reflect/KClass<*>|): R|Ann| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val kClass: R|kotlin/reflect/KClass<*>| = R|<local>/kClass|
|
||||
public get(): R|kotlin/reflect/KClass<*>|
|
||||
|
||||
}
|
||||
public final class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
@R|Ann|(<getClass>(Q|A.EmptyList|)) public final fun foo(): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final object EmptyList : R|kotlin/Any| {
|
||||
private constructor(): R|A.EmptyList| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
11
compiler/fir/analysis-tests/testData/resolve/arguments/nestedClassInAnnotationArgument.kt
vendored
Normal file
11
compiler/fir/analysis-tests/testData/resolve/arguments/nestedClassInAnnotationArgument.kt
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// WITH_STDLIB
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
annotation class Ann(val kClass: KClass<*>)
|
||||
|
||||
class A {
|
||||
@Ann(EmptyList::class)
|
||||
fun foo() {}
|
||||
|
||||
object EmptyList
|
||||
}
|
||||
@@ -7,7 +7,7 @@ FILE: typeAliasWithNotNullBound.kt
|
||||
}
|
||||
public final typealias MyAlias = R|Inv<out kotlin/CharSequence>|
|
||||
public final fun foo(p: R|MyAlias|): R|kotlin/Unit| {
|
||||
R|/bar|<R|kotlin/CharSequence|>(R|<local>/p|).R|kotlin/CharSequence.length|
|
||||
R|/bar|<R|CapturedType(out kotlin/CharSequence)|>(R|<local>/p|).R|kotlin/CharSequence.length|
|
||||
}
|
||||
public final fun <T : R|kotlin/Any|> bar(x: R|Inv<T>|): R|T| {
|
||||
^bar R|kotlin/TODO|()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// !DUMP_CFG
|
||||
inline fun foo(vararg x: Any) {}
|
||||
<!NOTHING_TO_INLINE!>inline<!> fun foo(vararg x: Any) {}
|
||||
|
||||
fun test(a: Any, b: Any, c: Any) {
|
||||
foo(a, { "" }, b)
|
||||
|
||||
@@ -8,17 +8,17 @@ fun test() {}
|
||||
|
||||
fun test(z: Int, c: Char) {}
|
||||
|
||||
<!REDECLARATION!>open class A {
|
||||
open class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>A<!> {
|
||||
open fun rest(s: String) {}
|
||||
|
||||
open val u = 20
|
||||
}<!>
|
||||
}
|
||||
|
||||
<!REDECLARATION!>class A {
|
||||
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>A<!> {
|
||||
|
||||
}<!>
|
||||
}
|
||||
|
||||
<!REDECLARATION!>class B : <!FINAL_SUPERTYPE, SUPERTYPE_NOT_INITIALIZED!>A<!> {
|
||||
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!> : <!FINAL_SUPERTYPE, SUPERTYPE_NOT_INITIALIZED!>A<!> {
|
||||
<!CONFLICTING_OVERLOADS!><!NOTHING_TO_OVERRIDE!>override<!> fun rest(s: String)<!> {}
|
||||
|
||||
<!CONFLICTING_OVERLOADS!>fun rest(s: String)<!> {}
|
||||
@@ -26,17 +26,17 @@ fun test(z: Int, c: Char) {}
|
||||
fun rest(l: Long) {}
|
||||
|
||||
<!NOTHING_TO_OVERRIDE!>override<!> val u = 310
|
||||
}<!>
|
||||
}
|
||||
|
||||
<!REDECLARATION!>interface B<!>
|
||||
interface <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!>
|
||||
|
||||
<!REDECLARATION!>enum class B<!>
|
||||
enum class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!>
|
||||
|
||||
<!REDECLARATION!>val u = 10<!>
|
||||
<!REDECLARATION!>val u = 20<!>
|
||||
val <!REDECLARATION!>u<!> = 10
|
||||
val <!REDECLARATION!>u<!> = 20
|
||||
|
||||
<!REDECLARATION!>typealias TA = A<!>
|
||||
<!REDECLARATION!>typealias TA = B<!>
|
||||
typealias <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>TA<!> = A
|
||||
typealias <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>TA<!> = B
|
||||
|
||||
typealias BA = A
|
||||
|
||||
@@ -52,7 +52,7 @@ fun lol(a: Array<Boolean>) {}
|
||||
|
||||
class M {
|
||||
companion <!REDECLARATION!>object<!> {}
|
||||
<!REDECLARATION!>val Companion = object : Any {}<!>
|
||||
val <!REDECLARATION!>Companion<!> = object : Any {}
|
||||
}
|
||||
|
||||
fun B.foo() {}
|
||||
|
||||
@@ -20,7 +20,7 @@ abstract class K {
|
||||
<!INCOMPATIBLE_MODIFIERS!>private<!> <!INCOMPATIBLE_MODIFIERS!>abstract<!> val i2: Int
|
||||
}
|
||||
|
||||
private open <!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER!>class L<!> : K()
|
||||
private open <!INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_ERROR!>class L<!> : K()
|
||||
private abstract class M : K()
|
||||
|
||||
class X {
|
||||
|
||||
@@ -37,7 +37,7 @@ class F(var a: Int, b: Int, closure: () -> Unit, instance: F?) {
|
||||
val a = 10
|
||||
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>
|
||||
test(<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>)
|
||||
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.<!UNRESOLVED_REFERENCE!>a<!> = 20
|
||||
<!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>.a = 20
|
||||
}, <!INSTANCE_ACCESS_BEFORE_SUPER_CALL!>this<!>) {
|
||||
this.a = 30
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ FILE: notASupertype.kt
|
||||
}
|
||||
|
||||
public final fun g(): R|kotlin/Unit| {
|
||||
this@R|/B|.super<R|kotlin/String|>.<Unresolved name: f>#()
|
||||
this@R|/B|.super<<ERROR TYPE REF: Not a super type>>.<Unresolved name: f>#()
|
||||
this@R|/B|.super<R|A|>.R|/A.f|()
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ open class A {
|
||||
|
||||
class B : <!SUPERTYPE_NOT_INITIALIZED!>A<!> {
|
||||
fun g() {
|
||||
<!NOT_A_SUPERTYPE!>super<String><!>.<!UNRESOLVED_REFERENCE!>f<!>()
|
||||
super<<!NOT_A_SUPERTYPE!>String<!>>.f()
|
||||
super<A>.f()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
sealed class A
|
||||
|
||||
<!REDECLARATION!>class B : A()<!>
|
||||
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!> : A()
|
||||
|
||||
interface C : <!INTERFACE_WITH_SUPERCLASS!>A<!>
|
||||
|
||||
@@ -30,7 +30,7 @@ sealed class P {
|
||||
|
||||
class K : P()
|
||||
|
||||
<!REDECLARATION!>object B<!> {
|
||||
object <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>B<!> {
|
||||
class I : P()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
FILE: superNotAvailable.kt
|
||||
public final fun R|kotlin/String|.f(): R|kotlin/Unit| {
|
||||
super<<ERROR TYPE REF: No super type>>@f#.<Unresolved name: compareTo>#(String())
|
||||
super<<ERROR TYPE REF: No super type>>.<Unresolved name: compareTo>#(String())
|
||||
<Super not available>#.<Unresolved name: compareTo>#(String())
|
||||
<Super not available>#.<Unresolved name: compareTo>#(String())
|
||||
}
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
super<<ERROR TYPE REF: No super type>>
|
||||
super<<ERROR TYPE REF: No super type>>.<Unresolved name: foo>#()
|
||||
super<R|kotlin/Nothing|>.<Unresolved name: foo>#()
|
||||
<Super not allowed>#
|
||||
<Super not available>#.<Unresolved name: foo>#()
|
||||
<Super not available>#.<Unresolved name: foo>#()
|
||||
}
|
||||
public final class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
fun String.f() {
|
||||
<!SUPER_NOT_AVAILABLE!>super@f<!>.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
|
||||
<!SUPER_NOT_AVAILABLE!>super<!>.<!UNRESOLVED_REFERENCE!>compareTo<!>("")
|
||||
<!SUPER_NOT_AVAILABLE!>super@f<!>.compareTo("")
|
||||
<!SUPER_NOT_AVAILABLE!>super<!>.compareTo("")
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
<!SUPER_NOT_AVAILABLE!>super<!>
|
||||
<!SUPER_NOT_AVAILABLE!>super<!>.<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.<!UNRESOLVED_REFERENCE!>foo<!>()
|
||||
<!SUPER_IS_NOT_AN_EXPRESSION!>super<!>
|
||||
<!SUPER_NOT_AVAILABLE!>super<!>.foo()
|
||||
<!SUPER_NOT_AVAILABLE!>super<Nothing><!>.foo()
|
||||
}
|
||||
|
||||
class A {
|
||||
|
||||
@@ -66,3 +66,9 @@ class Test8<S8 : Test7<S8, <!UPPER_BOUND_VIOLATED!>in Any<!>>>
|
||||
class Class<V : Any>
|
||||
typealias Alias <V1> = (Class<V1>) -> Boolean
|
||||
|
||||
/* TODO: Should not be errors. Uncomment after fixing of https://youtrack.jetbrains.com/issue/KT-48044
|
||||
abstract class Base<T : Base<T>> {}
|
||||
class DerivedOut<out O : Base<out O>> {}
|
||||
class DerivedIn<in I : Base<in I>> {}*/
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
fun x() {}
|
||||
|
||||
operator fun Int.invoke(): Foo = <!UNRESOLVED_LABEL!>this@Foo<!>
|
||||
operator fun Int.invoke(): Foo = this<!UNRESOLVED_LABEL!>@Foo<!>
|
||||
|
||||
class Foo {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!REDECLARATION!>object A<!>
|
||||
object <!REDECLARATION!>A<!>
|
||||
|
||||
<!REDECLARATION!>val A = 10<!>
|
||||
val <!REDECLARATION!>A<!> = 10
|
||||
|
||||
|
||||
fun foo() = A
|
||||
|
||||
@@ -137,7 +137,7 @@ fun main(args: Array<String?>) {
|
||||
<!ASSIGNED_VALUE_IS_NEVER_READ!>a<!> = args[0]
|
||||
} else {
|
||||
a = args.toString()
|
||||
if (a != null && a.equals("cde")) return
|
||||
if (<!SENSELESS_COMPARISON!>a != null<!> && a.equals("cde")) return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
annotation class Ann
|
||||
|
||||
<!REDECLARATION!>var x: Int
|
||||
var <!REDECLARATION!>x<!>: Int
|
||||
get() = 1
|
||||
set(@Ann private x) { }<!>
|
||||
set(@Ann private x) { }
|
||||
|
||||
|
||||
<!REDECLARATION!>var x: String = ""
|
||||
var <!REDECLARATION!>x<!>: String = ""
|
||||
set(param: <!REDUNDANT_SETTER_PARAMETER_TYPE!>String<!>) {
|
||||
field = "$param "
|
||||
}<!>
|
||||
}
|
||||
|
||||
class My {
|
||||
var y: Int = 1
|
||||
@@ -25,4 +25,4 @@ class My {
|
||||
set(param) {
|
||||
field = !param
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,15 @@ fun f() {
|
||||
LocalClass().foo = 1
|
||||
}
|
||||
|
||||
internal inline fun internal() {
|
||||
internal <!NOTHING_TO_INLINE!>inline<!> fun internal() {
|
||||
f()
|
||||
}
|
||||
|
||||
<!REDECLARATION!>class C {
|
||||
class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>C<!> {
|
||||
internal val z = object {
|
||||
fun foo() = 13
|
||||
}
|
||||
}<!>
|
||||
}
|
||||
|
||||
class Foo2<
|
||||
T1,
|
||||
@@ -26,12 +26,12 @@ class Foo2<
|
||||
internal inner class B<T,T2,>
|
||||
}
|
||||
|
||||
<!REDECLARATION!><!REDUNDANT_VISIBILITY_MODIFIER!>public<!> class C {
|
||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> class <!PACKAGE_OR_CLASSIFIER_REDECLARATION!>C<!> {
|
||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> val foo: Int = 0
|
||||
|
||||
<!REDUNDANT_VISIBILITY_MODIFIER!>public<!> fun bar() {}
|
||||
|
||||
}<!>
|
||||
}
|
||||
|
||||
open class D {
|
||||
protected open fun willRemainProtected() {
|
||||
|
||||
@@ -15,7 +15,7 @@ open class B {
|
||||
override fun foo() {
|
||||
super.foo()
|
||||
|
||||
super.<!UNRESOLVED_REFERENCE!>bar<!>() // should be ambiguity (NB: really we should have overridden bar in C)
|
||||
<!AMBIGUOUS_SUPER!>super<!>.bar() // should be ambiguity (NB: really we should have overridden bar in C)
|
||||
|
||||
super.baz() // Ok
|
||||
baz() // Ok
|
||||
|
||||
@@ -4,5 +4,5 @@ FILE: main.kt
|
||||
public final fun <D : R|A|> foo(b: R|B<D>|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun main(b: R|B<*>|): R|kotlin/Unit| {
|
||||
R|/foo|<R|ft<A, A?>|>(R|<local>/b|)
|
||||
R|/foo|<R|CapturedType(*)|>(R|<local>/b|)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ FILE: kt40131.kt
|
||||
}
|
||||
public final val <T : R|kotlin/reflect/KClass<*>|> R|T|.myJava1: R|java/lang/Class<*>|
|
||||
public get(): R|java/lang/Class<*>| {
|
||||
^ this@R|/myJava1|.R|/javaImpl|<R|kotlin/Any|>
|
||||
^ this@R|/myJava1|.R|/javaImpl|<R|CapturedType(*)|>
|
||||
}
|
||||
public final val <E : R|kotlin/Any|, T : R|kotlin/reflect/KClass<E>|> R|T|.myJava2: R|java/lang/Class<E>|
|
||||
public get(): R|java/lang/Class<E>| {
|
||||
|
||||
@@ -15,19 +15,19 @@ FILE: receiverWithCapturedType.kt
|
||||
^updateD R|<local>/d|
|
||||
}
|
||||
public final fun test_1_1(resolvedCall: R|ResolvedCall<out CallableDescriptor>|): R|kotlin/Unit| {
|
||||
R|<local>/resolvedCall|.R|/getParameterForArgument|<R|CallableDescriptor|>()
|
||||
R|<local>/resolvedCall|.R|/getParameterForArgument|<R|CapturedType(out CallableDescriptor)|>()
|
||||
}
|
||||
public final fun test_1_2(resolvedCall: R|ResolvedCall<in CallableDescriptor>|): R|kotlin/Unit| {
|
||||
R|<local>/resolvedCall|.R|/getParameterForArgument|<R|CallableDescriptor|>()
|
||||
R|<local>/resolvedCall|.R|/getParameterForArgument|<R|CapturedType(in CallableDescriptor)|>()
|
||||
}
|
||||
public final fun test_1_3(resolvedCall: R|ResolvedCall<CallableDescriptor>|): R|kotlin/Unit| {
|
||||
R|<local>/resolvedCall|.R|/getParameterForArgument|<R|CallableDescriptor|>()
|
||||
}
|
||||
public final fun test_2_1(resolvedCall: R|ResolvedCall<out CallableDescriptor>|, d: R|CallableDescriptor|): R|kotlin/Unit| {
|
||||
lval x: R|CallableDescriptor| = R|<local>/resolvedCall|.<Inapplicable(INAPPLICABLE): /updateD>#<R|CallableDescriptor|>(R|<local>/d|)
|
||||
lval x: R|CallableDescriptor| = R|<local>/resolvedCall|.<Inapplicable(INAPPLICABLE): /updateD>#<R|CapturedType(out CallableDescriptor)|>(R|<local>/d|)
|
||||
}
|
||||
public final fun test_2_2(resolvedCall: R|ResolvedCall<in CallableDescriptor>|, d: R|CallableDescriptor|): R|kotlin/Unit| {
|
||||
lval x: R|CallableDescriptor| = R|<local>/resolvedCall|.R|/updateD|<R|CallableDescriptor|>(R|<local>/d|)
|
||||
lval x: R|CallableDescriptor| = R|<local>/resolvedCall|.R|/updateD|<R|CapturedType(in CallableDescriptor)|>(R|<local>/d|)
|
||||
}
|
||||
public final fun test_2_3(resolvedCall: R|ResolvedCall<CallableDescriptor>|, d: R|CallableDescriptor|): R|kotlin/Unit| {
|
||||
lval x: R|CallableDescriptor| = R|<local>/resolvedCall|.R|/updateD|<R|CallableDescriptor|>(R|<local>/d|)
|
||||
|
||||
@@ -19,10 +19,10 @@ FILE: simpleCapturedTypes.kt
|
||||
^ this@R|/idP|
|
||||
}
|
||||
private final fun getSetterInfos(kc: R|KC<out Ann>|): R|kotlin/Unit| {
|
||||
R|/id|<R|Ann|>(R|<local>/kc|).R|SubstitutionOverride</KC.x: R|CapturedType(out Ann)|>|.R|/Ann.foo|()
|
||||
R|<local>/kc|.R|/idR|<R|Ann|>().R|SubstitutionOverride</KC.x: R|CapturedType(out Ann)|>|.R|/Ann.foo|()
|
||||
R|<local>/kc|.R|/idP|<R|Ann|>.R|SubstitutionOverride</KC.x: R|CapturedType(out Ann)|>|.R|/Ann.foo|()
|
||||
lval x1: R|KC<out Ann>| = R|/id|<R|Ann|>(R|<local>/kc|)
|
||||
lval x2: R|KC<out Ann>| = R|<local>/kc|.R|/idR|<R|Ann|>()
|
||||
lval x3: R|KC<out Ann>| = R|<local>/kc|.R|/idP|<R|Ann|>
|
||||
R|/id|<R|CapturedType(out Ann)|>(R|<local>/kc|).R|SubstitutionOverride</KC.x: R|CapturedType(out Ann)|>|.R|/Ann.foo|()
|
||||
R|<local>/kc|.R|/idR|<R|CapturedType(out Ann)|>().R|SubstitutionOverride</KC.x: R|CapturedType(out Ann)|>|.R|/Ann.foo|()
|
||||
R|<local>/kc|.R|/idP|<R|CapturedType(out Ann)|>.R|SubstitutionOverride</KC.x: R|CapturedType(out Ann)|>|.R|/Ann.foo|()
|
||||
lval x1: R|KC<out Ann>| = R|/id|<R|CapturedType(out Ann)|>(R|<local>/kc|)
|
||||
lval x2: R|KC<out Ann>| = R|<local>/kc|.R|/idR|<R|CapturedType(out Ann)|>()
|
||||
lval x3: R|KC<out Ann>| = R|<local>/kc|.R|/idP|<R|CapturedType(out Ann)|>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
FILE: sameValueParametersDifferentReceiver.kt
|
||||
public open class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final fun R|kotlin/String|.foo(from: R|kotlin/String|, to: R|kotlin/String|): R|kotlin/Int| {
|
||||
^foo Int(1)
|
||||
}
|
||||
|
||||
public final fun <T> R|T|.foo(from: R|kotlin/String|, to: R|kotlin/String|): R|kotlin/Int| {
|
||||
^foo Int(1)
|
||||
}
|
||||
|
||||
}
|
||||
public final class B : R|A| {
|
||||
public constructor(): R|B| {
|
||||
super<R|A|>()
|
||||
}
|
||||
|
||||
}
|
||||
11
compiler/fir/analysis-tests/testData/resolve/overrides/sameValueParametersDifferentReceiver.kt
vendored
Normal file
11
compiler/fir/analysis-tests/testData/resolve/overrides/sameValueParametersDifferentReceiver.kt
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
open class A {
|
||||
fun String.foo(from: String, to: String): Int {
|
||||
return 1
|
||||
}
|
||||
|
||||
fun <T> T.foo(from: String, to: String): Int {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
class B : A()
|
||||
@@ -40,8 +40,8 @@ FILE: referenceToExtension.kt
|
||||
}
|
||||
|
||||
public final fun test_2(): R|kotlin/Unit| {
|
||||
lval extensionValRef: R|kotlin/reflect/KProperty1<GenericTest.B<*>, GenericTest.A<CapturedType(*)>>| = Q|GenericTest.B|::R|/GenericTest.extensionVal<kotlin/Any?>|
|
||||
lval extensionFunRef: R|@ExtensionFunctionType kotlin/reflect/KFunction1<GenericTest.B<*>, GenericTest.A<CapturedType(*)>>| = Q|GenericTest.B|::R|/GenericTest.extensionFun<kotlin/Any?>|
|
||||
lval extensionValRef: R|kotlin/reflect/KProperty1<GenericTest.B<*>, GenericTest.A<CapturedType(*)>>| = Q|GenericTest.B|::R|/GenericTest.extensionVal<CapturedType(*)>|
|
||||
lval extensionFunRef: R|@ExtensionFunctionType kotlin/reflect/KFunction1<GenericTest.B<*>, GenericTest.A<CapturedType(*)>>| = Q|GenericTest.B|::R|/GenericTest.extensionFun<CapturedType(*)>|
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -702,44 +702,45 @@ digraph boundSmartcastsInBranches_kt {
|
||||
293 [label="Access variable R|<local>/x|"];
|
||||
294 [label="Access variable <Inapplicable(UNSAFE_CALL): kotlin/String.length>#"];
|
||||
295 [label="Access variable R|<local>/y|"];
|
||||
296 [label="Access variable R|kotlin/String.length|"];
|
||||
297 [label="Access variable R|<local>/z|"];
|
||||
298 [label="Access variable <Inapplicable(UNSAFE_CALL): kotlin/String.length>#"];
|
||||
299 [label="Exit block"];
|
||||
296 [label="Stub" style="filled" fillcolor=gray];
|
||||
297 [label="Access variable R|kotlin/String.length|" style="filled" fillcolor=gray];
|
||||
298 [label="Access variable R|<local>/z|" style="filled" fillcolor=gray];
|
||||
299 [label="Access variable <Inapplicable(UNSAFE_CALL): kotlin/String.length>#" style="filled" fillcolor=gray];
|
||||
300 [label="Exit block" style="filled" fillcolor=gray];
|
||||
}
|
||||
300 [label="Exit when branch result"];
|
||||
301 [label="Exit when"];
|
||||
301 [label="Exit when branch result" style="filled" fillcolor=gray];
|
||||
302 [label="Exit when"];
|
||||
}
|
||||
subgraph cluster_67 {
|
||||
color=blue
|
||||
302 [label="Enter when"];
|
||||
303 [label="Enter when"];
|
||||
subgraph cluster_68 {
|
||||
color=blue
|
||||
303 [label="Enter when branch condition "];
|
||||
304 [label="Access variable R|<local>/z|"];
|
||||
305 [label="Const: Null(null)"];
|
||||
306 [label="Equality operator !="];
|
||||
307 [label="Exit when branch condition"];
|
||||
304 [label="Enter when branch condition "];
|
||||
305 [label="Access variable R|<local>/z|"];
|
||||
306 [label="Const: Null(null)"];
|
||||
307 [label="Equality operator !="];
|
||||
308 [label="Exit when branch condition"];
|
||||
}
|
||||
308 [label="Synthetic else branch"];
|
||||
309 [label="Enter when branch result"];
|
||||
309 [label="Synthetic else branch"];
|
||||
310 [label="Enter when branch result"];
|
||||
subgraph cluster_69 {
|
||||
color=blue
|
||||
310 [label="Enter block"];
|
||||
311 [label="Access variable R|<local>/x|"];
|
||||
312 [label="Access variable R|kotlin/String.length|"];
|
||||
313 [label="Access variable R|<local>/y|"];
|
||||
314 [label="Access variable <Inapplicable(UNSAFE_CALL): kotlin/String.length>#"];
|
||||
315 [label="Access variable R|<local>/z|"];
|
||||
316 [label="Access variable R|kotlin/String.length|"];
|
||||
317 [label="Exit block"];
|
||||
311 [label="Enter block"];
|
||||
312 [label="Access variable R|<local>/x|"];
|
||||
313 [label="Access variable R|kotlin/String.length|"];
|
||||
314 [label="Access variable R|<local>/y|"];
|
||||
315 [label="Access variable <Inapplicable(UNSAFE_CALL): kotlin/String.length>#"];
|
||||
316 [label="Access variable R|<local>/z|"];
|
||||
317 [label="Access variable R|kotlin/String.length|"];
|
||||
318 [label="Exit block"];
|
||||
}
|
||||
318 [label="Exit when branch result"];
|
||||
319 [label="Exit when"];
|
||||
319 [label="Exit when branch result"];
|
||||
320 [label="Exit when"];
|
||||
}
|
||||
320 [label="Exit block"];
|
||||
321 [label="Exit block"];
|
||||
}
|
||||
321 [label="Exit function test_7" style="filled" fillcolor=red];
|
||||
322 [label="Exit function test_7" style="filled" fillcolor=red];
|
||||
}
|
||||
202 -> {203};
|
||||
203 -> {204};
|
||||
@@ -829,26 +830,27 @@ digraph boundSmartcastsInBranches_kt {
|
||||
287 -> {288};
|
||||
288 -> {289};
|
||||
289 -> {291 290};
|
||||
290 -> {301};
|
||||
290 -> {302};
|
||||
291 -> {292};
|
||||
292 -> {293};
|
||||
293 -> {294};
|
||||
294 -> {295};
|
||||
295 -> {296};
|
||||
296 -> {297};
|
||||
297 -> {298};
|
||||
298 -> {299};
|
||||
299 -> {300};
|
||||
300 -> {301};
|
||||
301 -> {302};
|
||||
295 -> {322} [label=onUncaughtException];
|
||||
295 -> {296} [style=dotted];
|
||||
296 -> {297} [style=dotted];
|
||||
297 -> {298} [style=dotted];
|
||||
298 -> {299} [style=dotted];
|
||||
299 -> {300} [style=dotted];
|
||||
300 -> {301} [style=dotted];
|
||||
301 -> {302} [style=dotted];
|
||||
302 -> {303};
|
||||
303 -> {304};
|
||||
304 -> {305};
|
||||
305 -> {306};
|
||||
306 -> {307};
|
||||
307 -> {309 308};
|
||||
308 -> {319};
|
||||
309 -> {310};
|
||||
307 -> {308};
|
||||
308 -> {310 309};
|
||||
309 -> {320};
|
||||
310 -> {311};
|
||||
311 -> {312};
|
||||
312 -> {313};
|
||||
@@ -860,5 +862,6 @@ digraph boundSmartcastsInBranches_kt {
|
||||
318 -> {319};
|
||||
319 -> {320};
|
||||
320 -> {321};
|
||||
321 -> {322};
|
||||
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ fun test_7() {
|
||||
y<!UNSAFE_CALL!>.<!>length // Bad
|
||||
z.length // OK
|
||||
}
|
||||
if (y != null) {
|
||||
if (<!SENSELESS_COMPARISON!>y != null<!>) {
|
||||
x<!UNSAFE_CALL!>.<!>length // Bad
|
||||
y.length // OK
|
||||
z<!UNSAFE_CALL!>.<!>length // Bad
|
||||
|
||||
144
compiler/fir/analysis-tests/testData/resolve/smartcasts/incorrectSmartcastToNothing.dot
vendored
Normal file
144
compiler/fir/analysis-tests/testData/resolve/smartcasts/incorrectSmartcastToNothing.dot
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
digraph incorrectSmartcastToNothing_kt {
|
||||
graph [nodesep=3]
|
||||
node [shape=box penwidth=2]
|
||||
edge [penwidth=2]
|
||||
|
||||
subgraph cluster_0 {
|
||||
color=red
|
||||
0 [label="Enter property" style="filled" fillcolor=red];
|
||||
1 [label="Const: String(foo)"];
|
||||
2 [label="Function call: R|java/io/File.File|(...)"];
|
||||
3 [label="Exit property" style="filled" fillcolor=red];
|
||||
}
|
||||
0 -> {1};
|
||||
1 -> {2};
|
||||
2 -> {3};
|
||||
|
||||
subgraph cluster_1 {
|
||||
color=red
|
||||
4 [label="Enter function test" style="filled" fillcolor=red];
|
||||
subgraph cluster_2 {
|
||||
color=blue
|
||||
5 [label="Enter block"];
|
||||
subgraph cluster_3 {
|
||||
color=blue
|
||||
6 [label="Enter when"];
|
||||
subgraph cluster_4 {
|
||||
color=blue
|
||||
7 [label="Enter when branch condition "];
|
||||
8 [label="Access variable R|<local>/cacheExtSetting|"];
|
||||
9 [label="Const: Null(null)"];
|
||||
10 [label="Equality operator =="];
|
||||
11 [label="Exit when branch condition"];
|
||||
}
|
||||
subgraph cluster_5 {
|
||||
color=blue
|
||||
12 [label="Enter when branch condition "];
|
||||
13 [label="Access variable R|<local>/cacheExtSetting|"];
|
||||
14 [label="Function call: R|<local>/cacheExtSetting|.R|kotlin/text/isBlank|()"];
|
||||
15 [label="Exit when branch condition"];
|
||||
}
|
||||
subgraph cluster_6 {
|
||||
color=blue
|
||||
16 [label="Enter when branch condition else"];
|
||||
17 [label="Exit when branch condition"];
|
||||
}
|
||||
18 [label="Enter when branch result"];
|
||||
subgraph cluster_7 {
|
||||
color=blue
|
||||
19 [label="Enter block"];
|
||||
20 [label="Access variable R|<local>/cacheExtSetting|"];
|
||||
21 [label="Function call: R|java/io/File.File|(...)"];
|
||||
22 [label="Exit block"];
|
||||
}
|
||||
23 [label="Exit when branch result"];
|
||||
24 [label="Enter when branch result"];
|
||||
subgraph cluster_8 {
|
||||
color=blue
|
||||
25 [label="Enter block"];
|
||||
26 [label="Const: Null(null)"];
|
||||
27 [label="Exit block"];
|
||||
}
|
||||
28 [label="Exit when branch result"];
|
||||
29 [label="Enter when branch result"];
|
||||
subgraph cluster_9 {
|
||||
color=blue
|
||||
30 [label="Enter block"];
|
||||
31 [label="Access variable R|/cache|"];
|
||||
32 [label="Enter safe call"];
|
||||
33 [label="Postponed enter to lambda"];
|
||||
subgraph cluster_10 {
|
||||
color=blue
|
||||
43 [label="Enter function anonymousFunction" style="filled" fillcolor=red];
|
||||
subgraph cluster_11 {
|
||||
color=blue
|
||||
44 [label="Enter block"];
|
||||
45 [label="Access variable R|<local>/it|"];
|
||||
46 [label="Const: String(main.kts.compiled.cache)"];
|
||||
47 [label="Function call: R|java/io/File.File|(...)"];
|
||||
48 [label="Exit block"];
|
||||
}
|
||||
49 [label="Exit function anonymousFunction" style="filled" fillcolor=red];
|
||||
}
|
||||
34 [label="Postponed exit from lambda"];
|
||||
35 [label="Function call: $subj$.R|kotlin/let|<R|java/io/File|, R|java/io/File|>(...)"];
|
||||
36 [label="Exit safe call"];
|
||||
37 [label="Exit block"];
|
||||
}
|
||||
38 [label="Exit when branch result"];
|
||||
39 [label="Exit when"];
|
||||
}
|
||||
40 [label="Variable declaration: lval cacheBaseDir: R|java/io/File?|"];
|
||||
41 [label="Exit block"];
|
||||
}
|
||||
42 [label="Exit function test" style="filled" fillcolor=red];
|
||||
}
|
||||
4 -> {5};
|
||||
5 -> {6};
|
||||
6 -> {7};
|
||||
7 -> {8};
|
||||
8 -> {9};
|
||||
9 -> {10};
|
||||
10 -> {11};
|
||||
11 -> {29 12};
|
||||
12 -> {13};
|
||||
13 -> {14};
|
||||
14 -> {15};
|
||||
15 -> {24 16};
|
||||
16 -> {17};
|
||||
17 -> {18};
|
||||
18 -> {19};
|
||||
19 -> {20};
|
||||
20 -> {21};
|
||||
21 -> {22};
|
||||
22 -> {23};
|
||||
23 -> {39};
|
||||
24 -> {25};
|
||||
25 -> {26};
|
||||
26 -> {27};
|
||||
27 -> {28};
|
||||
28 -> {39};
|
||||
29 -> {30};
|
||||
30 -> {31};
|
||||
31 -> {32 36};
|
||||
32 -> {33};
|
||||
33 -> {43};
|
||||
33 -> {34} [color=red];
|
||||
33 -> {43} [style=dashed];
|
||||
34 -> {35};
|
||||
35 -> {36};
|
||||
36 -> {37};
|
||||
37 -> {38};
|
||||
38 -> {39};
|
||||
39 -> {40};
|
||||
40 -> {41};
|
||||
41 -> {42};
|
||||
43 -> {44};
|
||||
44 -> {45};
|
||||
45 -> {46};
|
||||
46 -> {47};
|
||||
47 -> {48};
|
||||
48 -> {49};
|
||||
49 -> {34} [color=green];
|
||||
|
||||
}
|
||||
20
compiler/fir/analysis-tests/testData/resolve/smartcasts/incorrectSmartcastToNothing.fir.txt
vendored
Normal file
20
compiler/fir/analysis-tests/testData/resolve/smartcasts/incorrectSmartcastToNothing.fir.txt
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
FILE: incorrectSmartcastToNothing.kt
|
||||
public final val cache: R|java/io/File?| = R|java/io/File.File|(String(foo))
|
||||
public get(): R|java/io/File?|
|
||||
public final fun test(cacheExtSetting: R|kotlin/String?|): R|kotlin/Unit| {
|
||||
lval cacheBaseDir: R|java/io/File?| = when () {
|
||||
==(R|<local>/cacheExtSetting|, Null(null)) -> {
|
||||
R|/cache|?.{ $subj$.R|kotlin/let|<R|java/io/File|, R|java/io/File|>(<L> = let@fun <anonymous>(it: R|java/io/File|): R|java/io/File| <inline=Inline, kind=EXACTLY_ONCE> {
|
||||
^ R|java/io/File.File|(R|<local>/it|, String(main.kts.compiled.cache))
|
||||
}
|
||||
) }
|
||||
}
|
||||
R|<local>/cacheExtSetting|.R|kotlin/text/isBlank|() -> {
|
||||
Null(null)
|
||||
}
|
||||
else -> {
|
||||
R|java/io/File.File|(R|<local>/cacheExtSetting|)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
15
compiler/fir/analysis-tests/testData/resolve/smartcasts/incorrectSmartcastToNothing.kt
vendored
Normal file
15
compiler/fir/analysis-tests/testData/resolve/smartcasts/incorrectSmartcastToNothing.kt
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// WITH_STDLIB
|
||||
// FULL_JDK
|
||||
// DUMP_CFG
|
||||
|
||||
import java.io.File
|
||||
|
||||
val cache: File? = File("foo")
|
||||
|
||||
fun test(cacheExtSetting: String?) {
|
||||
val cacheBaseDir = when {
|
||||
cacheExtSetting == null -> cache?.let { File(it, "main.kts.compiled.cache") }
|
||||
cacheExtSetting.isBlank() -> null
|
||||
else -> File(cacheExtSetting)
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ var Any?.isNotNull: Boolean
|
||||
set(value) {
|
||||
contract {
|
||||
returns() implies (this@isNotNull != null)
|
||||
<!ERROR_IN_CONTRACT_DESCRIPTION!>require(this != null)<!>
|
||||
<!ERROR_IN_CONTRACT_DESCRIPTION!>require(<!SENSELESS_COMPARISON!>this != null<!>)<!>
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
FILE: DailyAggregatedDoubleFactor.kt
|
||||
public abstract interface DailyAggregatedDoubleFactor : R|kotlin/Any| {
|
||||
}
|
||||
private final fun R|DailyAggregatedDoubleFactor|.aggregateBy(reduce: R|(kotlin/Double, kotlin/Double) -> kotlin/Double|): R|kotlin/collections/Map<kotlin/String, kotlin/Double>| {
|
||||
^aggregateBy R|kotlin/collections/mutableMapOf|<R|kotlin/String|, R|kotlin/Double|>()
|
||||
}
|
||||
public final fun R|DailyAggregatedDoubleFactor|.aggregateMin(): R|kotlin/collections/Map<kotlin/String, kotlin/Double>| {
|
||||
^aggregateMin this@R|/aggregateMin|.R|/aggregateBy|(::R|kotlin/comparisons/minOf|)
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
interface DailyAggregatedDoubleFactor
|
||||
|
||||
private fun DailyAggregatedDoubleFactor.aggregateBy(reduce: (Double, Double) -> Double): Map<String, Double> {
|
||||
return mutableMapOf<String, Double>()
|
||||
}
|
||||
|
||||
fun DailyAggregatedDoubleFactor.aggregateMin(): Map<String, Double> = aggregateBy(::minOf)
|
||||
@@ -7,7 +7,7 @@ FILE: test.kt
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
private final val klass: R|java/lang/Class<out MyTest>| = <getClass>(this@R|/MyTest|).R|kotlin/jvm/java|<R|MyTest|>
|
||||
private final val klass: R|java/lang/Class<out MyTest>| = <getClass>(this@R|/MyTest|).R|kotlin/jvm/java|<R|CapturedType(out MyTest)|>
|
||||
private get(): R|java/lang/Class<out MyTest>|
|
||||
|
||||
private final val logger: R|ft<Logger, Logger?>| = Q|Logger|.R|/Logger.getInstance|(this@R|/MyTest|.R|/MyTest.klass|)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FILE: capturedFlexible.kt
|
||||
public final fun foo(z: R|java/util/zip/ZipFile|): R|kotlin/Unit| {
|
||||
R|<local>/z|.R|java/util/zip/ZipFile.entries|().R|kotlin/sequences/asSequence|<R|ft<java/util/zip/ZipEntry, java/util/zip/ZipEntry?>|>()
|
||||
R|<local>/z|.R|java/util/zip/ZipFile.entries|().R|kotlin/sequences/asSequence|<R|CapturedType(out ft<java/util/zip/ZipEntry, java/util/zip/ZipEntry?>)|>()
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ fun test() {
|
||||
val Any.bar get() = "456"
|
||||
val String.bar get() = "987"
|
||||
|
||||
<!REDECLARATION!>val t = "".bar<!>
|
||||
val <!REDECLARATION!>t<!> = "".bar
|
||||
|
||||
val p = Pair(0, "")
|
||||
|
||||
@@ -21,4 +21,4 @@ open class Base<T>(val x: T)
|
||||
class Derived : Base<Int>(10)
|
||||
val xx = Derived().x + 1
|
||||
|
||||
<!REDECLARATION!>val t = throw AssertionError("")<!>
|
||||
val <!REDECLARATION!>t<!> = throw AssertionError("")
|
||||
|
||||
@@ -731,6 +731,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/namedArrayInAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClassInAnnotationArgument.kt")
|
||||
public void testNestedClassInAnnotationArgument() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/nestedClassInAnnotationArgument.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noParameterForName.kt")
|
||||
public void testNoParameterForName() throws Exception {
|
||||
@@ -3053,6 +3059,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/overrides/protobufExt.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("sameValueParametersDifferentReceiver.kt")
|
||||
public void testSameValueParametersDifferentReceiver() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/overrides/sameValueParametersDifferentReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
@@ -3455,6 +3467,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/equalsAndIdentity.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("incorrectSmartcastToNothing.kt")
|
||||
public void testIncorrectSmartcastToNothing() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/incorrectSmartcastToNothing.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt10240.kt")
|
||||
public void testKt10240() throws Exception {
|
||||
@@ -5006,6 +5024,22 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Intellij {
|
||||
@Test
|
||||
public void testAllFilesPresentInIntellij() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("DailyAggregatedDoubleFactor.kt")
|
||||
public void testDailyAggregatedDoubleFactor() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/DailyAggregatedDoubleFactor.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
@@ -731,6 +731,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/namedArrayInAnnotation.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("nestedClassInAnnotationArgument.kt")
|
||||
public void testNestedClassInAnnotationArgument() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/arguments/nestedClassInAnnotationArgument.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("noParameterForName.kt")
|
||||
public void testNoParameterForName() throws Exception {
|
||||
@@ -3053,6 +3059,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/overrides/protobufExt.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("sameValueParametersDifferentReceiver.kt")
|
||||
public void testSameValueParametersDifferentReceiver() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/overrides/sameValueParametersDifferentReceiver.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("simple.kt")
|
||||
public void testSimple() throws Exception {
|
||||
@@ -3455,6 +3467,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/equalsAndIdentity.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("incorrectSmartcastToNothing.kt")
|
||||
public void testIncorrectSmartcastToNothing() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/smartcasts/incorrectSmartcastToNothing.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt10240.kt")
|
||||
public void testKt10240() throws Exception {
|
||||
@@ -5006,6 +5024,22 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Intellij {
|
||||
@Test
|
||||
public void testAllFilesPresentInIntellij() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("DailyAggregatedDoubleFactor.kt")
|
||||
public void testDailyAggregatedDoubleFactor() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolveWithStdlib/intellij/DailyAggregatedDoubleFactor.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
@@ -5908,6 +5908,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt4034.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaInTryFalsePositive.kt")
|
||||
public void testLambdaInTryFalsePositive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/lambdaInTryFalsePositive.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ReturnFromFunctionInObject.kt")
|
||||
public void testReturnFromFunctionInObject() throws Exception {
|
||||
@@ -6013,6 +6019,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/controlStructures"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakToLabel.kt")
|
||||
public void testBreakToLabel() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlStructures/breakToLabel.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("catchGenerics.kt")
|
||||
public void testCatchGenerics() throws Exception {
|
||||
@@ -7495,6 +7507,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mappedFunctionNotImplemented.kt")
|
||||
public void testMappedFunctionNotImplemented() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/declarationChecks/mappedFunctionNotImplemented.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mulitpleVarargParameters.kt")
|
||||
public void testMulitpleVarargParameters() throws Exception {
|
||||
@@ -10705,6 +10723,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/kt4529.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt47493.kt")
|
||||
public void testKt47493() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/kt47493.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6541_extensionForExtensionFunction.kt")
|
||||
public void testKt6541_extensionForExtensionFunction() throws Exception {
|
||||
@@ -15234,6 +15258,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/inference/regressions/kt44440.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt47941.kt")
|
||||
public void testKt47941() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/regressions/kt47941.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt702.kt")
|
||||
public void testKt702() throws Exception {
|
||||
@@ -21646,12 +21676,30 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("deepTypeHierarchy.kt")
|
||||
public void testDeepTypeHierarchy() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/deepTypeHierarchy.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inferenceFrom.kt")
|
||||
public void testInferenceFrom() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/inferenceFrom.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaOutProjection.kt")
|
||||
public void testJavaOutProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/javaOutProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinOutProjection.kt")
|
||||
public void testKotlinOutProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinOutProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("listSuperType.kt")
|
||||
public void testListSuperType() throws Exception {
|
||||
@@ -22330,6 +22378,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/properties")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Properties {
|
||||
@Test
|
||||
@TestMetadata("abstarctPropertyInPrimaryConstructor.kt")
|
||||
public void testAbstarctPropertyInPrimaryConstructor() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/properties/abstarctPropertyInPrimaryConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInProperties() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/properties"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
@@ -22763,6 +22817,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredTypeParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("RedeclaredValueParameters.kt")
|
||||
public void testRedeclaredValueParameters() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredValueParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("RedeclaringPrivateToFile.kt")
|
||||
public void testRedeclaringPrivateToFile() throws Exception {
|
||||
@@ -28205,6 +28265,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/accessorAndFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("aliasing.kt")
|
||||
public void testAliasing() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/aliasing.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInVariables() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/smartCasts/variables"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
@@ -31915,6 +31981,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/when/kt4434.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt47922.kt")
|
||||
public void testKt47922() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/kt47922.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt9929.kt")
|
||||
public void testKt9929() throws Exception {
|
||||
@@ -32071,6 +32143,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("whenOnNothing.kt")
|
||||
public void testWhenOnNothing() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/whenOnNothing.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("WhenTypeDisjunctions.kt")
|
||||
public void testWhenTypeDisjunctions() throws Exception {
|
||||
|
||||
@@ -5908,6 +5908,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/kt4034.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("lambdaInTryFalsePositive.kt")
|
||||
public void testLambdaInTryFalsePositive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlFlowAnalysis/definiteReturn/lambdaInTryFalsePositive.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ReturnFromFunctionInObject.kt")
|
||||
public void testReturnFromFunctionInObject() throws Exception {
|
||||
@@ -6013,6 +6019,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/controlStructures"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("breakToLabel.kt")
|
||||
public void testBreakToLabel() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlStructures/breakToLabel.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("catchGenerics.kt")
|
||||
public void testCatchGenerics() throws Exception {
|
||||
@@ -7495,6 +7507,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/declarationChecks/localVariablesWithTypeParameters_1_4.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mappedFunctionNotImplemented.kt")
|
||||
public void testMappedFunctionNotImplemented() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/declarationChecks/mappedFunctionNotImplemented.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("mulitpleVarargParameters.kt")
|
||||
public void testMulitpleVarargParameters() throws Exception {
|
||||
@@ -10705,6 +10723,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/kt4529.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt47493.kt")
|
||||
public void testKt47493() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/functionLiterals/kt47493.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt6541_extensionForExtensionFunction.kt")
|
||||
public void testKt6541_extensionForExtensionFunction() throws Exception {
|
||||
@@ -15234,6 +15258,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/inference/regressions/kt44440.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt47941.kt")
|
||||
public void testKt47941() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/regressions/kt47941.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt702.kt")
|
||||
public void testKt702() throws Exception {
|
||||
@@ -21646,12 +21676,30 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("deepTypeHierarchy.kt")
|
||||
public void testDeepTypeHierarchy() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/deepTypeHierarchy.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("inferenceFrom.kt")
|
||||
public void testInferenceFrom() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/inferenceFrom.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("javaOutProjection.kt")
|
||||
public void testJavaOutProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/javaOutProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinOutProjection.kt")
|
||||
public void testKotlinOutProjection() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/genericVarianceViolation/kotlinOutProjection.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("listSuperType.kt")
|
||||
public void testListSuperType() throws Exception {
|
||||
@@ -22330,6 +22378,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/properties")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class Properties {
|
||||
@Test
|
||||
@TestMetadata("abstarctPropertyInPrimaryConstructor.kt")
|
||||
public void testAbstarctPropertyInPrimaryConstructor() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/properties/abstarctPropertyInPrimaryConstructor.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInProperties() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/properties"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
@@ -22763,6 +22817,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredTypeParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("RedeclaredValueParameters.kt")
|
||||
public void testRedeclaredValueParameters() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/redeclarations/RedeclaredValueParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("RedeclaringPrivateToFile.kt")
|
||||
public void testRedeclaringPrivateToFile() throws Exception {
|
||||
@@ -28205,6 +28265,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/accessorAndFunction.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("aliasing.kt")
|
||||
public void testAliasing() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/smartCasts/variables/aliasing.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllFilesPresentInVariables() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/smartCasts/variables"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||
@@ -31915,6 +31981,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/when/kt4434.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt47922.kt")
|
||||
public void testKt47922() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/kt47922.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt9929.kt")
|
||||
public void testKt9929() throws Exception {
|
||||
@@ -32071,6 +32143,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/when/whenAndLambdaWithExpectedType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("whenOnNothing.kt")
|
||||
public void testWhenOnNothing() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/when/whenOnNothing.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("WhenTypeDisjunctions.kt")
|
||||
public void testWhenTypeDisjunctions() throws Exception {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ plugins {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":generators"))
|
||||
implementation(project(":compiler:fir:tree"))
|
||||
implementation(project(":compiler:fir:tree:tree-generator"))
|
||||
implementation(project(":compiler:resolution.common"))
|
||||
|
||||
@@ -14,16 +14,16 @@ import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.lexer.KtKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
@@ -87,11 +87,6 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by warning<KtParameter>(PositioningStrategy.VAL_OR_VAR_NODE) {
|
||||
parameter<KtKeywordToken>("valOrVar")
|
||||
}
|
||||
val INVISIBLE_SETTER by error<PsiElement>(PositioningStrategy.ASSIGNMENT_LHS) {
|
||||
parameter<FirPropertySymbol>("property")
|
||||
parameter<Visibility>("visibility")
|
||||
parameter<CallableId>("callableId")
|
||||
}
|
||||
}
|
||||
|
||||
val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
|
||||
@@ -101,7 +96,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val UNRESOLVED_REFERENCE by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
|
||||
parameter<String>("reference")
|
||||
}
|
||||
val UNRESOLVED_LABEL by error<PsiElement>()
|
||||
val UNRESOLVED_LABEL by error<PsiElement>(PositioningStrategy.LABEL)
|
||||
val DESERIALIZATION_ERROR by error<PsiElement>()
|
||||
val ERROR_FROM_JAVA_RESOLUTION by error<PsiElement>()
|
||||
val MISSING_STDLIB_CLASS by error<PsiElement>()
|
||||
@@ -146,6 +141,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
|
||||
val SUPERTYPES by object : DiagnosticGroup("Supertypes") {
|
||||
val NOT_A_SUPERTYPE by error<PsiElement>()
|
||||
val TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER by warning<KtElement>()
|
||||
val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error<PsiElement>()
|
||||
val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error<KtTypeReference> {
|
||||
parameter<Symbol>("otherSuperType")
|
||||
@@ -182,6 +178,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<FirRegularClassSymbol>("type")
|
||||
parameter<Collection<ConeKotlinType>>("bounds")
|
||||
}
|
||||
val AMBIGUOUS_SUPER by error<KtSuperExpression>()
|
||||
}
|
||||
|
||||
val CONSTRUCTOR_PROBLEMS by object : DiagnosticGroup("Constructor problems") {
|
||||
@@ -235,8 +232,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val DEPRECATED_SINCE_KOTLIN_WITH_DEPRECATED_LEVEL by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val DEPRECATED_SINCE_KOTLIN_OUTSIDE_KOTLIN_SUBPACKAGE by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
|
||||
val ANNOTATION_ON_SUPERCLASS by error<KtAnnotationEntry>()
|
||||
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by error<PsiElement>()
|
||||
val ANNOTATION_ON_SUPERCLASS by deprecationError<KtAnnotationEntry>(LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes)
|
||||
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by deprecationError<PsiElement>(LanguageFeature.RestrictRetentionForExpressionAnnotations)
|
||||
val WRONG_ANNOTATION_TARGET by error<KtAnnotationEntry> {
|
||||
parameter<String>("actualTarget")
|
||||
}
|
||||
@@ -497,11 +494,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||
}
|
||||
|
||||
val TYPE_PARAMETER_AS_REIFIED_ARRAY by error<PsiElement> {
|
||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||
}
|
||||
|
||||
val TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING by warning<PsiElement> {
|
||||
val TYPE_PARAMETER_AS_REIFIED_ARRAY by deprecationError<PsiElement>(LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments) {
|
||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||
}
|
||||
|
||||
@@ -670,11 +663,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<FirClassSymbol<*>>("classOrObject")
|
||||
parameter<FirCallableSymbol<*>>("missingDeclaration")
|
||||
}
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by error<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
parameter<FirClassSymbol<*>>("classOrObject")
|
||||
parameter<FirCallableSymbol<*>>("invisibleDeclaration")
|
||||
}
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING by warning<KtClassOrObject>(PositioningStrategy.DECLARATION_NAME) {
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by deprecationError<KtClassOrObject>(
|
||||
LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses,
|
||||
PositioningStrategy.DECLARATION_NAME
|
||||
) {
|
||||
parameter<FirClassSymbol<*>>("classOrObject")
|
||||
parameter<FirCallableSymbol<*>>("invisibleDeclaration")
|
||||
}
|
||||
@@ -724,7 +716,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val CONFLICTING_OVERLOADS by error<PsiElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
|
||||
parameter<Collection<Symbol>>("conflictingOverloads")
|
||||
}
|
||||
val REDECLARATION by error<PsiElement> {
|
||||
val REDECLARATION by error<KtNamedDeclaration>(PositioningStrategy.NAME_IDENTIFIER) {
|
||||
parameter<Collection<Symbol>>("conflictingDeclarations")
|
||||
}
|
||||
val PACKAGE_OR_CLASSIFIER_REDECLARATION by error<KtNamedDeclaration>(PositioningStrategy.ACTUAL_DECLARATION_NAME) {
|
||||
parameter<Collection<Symbol>>("conflictingDeclarations")
|
||||
}
|
||||
val METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE by error<PsiElement>()
|
||||
@@ -836,6 +831,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
}
|
||||
val ACCESSOR_FOR_DELEGATED_PROPERTY by error<KtPropertyAccessor>()
|
||||
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error<KtModifierListOwner>(PositioningStrategy.ABSTRACT_MODIFIER)
|
||||
}
|
||||
|
||||
val MPP_PROJECTS by object : DiagnosticGroup("Multi-platform projects") {
|
||||
@@ -928,10 +924,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val VAL_REASSIGNMENT by error<KtExpression> {
|
||||
parameter<FirVariableSymbol<*>>("variable")
|
||||
}
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD by warning<KtExpression> {
|
||||
parameter<FirBackingFieldSymbol>("property")
|
||||
}
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR by error<KtExpression> {
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD by deprecationError<KtExpression>(LanguageFeature.RestrictionOfValReassignmentViaBackingField) {
|
||||
parameter<FirBackingFieldSymbol>("property")
|
||||
}
|
||||
val CAPTURED_VAL_INITIALIZATION by error<KtExpression> {
|
||||
@@ -957,6 +950,15 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val INITIALIZATION_BEFORE_DECLARATION by error<KtExpression>() {
|
||||
parameter<Symbol>("property")
|
||||
}
|
||||
val UNREACHABLE_CODE by warning<KtElement>(PositioningStrategy.UNREACHABLE_CODE) {
|
||||
parameter<Set<FirSourceElement>>("reachable")
|
||||
parameter<Set<FirSourceElement>>("unreachable")
|
||||
}
|
||||
val SENSELESS_COMPARISON by warning<KtExpression> {
|
||||
parameter<FirExpression>("expression")
|
||||
parameter<Boolean>("compareResult")
|
||||
}
|
||||
val SENSELESS_NULL_IN_WHEN by warning<KtElement>()
|
||||
}
|
||||
|
||||
val NULLABILITY by object : DiagnosticGroup("Nullability") {
|
||||
@@ -1138,6 +1140,17 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<Symbol>("parameter")
|
||||
}
|
||||
|
||||
val NOT_YET_SUPPORTED_IN_INLINE by error<KtDeclaration>(PositioningStrategy.NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT) {
|
||||
parameter<String>("message")
|
||||
}
|
||||
|
||||
val NOTHING_TO_INLINE by warning<KtDeclaration>(PositioningStrategy.NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT)
|
||||
|
||||
val NULLABLE_INLINE_PARAMETER by error<KtDeclaration>() {
|
||||
parameter<FirValueParameterSymbol>("parameter")
|
||||
parameter<Symbol>("function")
|
||||
}
|
||||
|
||||
val RECURSION_IN_INLINE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("symbol")
|
||||
}
|
||||
@@ -1170,6 +1183,27 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val SUPER_CALL_FROM_PUBLIC_INLINE by warning<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("symbol")
|
||||
}
|
||||
|
||||
val DECLARATION_CANT_BE_INLINED by error<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
|
||||
val OVERRIDE_BY_INLINE by warning<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
|
||||
val NON_INTERNAL_PUBLISHED_API by error<KtElement>()
|
||||
|
||||
val INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE by error<KtElement>() {
|
||||
parameter<FirExpression>("defaultValue")
|
||||
parameter<FirValueParameterSymbol>("parameter")
|
||||
}
|
||||
|
||||
val REIFIED_TYPE_PARAMETER_IN_OVERRIDE by error<KtElement>(PositioningStrategy.REIFIED_MODIFIER)
|
||||
|
||||
val INLINE_PROPERTY_WITH_BACKING_FIELD by error<KtDeclaration>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
|
||||
val ILLEGAL_INLINE_PARAMETER_MODIFIER by error<KtElement>(PositioningStrategy.INLINE_PARAMETER_MODIFIER)
|
||||
|
||||
val INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED by error<KtParameter>()
|
||||
|
||||
val REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE by warning<KtElement>(PositioningStrategy.SUSPEND_MODIFIER)
|
||||
}
|
||||
|
||||
val IMPORTS by object : DiagnosticGroup("Imports") {
|
||||
@@ -1203,6 +1237,13 @@ 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 = {
|
||||
@@ -1213,13 +1254,13 @@ private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = {
|
||||
|
||||
private inline fun <reified P : PsiElement> AbstractDiagnosticGroup.exposedVisibilityError(
|
||||
positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT
|
||||
): PropertyDelegateProvider<Any?, ReadOnlyProperty<AbstractDiagnosticGroup, DiagnosticData>> {
|
||||
): PropertyDelegateProvider<Any?, ReadOnlyProperty<AbstractDiagnosticGroup, RegularDiagnosticData>> {
|
||||
return error<P>(positioningStrategy, exposedVisibilityDiagnosticInit)
|
||||
}
|
||||
|
||||
private inline fun <reified P : PsiElement> AbstractDiagnosticGroup.exposedVisibilityWarning(
|
||||
positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT
|
||||
): PropertyDelegateProvider<Any?, ReadOnlyProperty<AbstractDiagnosticGroup, DiagnosticData>> {
|
||||
): PropertyDelegateProvider<Any?, ReadOnlyProperty<AbstractDiagnosticGroup, RegularDiagnosticData>> {
|
||||
return warning<P>(positioningStrategy, exposedVisibilityDiagnosticInit)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import kotlin.properties.PropertyDelegateProvider
|
||||
@@ -24,24 +25,31 @@ abstract class AbstractDiagnosticGroup @PrivateForInline constructor(val name: S
|
||||
@OptIn(PrivateForInline::class)
|
||||
internal inline fun <reified P : PsiElement> error(
|
||||
positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT,
|
||||
crossinline init: DiagnosticBuilder.() -> Unit = {}
|
||||
crossinline init: DiagnosticBuilder.Regular.() -> Unit = {}
|
||||
) = diagnosticDelegateProvider<P>(Severity.ERROR, positioningStrategy, init)
|
||||
|
||||
|
||||
@OptIn(PrivateForInline::class)
|
||||
internal inline fun <reified P : PsiElement> warning(
|
||||
positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT,
|
||||
crossinline init: DiagnosticBuilder.() -> Unit = {}
|
||||
crossinline init: DiagnosticBuilder.Regular.() -> Unit = {}
|
||||
) = diagnosticDelegateProvider<P>(Severity.WARNING, positioningStrategy, init)
|
||||
|
||||
@OptIn(PrivateForInline::class)
|
||||
internal inline fun <reified P : PsiElement> deprecationError(
|
||||
featureForError: LanguageFeature,
|
||||
positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT,
|
||||
crossinline init: DiagnosticBuilder.Deprecation.() -> Unit = {}
|
||||
) = deprecationDiagnosticDelegateProvider<P>(featureForError, positioningStrategy, init)
|
||||
|
||||
@PrivateForInline
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
internal inline fun <reified P : PsiElement> diagnosticDelegateProvider(
|
||||
severity: Severity,
|
||||
positioningStrategy: PositioningStrategy,
|
||||
crossinline init: DiagnosticBuilder.() -> Unit = {}
|
||||
) = PropertyDelegateProvider<Any?, ReadOnlyProperty<AbstractDiagnosticGroup, DiagnosticData>> { _, property ->
|
||||
val diagnostic = DiagnosticBuilder(
|
||||
crossinline init: DiagnosticBuilder.Regular.() -> Unit = {}
|
||||
) = PropertyDelegateProvider<Any?, ReadOnlyProperty<AbstractDiagnosticGroup, RegularDiagnosticData>> { _, property ->
|
||||
val diagnostic = DiagnosticBuilder.Regular(
|
||||
containingObjectName,
|
||||
severity,
|
||||
name = property.name,
|
||||
@@ -52,6 +60,24 @@ abstract class AbstractDiagnosticGroup @PrivateForInline constructor(val name: S
|
||||
ReadOnlyProperty { _, _ -> diagnostic }
|
||||
}
|
||||
|
||||
@PrivateForInline
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
internal inline fun <reified P : PsiElement> deprecationDiagnosticDelegateProvider(
|
||||
featureForError: LanguageFeature,
|
||||
positioningStrategy: PositioningStrategy,
|
||||
crossinline init: DiagnosticBuilder.Deprecation.() -> Unit = {}
|
||||
) = PropertyDelegateProvider<Any?, ReadOnlyProperty<AbstractDiagnosticGroup, DeprecationDiagnosticData>> { _, property ->
|
||||
val diagnostic = DiagnosticBuilder.Deprecation(
|
||||
containingObjectName,
|
||||
featureForError,
|
||||
name = property.name,
|
||||
psiType = typeOf<P>(),
|
||||
positioningStrategy,
|
||||
).apply(init).build()
|
||||
_diagnostics += diagnostic
|
||||
ReadOnlyProperty { _, _ -> diagnostic }
|
||||
}
|
||||
|
||||
@OptIn(PrivateForInline::class)
|
||||
operator fun plus(other: AbstractDiagnosticGroup): AbstractDiagnosticGroup {
|
||||
require(name == other.name)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
@@ -65,13 +66,52 @@ abstract class DiagnosticList(internal val objectName: String) {
|
||||
abstract inner class DiagnosticGroup(name: String) : AbstractDiagnosticGroup(name, objectName)
|
||||
}
|
||||
|
||||
class DiagnosticBuilder(
|
||||
private val containingObjectName: String,
|
||||
private val severity: Severity,
|
||||
private val name: String,
|
||||
private val psiType: KType,
|
||||
private val positioningStrategy: PositioningStrategy,
|
||||
sealed class DiagnosticBuilder(
|
||||
protected val containingObjectName: String,
|
||||
protected val name: String,
|
||||
protected val psiType: KType,
|
||||
protected val positioningStrategy: PositioningStrategy,
|
||||
) {
|
||||
class Regular(
|
||||
containingObjectName: String,
|
||||
private val severity: Severity,
|
||||
name: String,
|
||||
psiType: KType,
|
||||
positioningStrategy: PositioningStrategy,
|
||||
) : DiagnosticBuilder(containingObjectName, name, psiType, positioningStrategy) {
|
||||
@OptIn(PrivateForInline::class)
|
||||
override fun build(): RegularDiagnosticData {
|
||||
return RegularDiagnosticData(
|
||||
containingObjectName,
|
||||
severity,
|
||||
name,
|
||||
psiType,
|
||||
parameters,
|
||||
positioningStrategy,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class Deprecation(
|
||||
containingObjectName: String,
|
||||
private val featureForError: LanguageFeature,
|
||||
name: String,
|
||||
psiType: KType,
|
||||
positioningStrategy: PositioningStrategy,
|
||||
) : DiagnosticBuilder(containingObjectName, name, psiType, positioningStrategy) {
|
||||
@OptIn(PrivateForInline::class)
|
||||
override fun build(): DeprecationDiagnosticData {
|
||||
return DeprecationDiagnosticData(
|
||||
containingObjectName,
|
||||
featureForError,
|
||||
name,
|
||||
psiType,
|
||||
parameters,
|
||||
positioningStrategy,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@PrivateForInline
|
||||
val parameters = mutableListOf<DiagnosticParameter>()
|
||||
|
||||
@@ -86,15 +126,7 @@ class DiagnosticBuilder(
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(PrivateForInline::class)
|
||||
fun build() = DiagnosticData(
|
||||
containingObjectName,
|
||||
severity,
|
||||
name,
|
||||
psiType,
|
||||
parameters,
|
||||
positioningStrategy,
|
||||
)
|
||||
abstract fun build(): DiagnosticData
|
||||
|
||||
companion object {
|
||||
const val MAX_DIAGNOSTIC_PARAMETER_COUNT = 4
|
||||
|
||||
@@ -55,16 +55,21 @@ object ErrorListDiagnosticListRenderer : DiagnosticListRenderer() {
|
||||
private fun SmartPrinter.printDiagnostic(diagnostic: DiagnosticData) {
|
||||
print("val ${diagnostic.name} by ${diagnostic.getFactoryFunction()}")
|
||||
printTypeArguments(diagnostic.getAllTypeArguments())
|
||||
printPositioningStrategy(diagnostic)
|
||||
printPositioningStrategyAndLanguageFeature(diagnostic)
|
||||
println()
|
||||
}
|
||||
|
||||
private fun SmartPrinter.printPositioningStrategy(diagnostic: DiagnosticData) {
|
||||
print("(")
|
||||
if (!diagnostic.hasDefaultPositioningStrategy()) {
|
||||
print(diagnostic.positioningStrategy.expressionToCreate)
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun SmartPrinter.printPositioningStrategyAndLanguageFeature(diagnostic: DiagnosticData) {
|
||||
val argumentsList = buildList {
|
||||
if (diagnostic is DeprecationDiagnosticData) {
|
||||
add(diagnostic.featureForError.name)
|
||||
}
|
||||
if (!diagnostic.hasDefaultPositioningStrategy()) {
|
||||
add(diagnostic.positioningStrategy.expressionToCreate)
|
||||
}
|
||||
}
|
||||
print(")")
|
||||
print(argumentsList.joinToString(", ", prefix = "(", postfix = ")"))
|
||||
}
|
||||
|
||||
|
||||
@@ -124,14 +129,19 @@ object ErrorListDiagnosticListRenderer : DiagnosticListRenderer() {
|
||||
add(PositioningStrategy.importToAdd)
|
||||
}
|
||||
}
|
||||
for (deprecationDiagnostic in diagnosticList.allDiagnostics.filterIsInstance<DeprecationDiagnosticData>()) {
|
||||
add("org.jetbrains.kotlin.config.LanguageFeature.${deprecationDiagnostic.featureForError.name}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val KType.kClass: KClass<*>
|
||||
get() = classifier as KClass<*>
|
||||
|
||||
private fun DiagnosticData.getFactoryFunction(): String =
|
||||
severity.name.lowercase() + parameters.size
|
||||
private fun DiagnosticData.getFactoryFunction(): String = when (this) {
|
||||
is RegularDiagnosticData -> severity.name.lowercase()
|
||||
is DeprecationDiagnosticData -> "deprecationError"
|
||||
} + parameters.size
|
||||
}
|
||||
|
||||
private inline fun <T> SmartPrinter.printSeparatedWithComma(list: List<T>, printItem: (T) -> Unit) {
|
||||
|
||||
@@ -5,17 +5,35 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import kotlin.reflect.KType
|
||||
|
||||
data class DiagnosticData(
|
||||
val containingObjectName: String,
|
||||
sealed class DiagnosticData {
|
||||
abstract val containingObjectName: String
|
||||
abstract val name: String
|
||||
abstract val psiType: KType
|
||||
abstract val parameters: List<DiagnosticParameter>
|
||||
abstract val positioningStrategy: PositioningStrategy
|
||||
}
|
||||
|
||||
data class RegularDiagnosticData(
|
||||
override val containingObjectName: String,
|
||||
val severity: Severity,
|
||||
val name: String,
|
||||
val psiType: KType,
|
||||
val parameters: List<DiagnosticParameter>,
|
||||
val positioningStrategy: PositioningStrategy,
|
||||
)
|
||||
override val name: String,
|
||||
override val psiType: KType,
|
||||
override val parameters: List<DiagnosticParameter>,
|
||||
override val positioningStrategy: PositioningStrategy,
|
||||
) : DiagnosticData()
|
||||
|
||||
data class DeprecationDiagnosticData(
|
||||
override val containingObjectName: String,
|
||||
val featureForError: LanguageFeature,
|
||||
override val name: String,
|
||||
override val psiType: KType,
|
||||
override val parameters: List<DiagnosticParameter>,
|
||||
override val positioningStrategy: PositioningStrategy,
|
||||
) : DiagnosticData()
|
||||
|
||||
data class DiagnosticParameter(
|
||||
val name: String,
|
||||
@@ -77,9 +95,13 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
DATA_MODIFIER,
|
||||
SPREAD_OPERATOR,
|
||||
DECLARATION_WITH_BODY,
|
||||
NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT,
|
||||
INCOMPATIBLE_DECLARATION,
|
||||
ACTUAL_DECLARATION_NAME,
|
||||
|
||||
UNREACHABLE_CODE,
|
||||
INLINE_PARAMETER_MODIFIER,
|
||||
ABSTRACT_MODIFIER,
|
||||
LABEL,
|
||||
;
|
||||
|
||||
val expressionToCreate get() = "SourceElementPositioningStrategies.${strategy ?: name}"
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirJavaGenericVarianceViolationTypeChecker
|
||||
|
||||
object JvmExpressionCheckers : ExpressionCheckers() {
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
get() = setOf(
|
||||
FirJavaGenericVarianceViolationTypeChecker,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.argumentMapping
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.originalOrSelf
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.TypeApproximatorConfiguration
|
||||
import org.jetbrains.kotlin.types.model.TypeConstructorMarker
|
||||
import org.jetbrains.kotlin.types.model.typeConstructor
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
/**
|
||||
* Checks compatibility of variance of type argument for Java collections.
|
||||
*
|
||||
* Java collection interfaces all include methods mutating the collection. Hence, they naturally map to mutable versions of Kotlin
|
||||
* collections. But Kotlin provides immutable collections and it's good practice to enforce immutability when possible. Hence, to make it
|
||||
* easier to use immutable collections in Kotlin, Java collection types are instead mapped to flexible type with mutable collection as the
|
||||
* lower type and immutable collection as upper type. However, flexible types make type checking unsound. Hence we have this check that
|
||||
* catches a common mistake allowed by flexible type.
|
||||
*
|
||||
* Consider a Java method accepting type `List<Object>`, which is mapped to `MutableList<Any?>..List<(out) Any?>`. If one passes a mutable
|
||||
* list of some more concrete type than `Any` (ArrayList<String>, LinkedList<Int>, etc.) to this Java method, then any writes to this
|
||||
* mutable collection could cause `ClassCastException`s if the same mutable list is read elsewhere. It's the purpose of this checker to
|
||||
* reject such code.
|
||||
*
|
||||
* On the other hand, if one passes an immutable list of some more concrete type, then any writes to it on the Java side would cause
|
||||
* `UnsupportedOperationException`, which is expected and the price we pay in order to make immutable collection easier to use. This checker
|
||||
* doesn't do anything to prevent this from happening.
|
||||
*/
|
||||
object FirJavaGenericVarianceViolationTypeChecker : FirFunctionCallChecker() {
|
||||
private val javaOrigin = setOf(FirDeclarationOrigin.Java, FirDeclarationOrigin.Enhancement)
|
||||
|
||||
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val calleeFunction = expression.calleeReference.toResolvedCallableSymbol() as? FirFunctionSymbol<*> ?: return
|
||||
if (calleeFunction.originalOrSelf().origin !in javaOrigin) {
|
||||
return
|
||||
}
|
||||
val argumentMapping = expression.argumentMapping ?: return
|
||||
val typeArgumentMap = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>()
|
||||
for (i in 0 until expression.typeArguments.size) {
|
||||
val type = expression.typeArguments[i].safeAs<FirTypeProjectionWithVariance>()?.typeRef?.coneTypeSafe<ConeKotlinType>()
|
||||
if (type != null) {
|
||||
typeArgumentMap[calleeFunction.typeParameterSymbols[i]] = type
|
||||
}
|
||||
}
|
||||
val typeParameterSubstitutor = substitutorByMap(typeArgumentMap, context.session)
|
||||
for ((arg, param) in argumentMapping) {
|
||||
val expectedType = typeParameterSubstitutor.substituteOrSelf(param.returnTypeRef.coneType)
|
||||
|
||||
// optimization: if no arguments or flexibility, everything is OK
|
||||
if (expectedType !is ConeFlexibleType || expectedType.typeArguments.isEmpty()) continue
|
||||
|
||||
// Anything is acceptable for raw types
|
||||
if (expectedType is ConeRawType) continue
|
||||
|
||||
val argType = arg.typeRef.coneType
|
||||
|
||||
val lowerBound = expectedType.lowerBound
|
||||
val upperBound = expectedType.upperBound
|
||||
val typeCtx = context.session.inferenceComponents.ctx
|
||||
val lowerConstructor = lowerBound.typeConstructor(typeCtx)
|
||||
val upperConstructor = upperBound.typeConstructor(typeCtx)
|
||||
|
||||
// Use site variance projection is always the same for flexible types. So there is no need to check if declaration site is the
|
||||
// same.
|
||||
if (lowerConstructor == upperConstructor) continue
|
||||
|
||||
// If the base class of the argument type is not equal or a sub class of the lower bound, then we simply allow it so that
|
||||
// Kotlin immutable collections can be used in place of Java collection types.
|
||||
if (!typeCtx.isTypeConstructorEqualOrSubClassOf(argType, lowerBound)) continue
|
||||
|
||||
// In general, out type projection makes a mutable collection "readonly". A priori such a projected type is not a subtype of a
|
||||
// non-projected type because projection has "removed" the ability to write to this collection. But for the purpose of this
|
||||
// checker, we don't care about the readability/writability of collections.
|
||||
//
|
||||
// More importantly, removing such out projection is a
|
||||
// shortcut to make this type comparable with the expected type by the function (after removing type capturing below). Consider
|
||||
// the code below (here we use kotlin code in the example, but the same idea applies to calls to Java methods as well)
|
||||
//
|
||||
// ```
|
||||
// fun get(): MutableList<out String> = ...
|
||||
// fun <T> take(l: MutableList<T>) = ...
|
||||
// fun test() {
|
||||
// take(get())
|
||||
// }
|
||||
// ```
|
||||
//
|
||||
// The type of `get()` is `MutableList<out String>`. After type parameter instantiation, `take` takes a
|
||||
// `MutableList<Captured<out String>>`. Obviously, a `MutableList<out String>` is not a subtype of `MutableList<Captured<out
|
||||
// String>>` because we have lost the identity of the captured type at this point: we no longer know that the captured type is
|
||||
// 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 lowerBoundWithoutCapturing = context.session.inferenceComponents.approximator.approximateToSuperType(
|
||||
lowerBound,
|
||||
TypeApproximatorConfiguration.FinalApproximationAfterResolutionAndInference
|
||||
) ?: lowerBound
|
||||
|
||||
if (!AbstractTypeChecker.isSubtypeOf(
|
||||
typeCtx,
|
||||
argTypeWithoutOutProjection,
|
||||
lowerBoundWithoutCapturing.withNullability(ConeNullability.NULLABLE, typeCtx)
|
||||
)
|
||||
) {
|
||||
reporter.reportOn(arg.source, FirErrors.JAVA_TYPE_MISMATCH, expectedType, argType, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.removeOutProjection(positive: Boolean): ConeKotlinType {
|
||||
return when (this) {
|
||||
is ConeFlexibleType -> ConeFlexibleType(lowerBound.removeOutProjection(positive), upperBound.removeOutProjection(positive))
|
||||
is ConeCapturedType -> ConeCapturedType(
|
||||
captureStatus,
|
||||
lowerType?.removeOutProjection(positive),
|
||||
nullability,
|
||||
constructor.apply {
|
||||
ConeCapturedTypeConstructor(
|
||||
projection.removeOutProjection(positive),
|
||||
supertypes?.map { it.removeOutProjection(positive) },
|
||||
typeParameterMarker
|
||||
)
|
||||
},
|
||||
attributes,
|
||||
isProjectionNotNull
|
||||
)
|
||||
is ConeDefinitelyNotNullType -> ConeDefinitelyNotNullType(original.removeOutProjection(positive))
|
||||
is ConeIntersectionType -> ConeIntersectionType(
|
||||
intersectedTypes.map { it.removeOutProjection(positive) },
|
||||
alternativeType?.removeOutProjection(positive)
|
||||
)
|
||||
is ConeClassLikeTypeImpl -> ConeClassLikeTypeImpl(
|
||||
lookupTag,
|
||||
typeArguments.map { it.removeOutProjection(positive) }.toTypedArray(),
|
||||
isNullable,
|
||||
attributes
|
||||
)
|
||||
else -> this
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeTypeProjection.removeOutProjection(positive: Boolean): ConeTypeProjection {
|
||||
return when (this) {
|
||||
is ConeKotlinTypeProjectionOut -> if (positive) type else this
|
||||
is ConeKotlinTypeProjectionIn -> ConeKotlinTypeProjectionIn(type.removeOutProjection(!positive))
|
||||
// Don't remove nested projections for types at invariant position.
|
||||
is ConeKotlinTypeConflictingProjection,
|
||||
is ConeKotlinType,
|
||||
is ConeStarProjection -> this
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeInferenceContext.isTypeConstructorEqualOrSubClassOf(subType: ConeKotlinType, superType: ConeKotlinType): Boolean {
|
||||
return isTypeConstructorEqualOrSubClassOf(subType.typeConstructor(), superType.typeConstructor())
|
||||
}
|
||||
|
||||
private fun ConeInferenceContext.isTypeConstructorEqualOrSubClassOf(
|
||||
subTypeConstructor: TypeConstructorMarker,
|
||||
superTypeConstructor: TypeConstructorMarker
|
||||
): Boolean {
|
||||
if (subTypeConstructor == superTypeConstructor) return true
|
||||
for (immediateSuperType in subTypeConstructor.supertypes()) {
|
||||
val immediateSuperTypeConstructor = immediateSuperType.typeConstructor()
|
||||
if (superTypeConstructor == immediateSuperTypeConstructor) return true
|
||||
if (this@isTypeConstructorEqualOrSubClassOf.isTypeConstructorEqualOrSubClassOf(immediateSuperTypeConstructor, superTypeConstructor)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,18 @@ 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.ProhibitInvisibleAbstractMethodsInSuperclasses
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.RestrictRetentionForExpressionAnnotations
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.RestrictionOfValReassignmentViaBackingField
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.SourceElementPositioningStrategies
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
@@ -32,7 +38,6 @@ 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.CallableId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
@@ -66,6 +71,7 @@ import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtPropertyAccessor
|
||||
import org.jetbrains.kotlin.psi.KtReturnExpression
|
||||
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||
import org.jetbrains.kotlin.psi.KtSuperExpression
|
||||
import org.jetbrains.kotlin.psi.KtTypeAlias
|
||||
import org.jetbrains.kotlin.psi.KtTypeParameter
|
||||
import org.jetbrains.kotlin.psi.KtTypeProjection
|
||||
@@ -118,12 +124,11 @@ object FirErrors {
|
||||
val VAL_OR_VAR_ON_FUN_PARAMETER by warning1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
||||
val VAL_OR_VAR_ON_CATCH_PARAMETER by warning1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
||||
val VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER by warning1<KtParameter, KtKeywordToken>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
|
||||
val INVISIBLE_SETTER by error3<PsiElement, FirPropertySymbol, Visibility, CallableId>(SourceElementPositioningStrategies.ASSIGNMENT_LHS)
|
||||
|
||||
// Unresolved
|
||||
val INVISIBLE_REFERENCE by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val UNRESOLVED_REFERENCE by error1<PsiElement, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val UNRESOLVED_LABEL by error0<PsiElement>()
|
||||
val UNRESOLVED_LABEL by error0<PsiElement>(SourceElementPositioningStrategies.LABEL)
|
||||
val DESERIALIZATION_ERROR by error0<PsiElement>()
|
||||
val ERROR_FROM_JAVA_RESOLUTION by error0<PsiElement>()
|
||||
val MISSING_STDLIB_CLASS by error0<PsiElement>()
|
||||
@@ -147,6 +152,7 @@ object FirErrors {
|
||||
|
||||
// Supertypes
|
||||
val NOT_A_SUPERTYPE by error0<PsiElement>()
|
||||
val TYPE_ARGUMENTS_REDUNDANT_IN_SUPER_QUALIFIER by warning0<KtElement>()
|
||||
val SUPERCLASS_NOT_ACCESSIBLE_FROM_INTERFACE by error0<PsiElement>()
|
||||
val QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE by error1<KtTypeReference, FirBasedSymbol<*>>()
|
||||
val SUPERTYPE_INITIALIZED_IN_INTERFACE by error0<KtTypeReference>()
|
||||
@@ -167,6 +173,7 @@ object FirErrors {
|
||||
val PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VARIANCE_MODIFIER)
|
||||
val INCONSISTENT_TYPE_PARAMETER_VALUES by error3<KtClass, FirTypeParameterSymbol, FirRegularClassSymbol, Collection<ConeKotlinType>>(SourceElementPositioningStrategies.SUPERTYPES_LIST)
|
||||
val INCONSISTENT_TYPE_PARAMETER_BOUNDS by error3<PsiElement, FirTypeParameterSymbol, FirRegularClassSymbol, Collection<ConeKotlinType>>()
|
||||
val AMBIGUOUS_SUPER by error0<KtSuperExpression>()
|
||||
|
||||
// Constructor problems
|
||||
val CONSTRUCTOR_IN_OBJECT by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
@@ -209,8 +216,8 @@ object FirErrors {
|
||||
val DEPRECATED_SINCE_KOTLIN_WITHOUT_DEPRECATED by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val DEPRECATED_SINCE_KOTLIN_WITH_DEPRECATED_LEVEL by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val DEPRECATED_SINCE_KOTLIN_OUTSIDE_KOTLIN_SUBPACKAGE by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val ANNOTATION_ON_SUPERCLASS by error0<KtAnnotationEntry>()
|
||||
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by error0<PsiElement>()
|
||||
val ANNOTATION_ON_SUPERCLASS by deprecationError0<KtAnnotationEntry>(ProhibitUseSiteTargetAnnotationsOnSuperTypes)
|
||||
val RESTRICTED_RETENTION_FOR_EXPRESSION_ANNOTATION by deprecationError0<PsiElement>(RestrictRetentionForExpressionAnnotations)
|
||||
val WRONG_ANNOTATION_TARGET by error1<KtAnnotationEntry, String>()
|
||||
val WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET by error2<KtAnnotationEntry, String, String>()
|
||||
val INAPPLICABLE_TARGET_ON_PROPERTY by error1<KtAnnotationEntry, String>()
|
||||
@@ -326,8 +333,7 @@ object FirErrors {
|
||||
val INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS by error0<KtClassOrObject>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val KCLASS_WITH_NULLABLE_TYPE_PARAMETER_IN_SIGNATURE by error1<KtNamedDeclaration, FirTypeParameterSymbol>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val TYPE_PARAMETER_AS_REIFIED by error1<PsiElement, FirTypeParameterSymbol>()
|
||||
val TYPE_PARAMETER_AS_REIFIED_ARRAY by error1<PsiElement, FirTypeParameterSymbol>()
|
||||
val TYPE_PARAMETER_AS_REIFIED_ARRAY_WARNING by warning1<PsiElement, FirTypeParameterSymbol>()
|
||||
val TYPE_PARAMETER_AS_REIFIED_ARRAY by deprecationError1<PsiElement, FirTypeParameterSymbol>(ProhibitNonReifiedArraysAsReifiedTypeArguments)
|
||||
val REIFIED_TYPE_FORBIDDEN_SUBSTITUTION by error1<PsiElement, ConeKotlinType>()
|
||||
val FINAL_UPPER_BOUND by warning1<KtTypeReference, ConeKotlinType>()
|
||||
val UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE by error0<KtTypeReference>()
|
||||
@@ -375,8 +381,7 @@ object FirErrors {
|
||||
val CONFLICTING_INHERITED_MEMBERS by error1<KtClassOrObject, List<FirCallableSymbol<*>>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val ABSTRACT_MEMBER_NOT_IMPLEMENTED by error2<KtClassOrObject, FirClassSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED by error2<KtClassOrObject, FirClassSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by error2<KtClassOrObject, FirClassSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING by warning2<KtClassOrObject, FirClassSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER by deprecationError2<KtClassOrObject, FirClassSymbol<*>, FirCallableSymbol<*>>(ProhibitInvisibleAbstractMethodsInSuperclasses, SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val MANY_IMPL_MEMBER_NOT_IMPLEMENTED by error2<KtClassOrObject, FirClassSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED by error2<KtClassOrObject, FirClassSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val OVERRIDING_FINAL_MEMBER_BY_DELEGATION by error2<KtClassOrObject, FirCallableSymbol<*>, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
@@ -392,7 +397,8 @@ object FirErrors {
|
||||
// Redeclarations
|
||||
val MANY_COMPANION_OBJECTS by error0<KtObjectDeclaration>(SourceElementPositioningStrategies.COMPANION_OBJECT)
|
||||
val CONFLICTING_OVERLOADS by error1<PsiElement, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val REDECLARATION by error1<PsiElement, Collection<FirBasedSymbol<*>>>()
|
||||
val REDECLARATION by error1<KtNamedDeclaration, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
|
||||
val PACKAGE_OR_CLASSIFIER_REDECLARATION by error1<KtNamedDeclaration, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.ACTUAL_DECLARATION_NAME)
|
||||
val METHOD_OF_ANY_IMPLEMENTED_IN_INTERFACE by error0<PsiElement>()
|
||||
|
||||
// Invalid local declarations
|
||||
@@ -455,6 +461,7 @@ object FirErrors {
|
||||
val WRONG_SETTER_RETURN_TYPE by error0<KtTypeReference>()
|
||||
val WRONG_GETTER_RETURN_TYPE by error2<KtTypeReference, ConeKotlinType, ConeKotlinType>()
|
||||
val ACCESSOR_FOR_DELEGATED_PROPERTY by error0<KtPropertyAccessor>()
|
||||
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error0<KtModifierListOwner>(SourceElementPositioningStrategies.ABSTRACT_MODIFIER)
|
||||
|
||||
// Multi-platform projects
|
||||
val EXPECTED_DECLARATION_WITH_BODY by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
@@ -495,8 +502,7 @@ object FirErrors {
|
||||
val UNINITIALIZED_ENUM_ENTRY by error1<KtSimpleNameExpression, FirEnumEntrySymbol>()
|
||||
val UNINITIALIZED_ENUM_COMPANION by error1<KtSimpleNameExpression, FirRegularClassSymbol>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val VAL_REASSIGNMENT by error1<KtExpression, FirVariableSymbol<*>>()
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD by warning1<KtExpression, FirBackingFieldSymbol>()
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR by error1<KtExpression, FirBackingFieldSymbol>()
|
||||
val VAL_REASSIGNMENT_VIA_BACKING_FIELD by deprecationError1<KtExpression, FirBackingFieldSymbol>(RestrictionOfValReassignmentViaBackingField)
|
||||
val CAPTURED_VAL_INITIALIZATION by error1<KtExpression, FirPropertySymbol>()
|
||||
val CAPTURED_MEMBER_VAL_INITIALIZATION by error1<KtExpression, FirPropertySymbol>()
|
||||
val SETTER_PROJECTED_OUT by error1<KtBinaryExpression, FirPropertySymbol>(SourceElementPositioningStrategies.ASSIGNMENT_LHS)
|
||||
@@ -505,6 +511,9 @@ object FirErrors {
|
||||
val WRONG_IMPLIES_CONDITION by warning0<PsiElement>()
|
||||
val VARIABLE_WITH_NO_TYPE_NO_INITIALIZER by error0<KtVariableDeclaration>(SourceElementPositioningStrategies.DECLARATION_NAME)
|
||||
val INITIALIZATION_BEFORE_DECLARATION by error1<KtExpression, FirBasedSymbol<*>>()
|
||||
val UNREACHABLE_CODE by warning2<KtElement, Set<FirSourceElement>, Set<FirSourceElement>>(SourceElementPositioningStrategies.UNREACHABLE_CODE)
|
||||
val SENSELESS_COMPARISON by warning2<KtExpression, FirExpression, Boolean>()
|
||||
val SENSELESS_NULL_IN_WHEN by warning0<KtElement>()
|
||||
|
||||
// Nullability
|
||||
val UNSAFE_CALL by error2<PsiElement, ConeKotlinType, FirExpression?>(SourceElementPositioningStrategies.DOT_BY_QUALIFIED)
|
||||
@@ -596,6 +605,9 @@ object FirErrors {
|
||||
// Inline
|
||||
val USAGE_IS_NOT_INLINABLE by error1<KtElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val NON_LOCAL_RETURN_NOT_ALLOWED by error1<KtElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val NOT_YET_SUPPORTED_IN_INLINE by error1<KtDeclaration, String>(SourceElementPositioningStrategies.NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT)
|
||||
val NOTHING_TO_INLINE by warning0<KtDeclaration>(SourceElementPositioningStrategies.NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT)
|
||||
val NULLABLE_INLINE_PARAMETER by error2<KtDeclaration, FirValueParameterSymbol, FirBasedSymbol<*>>()
|
||||
val RECURSION_IN_INLINE by error1<KtElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val NON_PUBLIC_CALL_FROM_PUBLIC_INLINE by error2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE by error2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
@@ -603,6 +615,15 @@ object FirErrors {
|
||||
val PROTECTED_CALL_FROM_PUBLIC_INLINE by warning2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val PRIVATE_CLASS_MEMBER_FROM_INLINE by error2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val SUPER_CALL_FROM_PUBLIC_INLINE by warning1<KtElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val DECLARATION_CANT_BE_INLINED by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val OVERRIDE_BY_INLINE by warning0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val NON_INTERNAL_PUBLISHED_API by error0<KtElement>()
|
||||
val INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE by error2<KtElement, FirExpression, FirValueParameterSymbol>()
|
||||
val REIFIED_TYPE_PARAMETER_IN_OVERRIDE by error0<KtElement>(SourceElementPositioningStrategies.REIFIED_MODIFIER)
|
||||
val INLINE_PROPERTY_WITH_BACKING_FIELD by error0<KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val ILLEGAL_INLINE_PARAMETER_MODIFIER by error0<KtElement>(SourceElementPositioningStrategies.INLINE_PARAMETER_MODIFIER)
|
||||
val INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED by error0<KtParameter>()
|
||||
val REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE by warning0<KtElement>(SourceElementPositioningStrategies.SUSPEND_MODIFIER)
|
||||
|
||||
// Imports
|
||||
val CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON by error1<KtImportDirective, Name>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
|
||||
@@ -620,4 +641,7 @@ 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>()
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.fir.declarations.utils.isLateInit
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.referredPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.cfg.*
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
|
||||
@@ -56,6 +56,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirPropertyTypeParametersChecker,
|
||||
FirInitializerTypeMismatchChecker,
|
||||
FirDelegatedPropertyChecker,
|
||||
FirInlinePropertyChecker,
|
||||
FirPropertyFromParameterChecker,
|
||||
)
|
||||
|
||||
override val classCheckers: Set<FirClassChecker>
|
||||
@@ -129,6 +131,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
override val annotatedDeclarationCheckers: Set<FirAnnotatedDeclarationChecker>
|
||||
get() = setOf(
|
||||
FirAnnotationChecker,
|
||||
FirPublishedApiChecker,
|
||||
)
|
||||
|
||||
override val typeAliasCheckers: Set<FirTypeAliasChecker>
|
||||
|
||||
@@ -29,8 +29,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
|
||||
get() = setOf(
|
||||
FirCallableReferenceChecker,
|
||||
FirSuperNotAvailableChecker,
|
||||
FirNotASupertypeChecker,
|
||||
FirSuperReferenceChecker,
|
||||
FirSuperclassNotAccessibleFromInterfaceChecker,
|
||||
FirAbstractSuperCallChecker,
|
||||
FirQualifiedSupertypeExtendedByOtherSupertypeChecker,
|
||||
@@ -60,7 +59,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
|
||||
override val variableAssignmentCheckers: Set<FirVariableAssignmentChecker>
|
||||
get() = setOf(
|
||||
FirReassignmentAndInvisibleSetterChecker,
|
||||
FirValReassignmentChecker,
|
||||
FirAssignmentTypeMismatchChecker
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.analysis.checkers
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.isPrimitiveType
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
@@ -63,7 +62,23 @@ internal object ConeTypeCompatibilityChecker {
|
||||
HARD_INCOMPATIBLE,
|
||||
}
|
||||
|
||||
fun Collection<ConeKotlinType>.areCompatible(ctx: ConeInferenceContext): Compatibility {
|
||||
fun ConeInferenceContext.isCompatible(a: ConeKotlinType, b: ConeKotlinType): Compatibility {
|
||||
val aUnwrap = unwrap(a)
|
||||
val bUnwrap = unwrap(b)
|
||||
if (aUnwrap.containsAll(bUnwrap) || bUnwrap.containsAll(aUnwrap)) {
|
||||
return Compatibility.COMPATIBLE
|
||||
}
|
||||
|
||||
val intersectionType = intersectTypesOrNull(listOf(a, b)) as? ConeIntersectionType ?: return Compatibility.COMPATIBLE
|
||||
return intersectionType.intersectedTypes.areCompatible(this)
|
||||
}
|
||||
|
||||
private fun unwrap(type: ConeKotlinType): Collection<ConeKotlinType> = when (type) {
|
||||
is ConeIntersectionType -> type.intersectedTypes
|
||||
else -> listOf(type)
|
||||
}
|
||||
|
||||
private fun Collection<ConeKotlinType>.areCompatible(ctx: ConeInferenceContext): Compatibility {
|
||||
// If all types are nullable, then `null` makes the given types compatible.
|
||||
if (all { with(ctx) { it.isNullableType() } }) return Compatibility.COMPATIBLE
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ object ExtendedDeclarationCheckers : DeclarationCheckers() {
|
||||
override val controlFlowAnalyserCheckers: Set<FirControlFlowChecker>
|
||||
get() = setOf(
|
||||
UnusedChecker,
|
||||
UnreachableCodeChecker,
|
||||
)
|
||||
|
||||
override val simpleFunctionCheckers: Set<FirSimpleFunctionChecker>
|
||||
|
||||
@@ -142,7 +142,7 @@ interface FirDeclarationPresenter {
|
||||
appendRepresentation(it.returnTypeRef)
|
||||
}
|
||||
|
||||
fun represent(it: FirProperty) = buildString {
|
||||
fun represent(it: FirVariable) = buildString {
|
||||
append('[')
|
||||
it.receiverTypeRef?.let {
|
||||
appendRepresentation(it)
|
||||
@@ -241,7 +241,7 @@ open class FirDeclarationInspector(
|
||||
declaration is FirSimpleFunction -> collectFunction(presenter.represent(declaration), declaration)
|
||||
declaration is FirRegularClass -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
declaration is FirTypeAlias -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
declaration is FirProperty -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
declaration is FirVariable -> collectNonFunctionDeclaration(presenter.represent(declaration), declaration)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
@@ -18,7 +19,7 @@ fun checkUnderscoreDiagnostics(
|
||||
reporter: DiagnosticReporter,
|
||||
isExpression: Boolean
|
||||
) {
|
||||
if (source != null && source.kind !is FirFakeSourceElementKind) {
|
||||
if (source != null && (source.kind is FirRealSourceElementKind || source.kind is FirFakeSourceElementKind.ReferenceInAtomicQualifiedAccess)) {
|
||||
with(SourceNavigator.forSource(source)) {
|
||||
if (source.getRawIdentifier()?.isUnderscore == true) {
|
||||
reporter.reportOn(
|
||||
|
||||
@@ -53,6 +53,15 @@ abstract class CheckerContext {
|
||||
|
||||
abstract fun dropDeclaration()
|
||||
|
||||
fun <T> withDeclaration(declaration: FirDeclaration, f: (CheckerContext) -> T): T {
|
||||
val newContext = addDeclaration(declaration)
|
||||
try {
|
||||
return f(newContext)
|
||||
} finally {
|
||||
newContext.dropDeclaration()
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun addQualifiedAccessOrAnnotationCall(qualifiedAccessOrAnnotationCall: FirStatement): CheckerContext
|
||||
|
||||
abstract fun dropQualifiedAccessOrAnnotationCall()
|
||||
|
||||
@@ -13,7 +13,9 @@ 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.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.impl.FirOuterClassTypeParameterRef
|
||||
import org.jetbrains.kotlin.fir.resolve.firProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.getOuterClass
|
||||
import org.jetbrains.kotlin.fir.scopes.PACKAGE_MEMBER
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
@@ -21,6 +23,7 @@ import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.ensureResolved
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.util.ListMultimap
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -197,7 +200,8 @@ object FirConflictsChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
if (declarationName != null) {
|
||||
session.lookupTracker?.recordLookup(
|
||||
@@ -213,17 +217,89 @@ object FirConflictsChecker : FirBasicDeclarationChecker() {
|
||||
when (declaration) {
|
||||
is FirFile -> checkFile(declaration, inspector, context)
|
||||
is FirRegularClass -> checkRegularClass(declaration, inspector)
|
||||
else -> return
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
|
||||
inspector.declarationConflictingSymbols.forEach { (declaration, symbols) ->
|
||||
when {
|
||||
symbols.isEmpty() -> {}
|
||||
declaration is FirSimpleFunction || declaration is FirConstructor -> {
|
||||
reporter.reportOn(declaration.source, FirErrors.CONFLICTING_OVERLOADS, symbols, context)
|
||||
inspector.declarationConflictingSymbols.forEach { (conflictingDeclaration, symbols) ->
|
||||
val source = conflictingDeclaration.source
|
||||
if (source != null && symbols.isNotEmpty()) {
|
||||
when (conflictingDeclaration) {
|
||||
is FirSimpleFunction,
|
||||
is FirConstructor -> {
|
||||
reporter.reportOn(source, FirErrors.CONFLICTING_OVERLOADS, symbols, context)
|
||||
}
|
||||
else -> {
|
||||
val factory = if (conflictingDeclaration is FirClassLikeDeclaration &&
|
||||
getOuterClass(conflictingDeclaration, context.session) == null &&
|
||||
symbols.any { it is FirClassLikeSymbol<*> }
|
||||
) {
|
||||
FirErrors.PACKAGE_OR_CLASSIFIER_REDECLARATION
|
||||
} else {
|
||||
FirErrors.REDECLARATION
|
||||
}
|
||||
reporter.reportOn(source, factory, symbols, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (declaration.source?.kind !is FirFakeSourceElementKind) {
|
||||
when (declaration) {
|
||||
is FirMemberDeclaration -> {
|
||||
if (declaration is FirFunction) {
|
||||
checkConflictingParameters(declaration.valueParameters, context, reporter)
|
||||
}
|
||||
checkConflictingParameters(declaration.typeParameters, context, reporter)
|
||||
}
|
||||
is FirTypeParametersOwner -> {
|
||||
checkConflictingParameters(declaration.typeParameters, context, reporter)
|
||||
}
|
||||
else -> {
|
||||
reporter.reportOn(declaration.source, FirErrors.REDECLARATION, symbols, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkConflictingParameters(parameters: List<FirElement>, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (parameters.size <= 1) return
|
||||
|
||||
val multimap = ListMultimap<Name, FirBasedSymbol<*>>()
|
||||
for (parameter in parameters) {
|
||||
val name: Name
|
||||
val symbol: FirBasedSymbol<*>
|
||||
when (parameter) {
|
||||
is FirValueParameter -> {
|
||||
symbol = parameter.symbol
|
||||
name = parameter.name
|
||||
}
|
||||
is FirOuterClassTypeParameterRef -> {
|
||||
continue
|
||||
}
|
||||
is FirTypeParameterRef -> {
|
||||
symbol = parameter.symbol
|
||||
name = symbol.name
|
||||
}
|
||||
is FirTypeParameter -> {
|
||||
symbol = parameter.symbol
|
||||
name = parameter.name
|
||||
}
|
||||
else -> throw AssertionError("Invalid parameter type")
|
||||
}
|
||||
if (!name.isSpecial) {
|
||||
multimap.put(name, symbol)
|
||||
}
|
||||
}
|
||||
for (key in multimap.keys) {
|
||||
val conflictingParameters = multimap[key]
|
||||
if (conflictingParameters.size > 1) {
|
||||
for (parameter in conflictingParameters) {
|
||||
reporter.reportOn(
|
||||
parameter.source,
|
||||
FirErrors.REDECLARATION,
|
||||
conflictingParameters,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user