Compare commits

...

71 Commits

Author SHA1 Message Date
Nikita Bobko
f4fad5609f Make it possible to attach platforms with different versions to kotlin repo 2021-04-30 18:54:10 +02:00
Nikita Bobko
34c46f9c3f [cleanup] Remove unused variable 2021-04-30 18:54:10 +02:00
Nikita Bobko
baf3902bbb Create 'installIdeArtifacts' task
This task is used for cooperative compilation with intellij
2021-04-28 15:17:20 +02:00
Nikita Bobko
709be26895 [kotlin + intellij combined] Add one more artifact url
This commit fixes:
```
* What went wrong:
Execution failed for task ':kotlin-ide.intellij.platform.testExtensions:compileKotlin'.
> Could not resolve all files for configuration ':kotlin-ide.intellij.platform.testExtensions:compileClasspath'.
   > Could not find intellij-core-analysis-deprecated-202.7660.26.jar (kotlin.build:ideaIC:202.7660.26).
     Searched in the following locations:
         file:/home/bobko/.gradle/kotlin-build-dependencies/repo/kotlin.build/ideaIC/202.7660.26/artifacts/lib/intellij-core-analysis-deprecated.jar
         file:/home/bobko/.gradle/kotlin-build-dependencies/repo/kotlin.build/ideaIC/202.7660.26/artifacts/intellij-core-analysis-deprecated.jar
         file:/home/bobko/.gradle/kotlin-build-dependencies/repo/kotlin.build/ideaIC/202.7660.26/artifacts/plugins/ideaIC/lib/intellij-core-analysis-deprecated.jar
         file:/home/bobko/.gradle/kotlin-build-dependencies/repo/kotlin.build/sources/intellij-core-analysis-deprecated-202.7660.26.jar
         file:/home/bobko/.gradle/kotlin-build-dependencies/repo/kotlin.build/ideaIC/202.7660.26/intellij-core-analysis-deprecated.jar
```
2021-04-26 21:13:41 +02:00
Nikita Bobko
d3cfa76c55 build.gradle.kts: exclude :kotlin-ide from allprojects 2021-04-26 21:08:11 +02:00
Nikita Bobko
11e4f177b8 Temporarily disable JVM IR until KT-45697 is fixed 2021-04-26 21:08:11 +02:00
Nikita Bobko
b178f16823 Initial implementation of kotlin + intellij combined repo 2021-04-26 21:07:53 +02:00
Nikita Bobko
c2df1656a2 TEMPORARILY! Fix gradle import
It is not fully supported to define distributionSha256Sum in gradle/wrapper/gradle-wrapper.properties.
Using an incorrect value may freeze or crash Android Studio.
Please manually verify or remove this property from all of included projects if applicable.
For more details, see https://github.com/gradle/gradle/issues/9361.
Use "8ad577590..." as checksum for https://services.gradle.org/distributions/gradle-6.7-bin.zip and sync project
Remove distributionSha256Sum and sync project
Open Gradle wrapper properties
2021-04-26 21:06:59 +02:00
Nikita Bobko
c1e8397554 Cleanup GenerateTests: remove tests related to Kotlin plugin 2021-04-26 21:06:59 +02:00
Nikita Bobko
21d7a83405 Remove :idea:idea-fir-performance-tests module 2021-04-26 21:06:58 +02:00
Nikita Bobko
e6cbd848e7 Remove :plugins:parcelize:parcelize-ide module 2021-04-26 21:06:58 +02:00
Nikita Bobko
c5f4680ddb TEMPORARILY! Temporarily disable ':kotlin-scripting-ide-services-unshaded' module from build
This module should leave as part of Kotlin repo not part of kotlin-ide repo.
But unfortunatelly, it depends on ide-common which is part of kotlin-ide repo.
2021-04-26 21:06:49 +02:00
Nikita Bobko
28e9db1a89 Remove :prepare:ide-lazy-resolver module 2021-04-26 20:56:36 +02:00
Nikita Bobko
055e3189d0 Remove :prepare:formatter module 2021-04-26 20:56:36 +02:00
Nikita Bobko
aea7cfcf44 Remove kotlin-ide related code 2021-04-26 20:56:36 +02:00
Nikita Bobko
1eb1fb768c Remove :prepare:idea-plugin module 2021-04-26 20:56:36 +02:00
Nikita Bobko
a03bbef270 Remove :idea module usages in remaining modules 2021-04-26 20:56:36 +02:00
Nikita Bobko
931e51457e Remove :idea module 2021-04-26 20:56:36 +02:00
Nikita Bobko
e00c8c60f1 Remove :idea:line-indent-provider module 2021-04-26 20:56:35 +02:00
Nikita Bobko
bd299d7240 Remove :idea:idea-frontend-independent module 2021-04-26 20:56:35 +02:00
Nikita Bobko
e485f27928 Remove :idea:idea-frontend-api module 2021-04-26 20:56:34 +02:00
Nikita Bobko
12e6508fe2 Remove :plugins:android-extensions-ide module 2021-04-26 20:56:34 +02:00
Nikita Bobko
e0b55b79a0 Remove :idea:idea-test-framework module 2021-04-26 20:56:34 +02:00
Nikita Bobko
019344f901 Remove :idea:idea-android module 2021-04-26 20:56:34 +02:00
Nikita Bobko
e781192aeb Remove :kotlin-scripting-ide-services module 2021-04-26 20:56:34 +02:00
Nikita Bobko
03ce1f4156 Remove :kotlin-jps-plugin module 2021-04-26 20:56:33 +02:00
Nikita Bobko
07859c8588 Remove :idea-runner module 2021-04-26 20:56:33 +02:00
Nikita Bobko
2efeb1ca88 Remove :kotlin-scripting-intellij module 2021-04-26 20:56:33 +02:00
Nikita Bobko
9fc468bb80 Remove :libraries:tools:new-project-wizard module 2021-04-26 20:56:33 +02:00
Nikita Bobko
c098e8ca88 Remove :libraries:tools:new-project-wizard:new-project-wizard-cli module 2021-04-26 20:56:33 +02:00
Nikita Bobko
ade506258c Remove :j2k module 2021-04-26 20:56:32 +02:00
Nikita Bobko
585a4b5ef5 Remove :nj2k module 2021-04-26 20:56:32 +02:00
Nikita Bobko
4a875aabad Remove :jps-plugin module 2021-04-26 20:56:32 +02:00
Nikita Bobko
3447d0776e Remove :idea:formatter module 2021-04-26 20:56:32 +02:00
Nikita Bobko
b460bd2b1a Remove :idea:scripting-support module 2021-04-26 20:56:31 +02:00
Nikita Bobko
81f64beff6 Remove :idea:kotlin-gradle-tooling module 2021-04-26 20:56:31 +02:00
Nikita Bobko
729f707f99 Remove :kotlinx-serialization-ide-plugin plugin 2021-04-26 20:56:31 +02:00
Nikita Bobko
ddfe9ec54e Remove :kotlin-scripting-idea module 2021-04-19 14:19:06 +02:00
Nikita Bobko
2b8f37bd5b Remove :noarg-ide-plugin module 2021-04-19 14:19:06 +02:00
Nikita Bobko
887eeccc5f Remove :plugins:kapt3-idea module 2021-04-19 14:19:05 +02:00
Nikita Bobko
1f1a9b5b5b Remove :plugins:annotation-based-compiler-plugins-ide-support module 2021-04-19 14:19:05 +02:00
Nikita Bobko
2dfd2bfaa9 Remove :allopen-ide-plugin module 2021-04-19 14:19:05 +02:00
Nikita Bobko
42272cf021 Remove idea/idea-live-templates dir 2021-04-19 14:19:05 +02:00
Nikita Bobko
0d586c7281 Remove :idea:jvm-debugger:jvm-debugger-test module 2021-04-19 14:19:04 +02:00
Nikita Bobko
92bd630ceb Remove :idea:jvm-debugger:jvm-debugger-sequence module 2021-04-19 14:19:04 +02:00
Nikita Bobko
8c401e863e Remove :idea:jvm-debugger:jvm-debugger-evaluation module 2021-04-19 14:19:04 +02:00
Nikita Bobko
ca9edeacc9 Remove :idea:jvm-debugger:jvm-debugger-coroutine module 2021-04-19 14:19:04 +02:00
Nikita Bobko
70662828cd Remove :idea:jvm-debugger:jvm-debugger-core module 2021-04-19 14:19:04 +02:00
Nikita Bobko
8697f1fc50 Remove :idea:jvm-debugger:jvm-debugger-util module 2021-04-19 14:19:03 +02:00
Nikita Bobko
6a126f2698 Remove :idea:jvm-debugger:eval4j module 2021-04-19 14:19:03 +02:00
Nikita Bobko
a63c99664f Remove idea/idea-repl dir 2021-04-19 14:19:03 +02:00
Nikita Bobko
046b14f796 Remove :idea:performanceTests module 2021-04-19 14:19:03 +02:00
Nikita Bobko
cc6e420bbd Remove :idea:idea-new-project-wizard 2021-04-19 14:19:02 +02:00
Nikita Bobko
d9dd998417 Remove idea-analysis module 2021-04-19 14:19:02 +02:00
Nikita Bobko
74c25e447c Remove :idea:idea-jps-common module 2021-04-19 14:19:02 +02:00
Nikita Bobko
bb22051d8b Remove :sam-with-receiver-ide-plugin module 2021-04-19 14:19:02 +02:00
Nikita Bobko
7d87491915 Remove :plugins:uast-kotlin-idea module 2021-04-19 14:19:02 +02:00
Nikita Bobko
e1961e77e8 Remove :plugins:uast-kotlin module 2021-04-19 14:19:01 +02:00
Nikita Bobko
8507172c60 Remove :nj2k:nj2k-services module 2021-04-19 14:19:01 +02:00
Nikita Bobko
cecf23cb33 Remove :idea:idea-native module 2021-04-19 14:19:01 +02:00
Nikita Bobko
540f015e47 Remove :idea:idea-gradle-native module 2021-04-19 14:19:01 +02:00
Nikita Bobko
88b63bfeb7 Remove :idea:idea-frontend-fir module 2021-04-19 14:19:00 +02:00
Nikita Bobko
9862de0b19 Remove :idea:idea-fir module 2021-04-19 14:19:00 +02:00
Nikita Bobko
0818a070b0 Remove :idea:idea-core module 2021-04-19 14:19:00 +02:00
Nikita Bobko
c02bea91f1 Remove :idea:ide-common module 2021-04-19 14:19:00 +02:00
Nikita Bobko
fa9870f6e4 Remove :idea:idea-j2k module 2021-04-19 14:19:00 +02:00
Nikita Bobko
391f14d14c Remove :idea:idea-git module 2021-04-19 14:18:59 +02:00
Nikita Bobko
72fbfd2e81 Remove :idea:idea-gradle module 2021-04-19 14:18:59 +02:00
Nikita Bobko
4f4fc47fdb Remove :idea:idea-maven module 2021-04-19 14:18:59 +02:00
Nikita Bobko
614fbe18aa Remove :idea:idea-jvm module 2021-04-19 14:18:59 +02:00
Nikita Bobko
4e159521b2 Add kotlin-ide/ to .gitignore 2021-04-19 14:18:58 +02:00
51171 changed files with 403 additions and 1181565 deletions

1
.gitignore vendored
View File

@@ -12,6 +12,7 @@
/android-studio/sdk
out/
/tmp
kotlin-ide/
workspace.xml
*.versionsBackup
/idea/testData/debugger/tinyApp/classes*

View File

@@ -76,8 +76,10 @@ val kotlinVersion by extra(
val kotlinLanguageVersion by extra("1.5")
allprojects {
group = "org.jetbrains.kotlin"
version = kotlinVersion
if (!path.startsWith(":kotlin-ide")) {
group = "org.jetbrains.kotlin"
version = kotlinVersion
}
}
extra["kotlin_root"] = rootDir
@@ -317,7 +319,6 @@ extra["compilerModulesForJps"] = listOf(
":core:compiler.common.jvm",
":core:descriptors",
":core:descriptors.jvm",
":idea:idea-jps-common",
":kotlin-preloader",
":compiler:util",
":compiler:config",
@@ -327,6 +328,33 @@ extra["compilerModulesForJps"] = listOf(
":compiler:compiler.version"
)
extra["compilerArtifactsForIde"] = listOf(
":prepare:ide-plugin-dependencies:android-extensions-compiler-plugin-for-ide",
":prepare:ide-plugin-dependencies:allopen-compiler-plugin-for-ide",
":prepare:ide-plugin-dependencies:incremental-compilation-impl-tests-for-ide",
":prepare:ide-plugin-dependencies:kotlin-build-common-tests-for-ide",
":prepare:ide-plugin-dependencies:kotlin-compiler-for-ide",
":prepare:ide-plugin-dependencies:kotlin-gradle-statistics-for-ide",
":prepare:ide-plugin-dependencies:kotlinx-serialization-compiler-plugin-for-ide",
":prepare:ide-plugin-dependencies:noarg-compiler-plugin-for-ide",
":prepare:ide-plugin-dependencies:sam-with-receiver-compiler-plugin-for-ide",
":prepare:ide-plugin-dependencies:compiler-components-for-jps",
":prepare:ide-plugin-dependencies:parcelize-compiler-plugin-for-ide",
":kotlin-script-runtime",
":kotlin-script-util",
":kotlin-scripting-common",
":kotlin-scripting-jvm",
":kotlin-scripting-compiler",
":kotlin-scripting-compiler-impl",
":kotlin-android-extensions-runtime",
":kotlin-stdlib-common",
":kotlin-stdlib",
":kotlin-stdlib-jdk7",
":kotlin-stdlib-jdk8",
":kotlin-reflect",
":kotlin-main-kts"
)
// TODO: fix remaining warnings and remove this property.
extra["tasksWithWarnings"] = listOf(
":kotlin-stdlib:compileTestKotlin",
@@ -390,6 +418,29 @@ val defaultJavaHome = jdkPath(if (Platform[203].orHigher()) "11" else defaultJvm
val ignoreTestFailures by extra(project.kotlinBuildProperties.ignoreTestFailures)
allprojects {
val mirrorRepo: String? = findProperty("maven.repository.mirror")?.toString()
repositories {
kotlinBuildLocalRepo(project)
mirrorRepo?.let(::maven)
internalBootstrapRepo?.let(::maven)
bootstrapKotlinRepo?.let(::maven)
maven(protobufRepo)
maven(intellijRepo)
mavenCentral()
maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-dependencies")
maven("https://dl.google.com/dl/android/maven2")
maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies")
jcenter()
}
if (path.startsWith(":kotlin-ide.")) {
return@allprojects
}
configurations.maybeCreate("embedded").apply {
isCanBeConsumed = false
@@ -418,25 +469,6 @@ allprojects {
// therefore it is disabled by default
// buildDir = File(commonBuildDir, project.name)
val mirrorRepo: String? = findProperty("maven.repository.mirror")?.toString()
repositories {
kotlinBuildLocalRepo(project)
mirrorRepo?.let(::maven)
internalBootstrapRepo?.let(::maven)
bootstrapKotlinRepo?.let(::maven)
maven(protobufRepo)
maven(intellijRepo)
mavenCentral()
maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-dependencies")
maven("https://dl.google.com/dl/android/maven2")
maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies")
jcenter()
}
configureJvmProject(javaHome!!, jvmTarget!!)
@@ -467,6 +499,8 @@ allprojects {
if (useJvmIrBackend) {
useIR = true
} else {
useOldBackend = true
}
if (useJvmFir) {
@@ -625,11 +659,6 @@ val copyCompilerToIdeaPlugin by task<Copy> {
from(distDir) { include("kotlinc/**") }
}
val ideaPlugin by task<Task> {
dependsOn(copyCompilerToIdeaPlugin)
dependsOn(":prepare:idea-plugin:ideaPlugin")
}
tasks {
named<Delete>("clean") {
delete += setOf("$buildDir/repo", distDir)
@@ -805,65 +834,9 @@ tasks {
dependsOn(":compiler:android-tests:test")
}
register("jps-tests") {
dependsOn("dist")
dependsOn(":jps-plugin:test")
}
register("idea-plugin-additional-tests") {
dependsOn("dist")
dependsOn(
":idea:idea-maven:test",
":nj2k:test",
":idea:jvm-debugger:jvm-debugger-core:test",
":idea:jvm-debugger:jvm-debugger-evaluation:test",
":idea:jvm-debugger:jvm-debugger-sequence:test",
":idea:jvm-debugger:eval4j:test",
":idea:scripting-support:test"
)
}
if (Ide.IJ()) {
register("idea-new-project-wizard-tests") {
dependsOn(
":libraries:tools:new-project-wizard:test",
":libraries:tools:new-project-wizard:new-project-wizard-cli:test",
":idea:idea-new-project-wizard:test"
)
}
}
register("idea-plugin-performance-tests") {
dependsOn(
"dist",
":idea:performanceTests:performanceTest",
":idea:performanceTests:aggregateResults"
)
}
register("idea-fir-plugin-performance-tests") {
dependsOn("dist")
dependsOn(
":idea:idea-fir-performance-tests:ideaFirPerformanceTest"
)
}
register("idea-fir-plugin-tests") {
dependsOn("dist")
dependsOn(
":idea:idea-fir:test",
":idea:idea-frontend-api:test",
":idea:idea-frontend-fir:test",
":idea:idea-frontend-fir:idea-fir-low-level-api:test"
)
}
register("android-ide-tests") {
dependsOn("dist")
dependsOn(
":plugins:android-extensions-ide:test",
":idea:idea-android:test",
":kotlin-annotation-processing:test",
":plugins:parcelize:parcelize-ide:test"
)
@@ -890,11 +863,7 @@ tasks {
":plugins:uast-kotlin:test",
":kotlin-annotation-processing-gradle:test",
":kotlinx-serialization-compiler-plugin:test",
":kotlinx-serialization-ide-plugin:test",
":idea:jvm-debugger:jvm-debugger-test:test",
"idea-plugin-additional-tests",
"jps-tests",
":generators:test"
":kotlinx-serialization-ide-plugin:test"
)
if (Ide.IJ()) {
dependsOn(
@@ -960,32 +929,13 @@ tasks {
register("publishIdeArtifacts") {
idePluginDependency {
dependsOn(
":prepare:ide-plugin-dependencies:android-extensions-compiler-plugin-for-ide:publish",
":prepare:ide-plugin-dependencies:allopen-compiler-plugin-for-ide:publish",
":prepare:ide-plugin-dependencies:incremental-compilation-impl-tests-for-ide:publish",
":prepare:ide-plugin-dependencies:kotlin-build-common-tests-for-ide:publish",
":prepare:ide-plugin-dependencies:kotlin-compiler-for-ide:publish",
":prepare:ide-plugin-dependencies:kotlin-gradle-statistics-for-ide:publish",
":prepare:ide-plugin-dependencies:kotlinx-serialization-compiler-plugin-for-ide:publish",
":prepare:ide-plugin-dependencies:noarg-compiler-plugin-for-ide:publish",
":prepare:ide-plugin-dependencies:sam-with-receiver-compiler-plugin-for-ide:publish",
":prepare:ide-plugin-dependencies:compiler-components-for-jps:publish",
":prepare:ide-plugin-dependencies:parcelize-compiler-plugin-for-ide:publish",
":kotlin-script-runtime:publish",
":kotlin-script-util:publish",
":kotlin-scripting-common:publish",
":kotlin-scripting-jvm:publish",
":kotlin-scripting-compiler:publish",
":kotlin-scripting-compiler-impl:publish",
":kotlin-android-extensions-runtime:publish",
":kotlin-stdlib-common:publish",
":kotlin-stdlib:publish",
":kotlin-stdlib-jdk7:publish",
":kotlin-stdlib-jdk8:publish",
":kotlin-reflect:publish",
":kotlin-main-kts:publish"
)
dependsOn((rootProject.extra["compilerArtifactsForIde"] as List<String>).map { "$it:prepare" })
}
}
register("installIdeArtifacts") {
idePluginDependency {
dependsOn((rootProject.extra["compilerArtifactsForIde"] as List<String>).map { "$it:install" })
}
}
}

View File

@@ -18,6 +18,7 @@ plugins {
val intellijUltimateEnabled: Boolean by rootProject.extra
val intellijReleaseType: String by rootProject.extra
val intellijVersion = rootProject.extra["versions.intellijSdk"] as String
val intellijVersionForIde = rootProject.intellijSdkVersionForIde()
val asmVersion = rootProject.findProperty("versions.jar.asm-all") as String?
val androidStudioRelease = rootProject.findProperty("versions.androidStudioRelease") as String?
val androidStudioBuild = rootProject.findProperty("versions.androidStudioBuild") as String?
@@ -25,15 +26,18 @@ val intellijSeparateSdks: Boolean by rootProject.extra
val installIntellijCommunity = !intellijUltimateEnabled || intellijSeparateSdks
val installIntellijUltimate = intellijUltimateEnabled && androidStudioRelease == null
val intellijVersionDelimiterIndex = intellijVersion.indexOfAny(charArrayOf('.', '-'))
if (intellijVersionDelimiterIndex == -1) {
error("Invalid IDEA version $intellijVersion")
fun checkIntellijVersion(intellijVersion: String) {
val intellijVersionDelimiterIndex = intellijVersion.indexOfAny(charArrayOf('.', '-'))
if (intellijVersionDelimiterIndex == -1) {
error("Invalid IDEA version $intellijVersion")
}
}
val platformBaseVersion = intellijVersion.substring(0, intellijVersionDelimiterIndex)
checkIntellijVersion(intellijVersion)
intellijVersionForIde?.let { checkIntellijVersion(it) }
logger.info("intellijUltimateEnabled: $intellijUltimateEnabled")
logger.info("intellijVersion: $intellijVersion")
logger.info("intellijVersionForIde: $intellijVersionForIde")
logger.info("androidStudioRelease: $androidStudioRelease")
logger.info("androidStudioBuild: $androidStudioBuild")
logger.info("intellijSeparateSdks: $intellijSeparateSdks")
@@ -73,11 +77,16 @@ repositories {
}
val intellij by configurations.creating
val intellijForIde by configurations.creating
val intellijUltimate by configurations.creating
val intellijUltimateForIde by configurations.creating
val androidStudio by configurations.creating
val sources by configurations.creating
val sourcesForIde by configurations.creating
val jpsStandalone by configurations.creating
val jpsStandaloneForIde by configurations.creating
val intellijCore by configurations.creating
val intellijCoreForIde by configurations.creating
val nodeJSPlugin by configurations.creating
/**
@@ -93,7 +102,6 @@ val dependenciesDir = (findProperty("kotlin.build.dependencies.dir") as String?)
val customDepsRepoDir = dependenciesDir.resolve("repo")
val customDepsOrg: String by rootProject.extra
val customDepsRevision = intellijVersion
val repoDir = File(customDepsRepoDir, customDepsOrg)
dependencies {
@@ -107,9 +115,11 @@ dependencies {
} else {
if (installIntellijCommunity) {
intellij("com.jetbrains.intellij.idea:ideaIC:$intellijVersion")
intellijVersionForIde?.let { intellijForIde("com.jetbrains.intellij.idea:ideaIC:$it") }
}
if (installIntellijUltimate) {
intellijUltimate("com.jetbrains.intellij.idea:ideaIU:$intellijVersion")
intellijVersionForIde.let { intellijUltimateForIde("com.jetbrains.intellij.idea:ideaIU:$it") }
}
}
@@ -118,102 +128,111 @@ dependencies {
}
sources("com.jetbrains.intellij.idea:ideaIC:$intellijVersion:sources@jar")
intellijVersionForIde?.let { sourcesForIde("com.jetbrains.intellij.idea:ideaIC:$it:sources@jar") }
jpsStandalone("com.jetbrains.intellij.idea:jps-standalone:$intellijVersion")
intellijVersionForIde?.let { jpsStandaloneForIde("com.jetbrains.intellij.idea:jps-standalone:$it") }
intellijCore("com.jetbrains.intellij.idea:intellij-core:$intellijVersion")
intellijVersionForIde?.let { intellijCoreForIde("com.jetbrains.intellij.idea:intellij-core:$it") }
if (intellijUltimateEnabled) {
nodeJSPlugin("com.jetbrains.plugins:NodeJS:${rootProject.extra["versions.idea.NodeJS"]}@zip")
}
}
val makeIntellijCore = buildIvyRepositoryTask(intellijCore, customDepsOrg, customDepsRepoDir)
fun prepareDeps(intellij: Configuration, intellijCore: Configuration, sources: Configuration, intellijUltimate: Configuration, jpsStandalone: Configuration, intellijVersion: String) {
val makeIntellijCore = buildIvyRepositoryTask(intellijCore, customDepsOrg, customDepsRepoDir)
val makeIntellijAnnotations by tasks.registering(Copy::class) {
dependsOn(makeIntellijCore)
val makeIntellijAnnotations = tasks.register("makeIntellijAnnotations${intellij.name.capitalize()}", Copy::class) {
dependsOn(makeIntellijCore)
val intellijCoreRepo = CleanableStore[repoDir.resolve("intellij-core").absolutePath][intellijVersion].use()
from(intellijCoreRepo.resolve("artifacts/annotations.jar"))
val intellijCoreRepo = CleanableStore[repoDir.resolve("intellij-core").absolutePath][intellijVersion].use()
from(intellijCoreRepo.resolve("artifacts/annotations.jar"))
val annotationsStore = CleanableStore[repoDir.resolve(intellijRuntimeAnnotations).absolutePath]
val targetDir = annotationsStore[intellijVersion].use()
into(targetDir)
val annotationsStore = CleanableStore[repoDir.resolve(intellijRuntimeAnnotations).absolutePath]
val targetDir = annotationsStore[intellijVersion].use()
into(targetDir)
val ivyFile = File(targetDir, "$intellijRuntimeAnnotations.ivy.xml")
outputs.files(ivyFile)
val ivyFile = File(targetDir, "$intellijRuntimeAnnotations.ivy.xml")
outputs.files(ivyFile)
doFirst {
annotationsStore.cleanStore()
doFirst {
annotationsStore.cleanStore()
}
doLast {
writeIvyXml(
customDepsOrg,
intellijRuntimeAnnotations,
intellijVersion,
intellijRuntimeAnnotations,
targetDir,
targetDir,
targetDir,
allowAnnotations = true
)
}
}
doLast {
writeIvyXml(
val mergeSources = tasks.create("mergeSources${intellij.name.capitalize()}", Jar::class.java) {
dependsOn(sources)
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
isZip64 = true
if (!kotlinBuildProperties.isTeamcityBuild) {
from(provider { sources.map(::zipTree) })
}
destinationDirectory.set(File(repoDir, sources.name))
archiveBaseName.set("intellij")
archiveClassifier.set("sources")
archiveVersion.set(intellijVersion)
}
val sourcesFile = mergeSources.outputs.files.singleFile
val makeIde = if (androidStudioBuild != null) {
buildIvyRepositoryTask(
androidStudio,
customDepsOrg,
intellijRuntimeAnnotations,
intellijVersion,
intellijRuntimeAnnotations,
targetDir,
targetDir,
targetDir,
allowAnnotations = true
customDepsRepoDir,
if (androidStudioOs == "mac")
::skipContentsDirectory
else
::skipToplevelDirectory
)
} else {
val task = if (installIntellijUltimate) {
buildIvyRepositoryTask(intellijUltimate, customDepsOrg, customDepsRepoDir, null, sourcesFile)
} else {
buildIvyRepositoryTask(intellij, customDepsOrg, customDepsRepoDir, null, sourcesFile)
}
task.configure {
dependsOn(mergeSources)
}
task
}
val buildJpsStandalone = buildIvyRepositoryTask(jpsStandalone, customDepsOrg, customDepsRepoDir, null, sourcesFile)
tasks.named("build") {
dependsOn(
makeIntellijCore,
makeIde,
buildJpsStandalone,
makeIntellijAnnotations
)
}
}
val mergeSources by tasks.creating(Jar::class.java) {
dependsOn(sources)
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
isZip64 = true
if (!kotlinBuildProperties.isTeamcityBuild) {
from(provider { sources.map(::zipTree) })
if (installIntellijUltimate) {
val buildNodeJsPlugin =
buildIvyRepositoryTask(nodeJSPlugin, customDepsOrg, customDepsRepoDir, ::skipToplevelDirectory, sourcesFile)
tasks.named("build") { dependsOn(buildNodeJsPlugin) }
}
destinationDirectory.set(File(repoDir, sources.name))
archiveBaseName.set("intellij")
archiveClassifier.set("sources")
archiveVersion.set(intellijVersion)
}
val sourcesFile = mergeSources.outputs.files.singleFile
val makeIde = if (androidStudioBuild != null) {
buildIvyRepositoryTask(
androidStudio,
customDepsOrg,
customDepsRepoDir,
if (androidStudioOs == "mac")
::skipContentsDirectory
else
::skipToplevelDirectory
)
} else {
val task = if (installIntellijUltimate) {
buildIvyRepositoryTask(intellijUltimate, customDepsOrg, customDepsRepoDir, null, sourcesFile)
} else {
buildIvyRepositoryTask(intellij, customDepsOrg, customDepsRepoDir, null, sourcesFile)
}
task.configure {
dependsOn(mergeSources)
}
task
}
val buildJpsStandalone = buildIvyRepositoryTask(jpsStandalone, customDepsOrg, customDepsRepoDir, null, sourcesFile)
tasks.named("build") {
dependsOn(
makeIntellijCore,
makeIde,
buildJpsStandalone,
makeIntellijAnnotations
)
}
if (installIntellijUltimate) {
val buildNodeJsPlugin =
buildIvyRepositoryTask(nodeJSPlugin, customDepsOrg, customDepsRepoDir, ::skipToplevelDirectory, sourcesFile)
tasks.named("build") { dependsOn(buildNodeJsPlugin) }
prepareDeps(intellij, intellijCore, sources, intellijUltimate, jpsStandalone, intellijVersion)
if (intellijVersionForIde != null) {
prepareDeps(intellijForIde, intellijCoreForIde, sourcesForIde, intellijUltimateForIde, jpsStandaloneForIde, intellijVersionForIde)
}
tasks.named<Delete>("clean") {
@@ -400,6 +419,11 @@ fun skipToplevelDirectory(path: String) = path.substringAfter('/')
fun skipContentsDirectory(path: String) = path.substringAfter("Contents/")
fun Project.intellijSdkVersionForIde(): String? {
val majorVersion = kotlinBuildProperties.getOrNull("kotlin.build.dependencies.kotlinIde.combined") as? String ?: return null
return rootProject.findProperty("versions.intellijSdk.forIde.$majorVersion") as? String
}
class XMLWriter(private val outputStreamWriter: OutputStreamWriter) : Closeable {
private val xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(outputStreamWriter)

View File

@@ -253,6 +253,29 @@ fun Project.idePluginDependency(block: () -> Unit) {
}
}
fun Project.publishJarsForIde(projects: List<String>, libraryDependencies: List<String> = emptyList()) {
idePluginDependency {
publishProjectJars(projects, libraryDependencies)
}
dependencies {
projects.forEach {
jpsLikeJarDependency(project(it), JpsDepScope.COMPILE, { isTransitive = false }, exported = true)
}
libraryDependencies.forEach {
jpsLikeJarDependency(it, JpsDepScope.COMPILE, exported = true)
}
}
}
fun Project.publishTestJarForIde(projectName: String) {
idePluginDependency {
publishTestJar(projectName)
}
dependencies {
jpsLikeJarDependency(projectTests(projectName), JpsDepScope.COMPILE, exported = true)
}
}
fun Project.publishProjectJars(projects: List<String>, libraryDependencies: List<String> = emptyList()) {
apply<JavaPlugin>()

View File

@@ -11,11 +11,13 @@ import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.ExternalModuleDependency
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.artifacts.ProjectDependency
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileCollection
import org.gradle.kotlin.dsl.accessors.runtime.addDependencyTo
import org.gradle.kotlin.dsl.closureOf
import org.gradle.kotlin.dsl.extra
import org.gradle.kotlin.dsl.project
import java.io.File
@@ -115,6 +117,87 @@ fun DependencyHandler.projectTests(name: String): ProjectDependency = project(na
fun DependencyHandler.projectRuntimeJar(name: String): ProjectDependency = project(name, configuration = "runtimeJar")
fun DependencyHandler.projectArchives(name: String): ProjectDependency = project(name, configuration = "archives")
enum class JpsDepScope {
COMPILE, TEST, RUNTIME, PROVIDED
}
fun DependencyHandler.add(configurationName: String, dependencyNotation: Any, configure: (ModuleDependency.() -> Unit)?) {
// Avoid `dependencyNotation` to `ModuleDependency` class cast exception if possible
if (configure != null) {
add(configurationName, dependencyNotation, closureOf(configure))
} else {
add(configurationName, dependencyNotation)
}
}
fun DependencyHandler.jpsLikeJarDependency(
dependencyNotation: Any,
scope: JpsDepScope,
dependencyConfiguration: (ModuleDependency.() -> Unit)? = null,
exported: Boolean = false
) {
when (scope) {
JpsDepScope.COMPILE -> {
if (exported) {
add("api", dependencyNotation, dependencyConfiguration)
add("testCompile", dependencyNotation, dependencyConfiguration)
} else {
add("implementation", dependencyNotation, dependencyConfiguration)
}
}
JpsDepScope.TEST -> {
if (exported) {
add("testCompile", dependencyNotation, dependencyConfiguration)
} else {
add("testImplementation", dependencyNotation, dependencyConfiguration)
}
}
JpsDepScope.RUNTIME -> {
add("testRuntimeOnly", dependencyNotation, dependencyConfiguration)
}
JpsDepScope.PROVIDED -> {
if (exported) {
add("compileOnlyApi", dependencyNotation, dependencyConfiguration)
add("testCompile", dependencyNotation, dependencyConfiguration)
} else {
add("compileOnly", dependencyNotation, dependencyConfiguration)
add("testImplementation", dependencyNotation, dependencyConfiguration)
}
}
}
}
fun DependencyHandler.jpsLikeModuleDependency(moduleName: String, scope: JpsDepScope, exported: Boolean = false) {
jpsLikeJarDependency(project(moduleName), scope, exported = exported)
when (scope) {
JpsDepScope.COMPILE -> {
if (exported) {
add("testCompile", projectTests(moduleName))
} else {
add("testImplementation", projectTests(moduleName))
}
}
JpsDepScope.TEST -> {
if (exported) {
add("testCompile", projectTests(moduleName))
} else {
add("testImplementation", projectTests(moduleName))
}
}
JpsDepScope.RUNTIME -> {
add("runtimeOnly", projectTests(moduleName))
}
JpsDepScope.PROVIDED -> {
if (exported) {
add("testCompile", projectTests(moduleName))
} else {
add("testImplementation", projectTests(moduleName))
}
}
}
}
fun Project.testApiJUnit5(
vintageEngine: Boolean = false,
runner: Boolean = false,

View File

@@ -42,9 +42,21 @@ private fun Project.ideModuleName() = when (IdeVersionConfigurator.currentIde.ki
}
}
private fun Project.ideModuleVersion() = when (IdeVersionConfigurator.currentIde.kind) {
private fun Project.ideModuleVersion(forIde: Boolean) = when (IdeVersionConfigurator.currentIde.kind) {
Ide.Kind.AndroidStudio -> rootProject.findProperty("versions.androidStudioBuild")
Ide.Kind.IntelliJ -> rootProject.findProperty("versions.intellijSdk")
Ide.Kind.IntelliJ -> {
if (forIde) {
intellijSdkVersionForIde()
?: error("Please specify 'kotlin.build.dependencies.kotlinIde.combined' in your local.properties")
} else {
rootProject.findProperty("versions.intellijSdk")
}
}
}
fun Project.intellijSdkVersionForIde(): String? {
val majorVersion = kotlinBuildProperties.getOrNull("kotlin.build.dependencies.kotlinIde.combined") as? String ?: return null
return rootProject.findProperty("versions.intellijSdk.forIde.$majorVersion") as? String
}
fun RepositoryHandler.kotlinBuildLocalRepo(project: Project): IvyArtifactRepository = ivy {
@@ -58,6 +70,7 @@ fun RepositoryHandler.kotlinBuildLocalRepo(project: Project): IvyArtifactReposit
artifact("[organisation]/[module]/[revision]/artifacts/lib/[artifact](-[classifier]).[ext]")
artifact("[organisation]/[module]/[revision]/artifacts/[artifact](-[classifier]).[ext]")
artifact("[organisation]/intellij-core/[revision]/artifacts/[artifact](-[classifier]).[ext]")
artifact("[organisation]/${project.ideModuleName()}/[revision]/artifacts/plugins/[module]/lib/[artifact](-[classifier]).[ext]") // bundled plugins
artifact("[organisation]/sources/[artifact]-[revision](-[classifier]).[ext]")
artifact("[organisation]/[module]/[revision]/[artifact](-[classifier]).[ext]")
@@ -68,7 +81,9 @@ fun RepositoryHandler.kotlinBuildLocalRepo(project: Project): IvyArtifactReposit
}
}
fun Project.intellijDep(module: String? = null) = "kotlin.build:${module ?: ideModuleName()}:${ideModuleVersion()}"
@Suppress("UNUSED_PARAMETER")
fun Project.intellijDep(module: String? = null, forIde: Boolean = false) =
"kotlin.build:${module ?: ideModuleName()}:${ideModuleVersion(forIde)}"
fun Project.intellijCoreDep() = "kotlin.build:intellij-core:${rootProject.extra["versions.intellijSdk"]}"
@@ -93,7 +108,7 @@ fun Project.kotlinxCollectionsImmutable() = "org.jetbrains.kotlinx:kotlinx-colle
*/
fun Project.intellijRuntimeAnnotations() = "kotlin.build:intellij-runtime-annotations:${rootProject.extra["versions.intellijSdk"]}"
fun Project.intellijPluginDep(plugin: String) = intellijDep(plugin)
fun Project.intellijPluginDep(plugin: String, forIde: Boolean = false) = intellijDep(plugin, forIde)
fun Project.intellijUltimateDep() = intellijDep("ideaIU")
@@ -125,7 +140,7 @@ object IntellijRootUtils {
fun getIntellijRootDir(project: Project): File = with(project.rootProject) {
return File(
getRepositoryRootDir(this),
"${ideModuleName()}/${ideModuleVersion()}/artifacts"
"${ideModuleName()}/${ideModuleVersion(forIde = false)}/artifacts"
)
}
}

View File

@@ -24,7 +24,6 @@ dependencies {
testApi(projectTests(":compiler:tests-compiler-utils"))
testApi(projectTests(":compiler:tests-common-new"))
testCompile(projectTests(":jps-plugin"))
testCompile(commonDep("junit:junit"))
Platform[193].orLower {

View File

@@ -44,37 +44,17 @@ dependencies {
testCompile(interpreterSourceSet.output)
testCompile(projectTests(":compiler:cli"))
testCompile(projectTests(":idea:idea-maven"))
testCompile(projectTests(":idea:idea-fir"))
testCompile(projectTests(":idea:idea-fir-performance-tests"))
testCompile(projectTests(":idea:idea-frontend-fir"))
testCompile(projectTests(":idea:idea-frontend-fir:idea-fir-low-level-api"))
testCompile(projectTests(":j2k"))
testCompile(projectTests(":nj2k"))
if (Ide.IJ()) {
testCompile(projectTests(":libraries:tools:new-project-wizard:new-project-wizard-cli"))
testCompile(projectTests(":idea:idea-new-project-wizard"))
}
testCompile(projectTests(":idea:idea-android"))
testCompile(projectTests(":idea:performanceTests"))
testCompile(projectTests(":idea:scripting-support"))
testCompile(projectTests(":jps-plugin"))
testCompile(projectTests(":plugins:jvm-abi-gen"))
testCompile(projectTests(":plugins:android-extensions-compiler"))
testCompile(projectTests(":plugins:android-extensions-ide"))
testCompile(projectTests(":plugins:parcelize:parcelize-compiler"))
testCompile(projectTests(":plugins:parcelize:parcelize-ide"))
testCompile(projectTests(":kotlin-annotation-processing"))
testCompile(projectTests(":kotlin-annotation-processing-cli"))
testCompile(projectTests(":kotlin-allopen-compiler-plugin"))
testCompile(projectTests(":kotlin-noarg-compiler-plugin"))
testCompile(projectTests(":kotlin-sam-with-receiver-compiler-plugin"))
testCompile(projectTests(":kotlinx-serialization-compiler-plugin"))
testCompile(projectTests(":kotlinx-serialization-ide-plugin"))
testCompile(projectTests(":plugins:fir:fir-plugin-prototype"))
testCompile(projectTests(":idea:jvm-debugger:jvm-debugger-test"))
testCompile(projectTests(":generators:test-generator"))
testCompile(projectTests(":idea"))
testCompileOnly(project(":kotlin-reflect-api"))
testRuntime(intellijDep()) { includeJars("idea_rt") }
testRuntime(project(":kotlin-reflect"))

View File

@@ -10,7 +10,7 @@ kotlin.compiler.effectSystemEnabled=true
kotlin.compiler.newInferenceEnabled=true
# Enable JVM IR backend for all modules except libraries such as kotlin-stdlib, kotlin-reflect, kotlin-test.
kotlin.build.useIR=true
kotlin.build.useIR=false
# Enable JVM IR backend for the libraries mentioned above.
#kotlin.build.useIRForLibraries=true
@@ -27,6 +27,7 @@ kotlin.build.publishing.attempts=20
#jpsBuild=true
#cidrPluginsEnabled=true
#idea.fir.plugin=true
#kotlin.build.dependencies.kotlinIde.combined=203 (or any other platform version)
## Used for compare gradle and jps build

View File

@@ -1,4 +1,6 @@
versions.intellijSdk=202.7660.26
versions.intellijSdk.forIde.202=202.7660.26
versions.intellijSdk.forIde.203=203.6682.168
versions.idea.NodeJS=193.6494.7
versions.jar.asm-all=8.0.1
versions.jar.guava=29.0-jre

View File

@@ -1,6 +1,6 @@
#Fri Mar 26 00:53:30 CET 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip
distributionSha256Sum=8ad57759019a9233dc7dc4d1a530cefe109dc122000d57f7e623f8cf4ba9dfc4
zipStoreBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME

View File

@@ -1,3 +0,0 @@
This module exists for the sole purpose of providing the classpath for the IDEA run configuration.
This run configuration takes a plugin from the KotlinPlugin artifact instead of the project's 'out' directory, which makes it possible for our plugin to depend on other plugins such as JUnit plugin.
If you want to debug some patch to IDEA, you can add copy of IDEA class into this module and modify.

View File

@@ -1,23 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compileOnly(project(":idea"))
compileOnly(project(":idea:idea-maven"))
compileOnly(project(":idea:idea-gradle"))
compileOnly(project(":idea:idea-jvm"))
runtimeOnly(intellijDep())
runtimeOnly(intellijRuntimeAnnotations())
runtimeOnly(toolsJar())
}
val ideaPluginDir: File by rootProject.extra
val ideaSandboxDir: File by rootProject.extra
runIdeTask("runIde", ideaPluginDir, ideaSandboxDir) {
dependsOn(":dist", ":ideaPlugin")
}

View File

@@ -1,224 +0,0 @@
import org.apache.tools.ant.filters.ReplaceTokens
plugins {
kotlin("jvm")
id("jps-compatible")
}
val kotlinVersion: String by rootProject.extra
sourceSets {
"main" {
projectDefault()
java.srcDirs(
"idea-completion/src",
"idea-live-templates/src",
"idea-repl/src"
)
resources.srcDirs(
"idea-completion/resources",
"idea-live-templates/resources",
"idea-repl/resources",
"resources-en"
)
if (kotlinBuildProperties.useFirIdeaPlugin) {
resources.srcDir("resources-fir")
} else {
resources.srcDir("resources-descriptors")
}
}
"test" {
projectDefault()
java.srcDirs(
"idea-completion/tests",
"idea-live-templates/tests"
)
}
}
dependencies {
testRuntime(intellijDep())
testRuntime(intellijRuntimeAnnotations())
compile(kotlinStdlib("jdk8"))
compileOnly(project(":kotlin-reflect-api"))
compile(project(":core:descriptors"))
compile(project(":core:descriptors.jvm"))
compile(project(":compiler:backend"))
compile(project(":compiler:frontend"))
compile(project(":compiler:frontend.common"))
compile(project(":compiler:frontend.java"))
compile(project(":compiler:ir.backend.common")) // TODO: fix import (workaround for jps build)
compile(project(":js:js.frontend"))
compile(project(":js:js.serializer"))
compile(project(":compiler:light-classes"))
compile(project(":compiler:util"))
compile(project(":kotlin-build-common"))
compile(project(":daemon-common"))
compile(project(":daemon-common-new"))
compile(projectRuntimeJar(":kotlin-daemon-client"))
compile(project(":compiler:plugin-api"))
compile(project(":idea:jvm-debugger:jvm-debugger-util"))
compile(project(":idea:jvm-debugger:jvm-debugger-core"))
compile(project(":idea:jvm-debugger:jvm-debugger-evaluation"))
compile(project(":idea:jvm-debugger:jvm-debugger-sequence"))
compile(project(":idea:jvm-debugger:jvm-debugger-coroutine"))
compile(project(":j2k"))
compile(project(":idea:idea-j2k"))
compile(project(":idea:formatter"))
compile(project(":compiler:fir:fir2ir"))
compile(project(":compiler:fir:resolve"))
compile(project(":compiler:fir:checkers"))
compile(project(":compiler:fir:java"))
compile(project(":compiler:fir:jvm"))
compile(project(":idea:idea-core"))
compile(project(":idea:idea-frontend-independent"))
compile(project(":idea:ide-common"))
compile(project(":idea:idea-jps-common"))
compile(project(":idea:kotlin-gradle-tooling"))
compile(project(":idea:line-indent-provider"))
compile(project(":plugins:uast-kotlin"))
compile(project(":plugins:uast-kotlin-idea"))
compile(project(":kotlin-script-util")) { isTransitive = false }
compile(project(":kotlin-scripting-intellij"))
compile(project(":compiler:backend.jvm")) // Do not delete, for Pill
compile(project(":compiler:backend.jvm:backend.jvm.entrypoint"))
compile(commonDep("org.jetbrains.kotlinx", "kotlinx-coroutines-core")) { isTransitive = false }
compileOnly(project(":kotlin-daemon-client"))
compileOnly(intellijDep())
compileOnly(intellijPluginDep("java"))
testCompileOnly(intellijPluginDep("java"))
testRuntime(intellijPluginDep("java"))
implementation(commonDep("org.jetbrains.intellij.deps.completion", "completion-ranking-kotlin"))
Ide.IJ {
implementation(intellijPluginDep("stats-collector"))
}
compileOnly(commonDep("org.jetbrains", "markdown"))
compileOnly(commonDep("com.google.code.findbugs", "jsr305"))
compileOnly(intellijPluginDep("IntelliLang"))
compileOnly(intellijPluginDep("copyright"))
compileOnly(intellijPluginDep("properties"))
compileOnly(intellijPluginDep("java-i18n"))
compileOnly(intellijPluginDep("gradle"))
testCompileOnly(toolsJar())
testCompileOnly(project(":kotlin-reflect-api")) // TODO: fix import (workaround for jps build)
testCompile(project(":kotlin-test:kotlin-test-junit"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(projectTests(":idea:idea-test-framework")) { isTransitive = false }
testImplementation(projectTests(":idea:idea-frontend-independent")) { isTransitive = false }
testCompile(project(":idea:idea-jvm")) { isTransitive = false }
testCompile(project(":idea:idea-gradle")) { isTransitive = false }
testCompile(project(":idea:idea-maven")) { isTransitive = false }
testCompile(project(":idea:idea-native")) { isTransitive = false }
testCompile(project(":idea:idea-gradle-native")) { isTransitive = false }
testCompile(commonDep("junit:junit"))
testCompileOnly(intellijPluginDep("coverage"))
testRuntimeOnly(toolsJar())
testRuntime(commonDep("org.jetbrains", "markdown"))
testRuntime(project(":plugins:kapt3-idea")) { isTransitive = false }
testRuntime(project(":kotlin-reflect"))
testRuntime(project(":kotlin-preloader"))
testCompile(project(":kotlin-sam-with-receiver-compiler-plugin")) { isTransitive = false }
testRuntime(project(":plugins:android-extensions-compiler"))
testRuntimeOnly(project(":kotlin-android-extensions-runtime")) // TODO: fix import (workaround for jps build)
testRuntime(project(":plugins:android-extensions-ide")) { isTransitive = false }
testRuntime(project(":allopen-ide-plugin")) { isTransitive = false }
testRuntime(project(":kotlin-allopen-compiler-plugin"))
testRuntime(project(":noarg-ide-plugin")) { isTransitive = false }
testRuntime(project(":kotlin-noarg-compiler-plugin"))
testRuntime(project(":plugins:annotation-based-compiler-plugins-ide-support")) { isTransitive = false }
testRuntime(project(":plugins:parcelize:parcelize-compiler"))
testRuntime(project(":plugins:parcelize:parcelize-ide")) { isTransitive = false }
testRuntime(project(":kotlin-scripting-idea")) { isTransitive = false }
testRuntime(project(":kotlin-scripting-compiler-impl"))
testRuntime(project(":sam-with-receiver-ide-plugin")) { isTransitive = false }
testRuntime(project(":kotlinx-serialization-compiler-plugin"))
testRuntime(project(":kotlinx-serialization-ide-plugin")) { isTransitive = false }
testRuntime(project(":idea:idea-android")) { isTransitive = false }
testRuntime(project(":plugins:lint")) { isTransitive = false }
testRuntime(project(":plugins:uast-kotlin"))
testRuntime(project(":nj2k:nj2k-services")) { isTransitive = false }
(rootProject.extra["compilerModules"] as Array<String>).forEach {
testRuntime(project(it))
}
testCompile(intellijPluginDep("IntelliLang"))
testCompile(intellijPluginDep("copyright"))
testCompile(intellijPluginDep("properties"))
testCompile(intellijPluginDep("java-i18n"))
testCompile(intellijPluginDep("junit"))
testCompileOnly(intellijDep())
testCompileOnly(commonDep("com.google.code.findbugs", "jsr305"))
testCompileOnly(intellijPluginDep("gradle"))
testCompileOnly(intellijPluginDep("Groovy"))
if (Ide.IJ()) {
testCompileOnly(intellijPluginDep("maven"))
testRuntime(intellijPluginDep("maven"))
if (Ide.IJ201.orHigher()) {
testRuntime(intellijPluginDep("repository-search"))
}
}
testRuntime(intellijPluginDep("junit"))
testRuntime(intellijPluginDep("gradle"))
testRuntime(intellijPluginDep("Groovy"))
testRuntime(intellijPluginDep("coverage"))
testRuntime(intellijPluginDep("android"))
testRuntime(intellijPluginDep("smali"))
testRuntime(intellijPluginDep("testng"))
if (kotlinBuildProperties.useFirIdeaPlugin) {
testRuntime(project(":idea:idea-fir"))
}
if (Ide.AS36.orHigher()) {
testRuntime(intellijPluginDep("android-layoutlib"))
testRuntime(intellijPluginDep("git4idea"))
testRuntime(intellijPluginDep("google-cloud-tools-core-as"))
testRuntime(intellijPluginDep("google-login-as"))
}
if (Ide.AS41.orHigher()) {
testRuntime(intellijPluginDep("platform-images"))
}
}
tasks.named<Copy>("processResources") {
val currentIde = IdeVersionConfigurator.currentIde
val pluginPatchNumber = findProperty("pluginPatchNumber") as String? ?: "1"
val defaultPluginVersion = "$kotlinVersion-${currentIde.displayVersion}-$pluginPatchNumber"
val pluginVersion = findProperty("pluginVersion") as String? ?: defaultPluginVersion
inputs.property("pluginVersion", pluginVersion)
filesMatching("META-INF/plugin.xml") {
filter<ReplaceTokens>("tokens" to mapOf("snapshot" to pluginVersion))
}
from(provider { project(":compiler:cli-common").mainSourceSet.resources }) {
include("META-INF/extensions/compiler.xml")
}
}
projectTest(parallel = true) {
dependsOn(":dist")
workingDir = rootDir
}
configureFormInstrumentation()
testsJar()

View File

@@ -1,18 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compile(project(":compiler:util"))
compile(project(":compiler:frontend"))
compileOnly(intellijDep())
compileOnly(intellijPluginDep("java"))
}
sourceSets {
"main" { projectDefault() }
"test" {}
}

View File

@@ -1,196 +0,0 @@
/*
* Copyright 2010-2019 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.idea.core.formatter;
import com.intellij.application.options.CodeStyle;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CustomCodeStyleSettings;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.formatter.KotlinObsoleteCodeStyle;
import org.jetbrains.kotlin.idea.formatter.KotlinStyleGuideCodeStyle;
import org.jetbrains.kotlin.idea.util.FormatterUtilKt;
import org.jetbrains.kotlin.idea.util.ReflectionUtil;
import static com.intellij.util.ReflectionUtil.copyFields;
public class KotlinCodeStyleSettings extends CustomCodeStyleSettings {
public final KotlinPackageEntryTable PACKAGES_TO_USE_STAR_IMPORTS = new KotlinPackageEntryTable();
public final KotlinPackageEntryTable PACKAGES_IMPORT_LAYOUT = new KotlinPackageEntryTable();
public boolean SPACE_AROUND_RANGE = false;
public boolean SPACE_BEFORE_TYPE_COLON = false;
public boolean SPACE_AFTER_TYPE_COLON = true;
public boolean SPACE_BEFORE_EXTEND_COLON = true;
public boolean SPACE_AFTER_EXTEND_COLON = true;
public boolean INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD = true;
public boolean ALIGN_IN_COLUMNS_CASE_BRANCH = false;
public boolean SPACE_AROUND_FUNCTION_TYPE_ARROW = true;
public boolean SPACE_AROUND_WHEN_ARROW = true;
public boolean SPACE_BEFORE_LAMBDA_ARROW = true;
public boolean SPACE_BEFORE_WHEN_PARENTHESES = true;
public boolean LBRACE_ON_NEXT_LINE = false;
public int NAME_COUNT_TO_USE_STAR_IMPORT = ApplicationManager.getApplication().isUnitTestMode() ? Integer.MAX_VALUE : 5;
public int NAME_COUNT_TO_USE_STAR_IMPORT_FOR_MEMBERS = ApplicationManager.getApplication().isUnitTestMode() ? Integer.MAX_VALUE : 3;
public boolean IMPORT_NESTED_CLASSES = false;
public boolean CONTINUATION_INDENT_IN_PARAMETER_LISTS = true;
public boolean CONTINUATION_INDENT_IN_ARGUMENT_LISTS = true;
public boolean CONTINUATION_INDENT_FOR_EXPRESSION_BODIES = true;
public boolean CONTINUATION_INDENT_FOR_CHAINED_CALLS = true;
public boolean CONTINUATION_INDENT_IN_SUPERTYPE_LISTS = true;
public boolean CONTINUATION_INDENT_IN_IF_CONDITIONS = true;
public boolean CONTINUATION_INDENT_IN_ELVIS = true;
public int BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES = 0;
public int WRAP_EXPRESSION_BODY_FUNCTIONS = 0;
public int WRAP_ELVIS_EXPRESSIONS = 1;
public boolean IF_RPAREN_ON_NEW_LINE = false;
public boolean ALLOW_TRAILING_COMMA = false;
public boolean ALLOW_TRAILING_COMMA_ON_CALL_SITE = false;
public int BLANK_LINES_BEFORE_DECLARATION_WITH_COMMENT_OR_ANNOTATION_ON_SEPARATE_LINE = 1;
@ReflectionUtil.SkipInEquals
public String CODE_STYLE_DEFAULTS = null;
/**
* Load settings with previous IDEA defaults to have an ability to restore them.
*/
@Nullable
private KotlinCodeStyleSettings settingsAgainstPreviousDefaults = null;
private final boolean isTempForDeserialize;
public KotlinCodeStyleSettings(CodeStyleSettings container) {
this(container, false);
}
private KotlinCodeStyleSettings(CodeStyleSettings container, boolean isTempForDeserialize) {
super("JetCodeStyleSettings", container);
this.isTempForDeserialize = isTempForDeserialize;
// defaults in IDE but not in tests
if (!ApplicationManager.getApplication().isUnitTestMode()) {
PACKAGES_TO_USE_STAR_IMPORTS.addEntry(new KotlinPackageEntry("java.util", false));
PACKAGES_TO_USE_STAR_IMPORTS.addEntry(new KotlinPackageEntry("kotlinx.android.synthetic", true));
PACKAGES_TO_USE_STAR_IMPORTS.addEntry(new KotlinPackageEntry("io.ktor", true));
}
// Many of test data actually depend on this order of imports,
// that is why we put it here even for test mode
PACKAGES_IMPORT_LAYOUT.addEntry(KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY);
PACKAGES_IMPORT_LAYOUT.addEntry(new KotlinPackageEntry("java", true));
PACKAGES_IMPORT_LAYOUT.addEntry(new KotlinPackageEntry("javax", true));
PACKAGES_IMPORT_LAYOUT.addEntry(new KotlinPackageEntry("kotlin", true));
PACKAGES_IMPORT_LAYOUT.addEntry(KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY);
}
public static KotlinCodeStyleSettings getInstance(Project project) {
return CodeStyle.getSettings(project).getCustomSettings(KotlinCodeStyleSettings.class);
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
public Object clone() {
return cloneSettings();
}
@NotNull
public KotlinCodeStyleSettings cloneSettings() {
KotlinCodeStyleSettings clone = new KotlinCodeStyleSettings(getContainer());
clone.copyFrom(this);
clone.settingsAgainstPreviousDefaults = this.settingsAgainstPreviousDefaults;
return clone;
}
private void copyFrom(@NotNull KotlinCodeStyleSettings from) {
copyFields(getClass().getFields(), from, this);
PACKAGES_TO_USE_STAR_IMPORTS.copyFrom(from.PACKAGES_TO_USE_STAR_IMPORTS);
PACKAGES_IMPORT_LAYOUT.copyFrom(from.PACKAGES_IMPORT_LAYOUT);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof KotlinCodeStyleSettings)) return false;
if (!ReflectionUtil.comparePublicNonFinalFieldsWithSkip(this, obj)) return false;
return true;
}
@Override
public void writeExternal(Element parentElement, @NotNull CustomCodeStyleSettings parentSettings) throws WriteExternalException {
if (CODE_STYLE_DEFAULTS != null) {
KotlinCodeStyleSettings defaultKotlinCodeStyle = (KotlinCodeStyleSettings) parentSettings.clone();
if (KotlinStyleGuideCodeStyle.CODE_STYLE_ID.equals(CODE_STYLE_DEFAULTS)) {
KotlinStyleGuideCodeStyle.Companion.applyToKotlinCustomSettings(defaultKotlinCodeStyle, false);
}
else if (KotlinObsoleteCodeStyle.CODE_STYLE_ID.equals(CODE_STYLE_DEFAULTS)) {
KotlinObsoleteCodeStyle.Companion.applyToKotlinCustomSettings(defaultKotlinCodeStyle, false);
}
parentSettings = defaultKotlinCodeStyle;
}
super.writeExternal(parentElement, parentSettings);
}
@Override
public void readExternal(Element parentElement) throws InvalidDataException {
if (isTempForDeserialize) {
super.readExternal(parentElement);
return;
}
KotlinCodeStyleSettings tempSettings = readExternalToTemp(parentElement);
String customDefaults = tempSettings.CODE_STYLE_DEFAULTS;
if (KotlinStyleGuideCodeStyle.CODE_STYLE_ID.equals(customDefaults)) {
KotlinStyleGuideCodeStyle.Companion.applyToKotlinCustomSettings(this, true);
}
else if (KotlinObsoleteCodeStyle.CODE_STYLE_ID.equals(customDefaults)) {
KotlinObsoleteCodeStyle.Companion.applyToKotlinCustomSettings(this, true);
}
else if (customDefaults == null && FormatterUtilKt.isDefaultOfficialCodeStyle()) {
// Temporary load settings against previous defaults
settingsAgainstPreviousDefaults = new KotlinCodeStyleSettings(null, true);
KotlinObsoleteCodeStyle.Companion.applyToKotlinCustomSettings(settingsAgainstPreviousDefaults, true);
settingsAgainstPreviousDefaults.readExternal(parentElement);
}
// Actual read
super.readExternal(parentElement);
}
private static KotlinCodeStyleSettings readExternalToTemp(Element parentElement) {
// Read to temp
KotlinCodeStyleSettings tempSettings = new KotlinCodeStyleSettings(null, true);
tempSettings.readExternal(parentElement);
return tempSettings;
}
public boolean canRestore() {
return settingsAgainstPreviousDefaults != null;
}
public void restore() {
if (settingsAgainstPreviousDefaults != null) {
copyFrom(settingsAgainstPreviousDefaults);
}
}
public static KotlinCodeStyleSettings defaultSettings() {
return ServiceManager.getService(KotlinCodeStyleSettingsHolder.class).defaultSettings;
}
public static final class KotlinCodeStyleSettingsHolder {
private final KotlinCodeStyleSettings defaultSettings = new KotlinCodeStyleSettings(new CodeStyleSettings());
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright 2010-2020 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.idea.core.formatter
import com.intellij.openapi.application.ApplicationBundle
class KotlinPackageEntry(
packageName: String,
val withSubpackages: Boolean
) {
val packageName = packageName.removeSuffix(".*")
companion object {
@JvmField
val ALL_OTHER_IMPORTS_ENTRY =
KotlinPackageEntry(ApplicationBundle.message("listbox.import.all.other.imports"), withSubpackages = true)
@JvmField
val ALL_OTHER_ALIAS_IMPORTS_ENTRY = KotlinPackageEntry("<all other alias imports>", withSubpackages = true)
}
fun matchesPackageName(otherPackageName: String): Boolean {
if (otherPackageName.startsWith(packageName)) {
if (otherPackageName.length == packageName.length) return true
if (withSubpackages) {
if (otherPackageName[packageName.length] == '.') return true
}
}
return false
}
val isSpecial: Boolean get() = this == ALL_OTHER_IMPORTS_ENTRY || this == ALL_OTHER_ALIAS_IMPORTS_ENTRY
override fun toString(): String {
return packageName
}
}

View File

@@ -1,92 +0,0 @@
/*
* Copyright 2010-2020 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.idea.core.formatter
import com.intellij.openapi.util.InvalidDataException
import com.intellij.openapi.util.JDOMExternalizable
import org.jdom.Element
class KotlinPackageEntryTable : JDOMExternalizable, Cloneable {
private val entries = mutableListOf<KotlinPackageEntry>()
val entryCount: Int get() = entries.size
public override fun clone(): KotlinPackageEntryTable {
val clone = KotlinPackageEntryTable()
clone.copyFrom(this)
return clone
}
fun copyFrom(packageTable: KotlinPackageEntryTable) {
entries.clear()
entries.addAll(packageTable.entries)
}
fun getEntries(): Array<KotlinPackageEntry> {
return entries.toTypedArray()
}
fun insertEntryAt(entry: KotlinPackageEntry, index: Int) {
entries.add(index, entry)
}
fun removeEntryAt(index: Int) {
entries.removeAt(index)
}
fun getEntryAt(index: Int): KotlinPackageEntry {
return entries[index]
}
fun setEntryAt(entry: KotlinPackageEntry, index: Int) {
entries[index] = entry
}
operator fun contains(packageName: String): Boolean {
return entries.any { !it.isSpecial && it.matchesPackageName(packageName) }
}
fun removeEmptyPackages() {
entries.removeAll { it.packageName.isBlank() }
}
fun addEntry(entry: KotlinPackageEntry) {
entries.add(entry)
}
override fun readExternal(element: Element) {
entries.clear()
element.children.forEach {
if (it.name == "package") {
val packageName = it.getAttributeValue("name") ?: throw InvalidDataException()
val alias = it.getAttributeValue("alias")?.toBoolean() ?: false
val withSubpackages = it.getAttributeValue("withSubpackages")?.toBoolean() ?: false
val entry = when {
packageName.isEmpty() && !alias -> KotlinPackageEntry.ALL_OTHER_IMPORTS_ENTRY
packageName.isEmpty() && alias -> KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY
else -> KotlinPackageEntry(packageName, withSubpackages)
}
entries.add(entry)
}
}
}
override fun writeExternal(parentNode: Element) {
for (entry in entries) {
val element = Element("package")
parentNode.addContent(element)
val name = if (entry.isSpecial) "" else entry.packageName
val alias = (entry == KotlinPackageEntry.ALL_OTHER_ALIAS_IMPORTS_ENTRY)
element.setAttribute("name", name)
element.setAttribute("alias", alias.toString())
element.setAttribute("withSubpackages", entry.withSubpackages.toString())
}
}
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.formatter
import com.intellij.formatting.Alignment
import com.intellij.lang.ASTNode
abstract class CommonAlignmentStrategy {
abstract fun getAlignment(node: ASTNode): Alignment?
}

View File

@@ -1,273 +0,0 @@
/*
* Copyright 2000-2019 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.idea.formatter;
import com.intellij.lang.Language;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.DifferenceFilter;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CommonCodeStyleSettings;
import com.intellij.psi.codeStyle.LanguageCodeStyleSettingsProvider;
import com.intellij.psi.codeStyle.arrangement.ArrangementSettings;
import com.intellij.psi.codeStyle.arrangement.ArrangementUtil;
import com.intellij.util.xmlb.XmlSerializer;
import kotlin.collections.ArraysKt;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinLanguage;
import org.jetbrains.kotlin.idea.util.FormatterUtilKt;
import org.jetbrains.kotlin.idea.util.ReflectionUtil;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
@SuppressWarnings("UnnecessaryFinalOnLocalVariableOrParameter")
public class KotlinCommonCodeStyleSettings extends CommonCodeStyleSettings {
@ReflectionUtil.SkipInEquals
public String CODE_STYLE_DEFAULTS = null;
/**
* Load settings with previous IDEA defaults to have an ability to restore them.
*/
@Nullable
private KotlinCommonCodeStyleSettings settingsAgainstPreviousDefaults = null;
private final boolean isTempForDeserialize;
public KotlinCommonCodeStyleSettings() {
this(false);
}
private KotlinCommonCodeStyleSettings(boolean isTempForDeserialize) {
super(KotlinLanguage.INSTANCE);
this.isTempForDeserialize = isTempForDeserialize;
}
private static KotlinCommonCodeStyleSettings createForTempDeserialize() {
return new KotlinCommonCodeStyleSettings(true);
}
@Override
public void readExternal(Element element) throws InvalidDataException {
if (isTempForDeserialize) {
super.readExternal(element);
return;
}
KotlinCommonCodeStyleSettings tempDeserialize = createForTempDeserialize();
tempDeserialize.readExternal(element);
String customDefaults = tempDeserialize.CODE_STYLE_DEFAULTS;
if (KotlinStyleGuideCodeStyle.CODE_STYLE_ID.equals(customDefaults)) {
KotlinStyleGuideCodeStyle.Companion.applyToCommonSettings(this, true);
}
else if (KotlinObsoleteCodeStyle.CODE_STYLE_ID.equals(customDefaults)) {
KotlinObsoleteCodeStyle.Companion.applyToCommonSettings(this, true);
}
else if (customDefaults == null && FormatterUtilKt.isDefaultOfficialCodeStyle()) {
// Temporary load settings against previous defaults
settingsAgainstPreviousDefaults = createForTempDeserialize();
KotlinObsoleteCodeStyle.Companion.applyToCommonSettings(settingsAgainstPreviousDefaults, true);
settingsAgainstPreviousDefaults.readExternal(element);
}
readExternalBase(element);
}
@Override
public void writeExternal(Element element) throws WriteExternalException {
CommonCodeStyleSettings defaultSettings = getDefaultSettings();
if (defaultSettings != null) {
if (KotlinStyleGuideCodeStyle.CODE_STYLE_ID.equals(CODE_STYLE_DEFAULTS)) {
KotlinStyleGuideCodeStyle.Companion.applyToCommonSettings(defaultSettings, false);
}
else if (KotlinObsoleteCodeStyle.CODE_STYLE_ID.equals(CODE_STYLE_DEFAULTS)) {
KotlinObsoleteCodeStyle.Companion.applyToCommonSettings(defaultSettings, false);
}
}
writeExternalBase(element, defaultSettings);
}
//<editor-fold desc="Copied and adapted from CommonCodeStyleSettings ">
private void readExternalBase(Element element) throws InvalidDataException {
super.readExternal(element);
}
private void writeExternalBase(Element element, CommonCodeStyleSettings defaultSettings) throws WriteExternalException {
Set<String> supportedFields = getSupportedFields();
if (supportedFields != null) {
supportedFields.add("FORCE_REARRANGE_MODE");
supportedFields.add("CODE_STYLE_DEFAULTS");
}
//noinspection deprecation
DefaultJDOMExternalizer.writeExternal(this, element, new SupportedFieldsDiffFilter(this, supportedFields, defaultSettings));
List<Integer> softMargins = getSoftMargins();
serializeInto(softMargins, element);
IndentOptions myIndentOptions = getIndentOptions();
if (myIndentOptions != null) {
IndentOptions defaultIndentOptions = defaultSettings != null ? defaultSettings.getIndentOptions() : null;
Element indentOptionsElement = new Element(INDENT_OPTIONS_TAG);
myIndentOptions.serialize(indentOptionsElement, defaultIndentOptions);
if (!indentOptionsElement.getChildren().isEmpty()) {
element.addContent(indentOptionsElement);
}
}
ArrangementSettings myArrangementSettings = getArrangementSettings();
if (myArrangementSettings != null) {
Element container = new Element(ARRANGEMENT_ELEMENT_NAME);
ArrangementUtil.writeExternal(container, myArrangementSettings, myLanguage);
if (!container.getChildren().isEmpty()) {
element.addContent(container);
}
}
}
@Override
public CommonCodeStyleSettings clone(@NotNull CodeStyleSettings rootSettings) {
KotlinCommonCodeStyleSettings commonSettings = new KotlinCommonCodeStyleSettings();
commonSettings.settingsAgainstPreviousDefaults = settingsAgainstPreviousDefaults;
copyPublicFieldsOwn(this, commonSettings);
try {
Method setRootSettingsMethod = CommonCodeStyleSettings.class.getDeclaredMethod("setRootSettings", CodeStyleSettings.class);
setRootSettingsMethod.setAccessible(true);
setRootSettingsMethod.invoke(commonSettings, rootSettings);
}
catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException(e);
}
commonSettings.setForceArrangeMenuAvailable(isForceArrangeMenuAvailable());
IndentOptions indentOptions = getIndentOptions();
if (indentOptions != null) {
IndentOptions targetIndentOptions = commonSettings.initIndentOptions();
targetIndentOptions.copyFrom(indentOptions);
}
ArrangementSettings arrangementSettings = getArrangementSettings();
if (arrangementSettings != null) {
commonSettings.setArrangementSettings(arrangementSettings.clone());
}
try {
Method setRootSettingsMethod = ArraysKt.singleOrNull(
CommonCodeStyleSettings.class.getDeclaredMethods(),
method -> "setSoftMargins".equals(method.getName()));
if (setRootSettingsMethod != null) {
// Method was introduced in 173
setRootSettingsMethod.setAccessible(true);
setRootSettingsMethod.invoke(commonSettings, getSoftMargins());
}
}
catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException(e);
}
return commonSettings;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof KotlinCommonCodeStyleSettings)) {
return false;
}
if (!ReflectionUtil.comparePublicNonFinalFieldsWithSkip(this, obj)) {
return false;
}
CommonCodeStyleSettings other = (CommonCodeStyleSettings) obj;
if (!getSoftMargins().equals(other.getSoftMargins())) {
return false;
}
IndentOptions options = getIndentOptions();
if ((options == null && other.getIndentOptions() != null) ||
(options != null && !options.equals(other.getIndentOptions()))) {
return false;
}
return arrangementSettingsEqual(other);
}
// SoftMargins.serializeInfo
private void serializeInto(@NotNull List<Integer> softMargins, @NotNull Element element) {
if (softMargins.size() > 0) {
XmlSerializer.serializeInto(this, element);
}
}
//</editor-fold>
//<editor-fold desc="Copied from CommonCodeStyleSettings">
private static final String INDENT_OPTIONS_TAG = "indentOptions";
private static final String ARRANGEMENT_ELEMENT_NAME = "arrangement";
private final Language myLanguage = KotlinLanguage.INSTANCE;
@Nullable
private CommonCodeStyleSettings getDefaultSettings() {
return LanguageCodeStyleSettingsProvider.getDefaultCommonSettings(myLanguage);
}
@Nullable
private Set<String> getSupportedFields() {
final LanguageCodeStyleSettingsProvider provider = LanguageCodeStyleSettingsProvider.forLanguage(myLanguage);
return provider == null ? null : provider.getSupportedFields();
}
public boolean canRestore() {
return settingsAgainstPreviousDefaults != null;
}
public void restore() {
if (settingsAgainstPreviousDefaults != null) {
copyFrom(settingsAgainstPreviousDefaults);
}
}
private static class SupportedFieldsDiffFilter extends DifferenceFilter<CommonCodeStyleSettings> {
private final Set<String> mySupportedFieldNames;
public SupportedFieldsDiffFilter(
final CommonCodeStyleSettings object,
Set<String> supportedFiledNames,
final CommonCodeStyleSettings parentObject
) {
super(object, parentObject);
mySupportedFieldNames = supportedFiledNames;
}
@Override
public boolean isAccept(@NotNull Field field) {
if (mySupportedFieldNames == null ||
mySupportedFieldNames.contains(field.getName())) {
return super.isAccept(field);
}
return false;
}
}
// Can't use super.copyPublicFields because the method is internal in 181
private static void copyPublicFieldsOwn(Object from, Object to) {
assert from != to;
com.intellij.util.ReflectionUtil.copyFields(to.getClass().getFields(), from, to);
}
//</editor-fold>
}

View File

@@ -1,70 +0,0 @@
/*
* Copyright 2010-2020 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.idea.formatter
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
class KotlinObsoleteCodeStyle : KotlinPredefinedCodeStyle(CODE_STYLE_TITLE, KotlinLanguage.INSTANCE) {
override val codeStyleId: String = CODE_STYLE_ID
override fun apply(settings: CodeStyleSettings) {
Companion.apply(settings)
}
companion object {
val INSTANCE = KotlinObsoleteCodeStyle()
const val CODE_STYLE_ID = "KOTLIN_OLD_DEFAULTS"
const val CODE_STYLE_SETTING = "obsolete"
const val CODE_STYLE_TITLE = "Kotlin obsolete IntelliJ IDEA codestyle"
fun apply(settings: CodeStyleSettings) {
applyToKotlinCustomSettings(settings.kotlinCustomSettings)
applyToCommonSettings(settings.kotlinCommonSettings)
}
fun applyToKotlinCustomSettings(kotlinCustomSettings: KotlinCodeStyleSettings, modifyCodeStyle: Boolean = true) {
kotlinCustomSettings.apply {
if (modifyCodeStyle) {
CODE_STYLE_DEFAULTS = CODE_STYLE_ID
}
CONTINUATION_INDENT_IN_PARAMETER_LISTS = true
CONTINUATION_INDENT_IN_ARGUMENT_LISTS = true
CONTINUATION_INDENT_FOR_EXPRESSION_BODIES = true
CONTINUATION_INDENT_FOR_CHAINED_CALLS = true
CONTINUATION_INDENT_IN_SUPERTYPE_LISTS = true
CONTINUATION_INDENT_IN_IF_CONDITIONS = true
CONTINUATION_INDENT_IN_ELVIS = true
WRAP_EXPRESSION_BODY_FUNCTIONS = CodeStyleSettings.DO_NOT_WRAP
IF_RPAREN_ON_NEW_LINE = false
}
}
fun applyToCommonSettings(commonSettings: CommonCodeStyleSettings, modifyCodeStyle: Boolean = true) {
commonSettings.apply {
CALL_PARAMETERS_WRAP = CodeStyleSettings.DO_NOT_WRAP
CALL_PARAMETERS_LPAREN_ON_NEXT_LINE = false
CALL_PARAMETERS_RPAREN_ON_NEXT_LINE = false
METHOD_PARAMETERS_WRAP = CodeStyleSettings.DO_NOT_WRAP
METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE = false
METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE = false
EXTENDS_LIST_WRAP = CodeStyleSettings.DO_NOT_WRAP
METHOD_CALL_CHAIN_WRAP = CodeStyleSettings.DO_NOT_WRAP
ASSIGNMENT_WRAP = CodeStyleSettings.DO_NOT_WRAP
}
if (modifyCodeStyle && commonSettings is KotlinCommonCodeStyleSettings) {
commonSettings.CODE_STYLE_DEFAULTS = CODE_STYLE_ID
}
}
}
}

View File

@@ -1,13 +0,0 @@
/*
* Copyright 2010-2018 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.idea.formatter
import com.intellij.lang.Language
import com.intellij.psi.codeStyle.PredefinedCodeStyle
abstract class KotlinPredefinedCodeStyle(name: String, language: Language) : PredefinedCodeStyle(name, language) {
abstract val codeStyleId: String
}

View File

@@ -1,215 +0,0 @@
/*
* Copyright 2010-2019 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.idea.formatter
import com.intellij.formatting.*
import com.intellij.formatting.DependentSpacingRule.Anchor
import com.intellij.formatting.DependentSpacingRule.Trigger
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiComment
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.idea.util.requireNode
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.psiUtil.children
import org.jetbrains.kotlin.psi.stubs.elements.KtModifierListElementType
import kotlin.math.max
fun CommonCodeStyleSettings.createSpaceBeforeRBrace(numSpacesOtherwise: Int, textRange: TextRange): Spacing? {
return Spacing.createDependentLFSpacing(
numSpacesOtherwise, numSpacesOtherwise, textRange,
KEEP_LINE_BREAKS,
KEEP_BLANK_LINES_BEFORE_RBRACE
)
}
class KotlinSpacingBuilder(val commonCodeStyleSettings: CommonCodeStyleSettings, val spacingBuilderUtil: KotlinSpacingBuilderUtil) {
private val builders = ArrayList<Builder>()
private interface Builder {
fun getSpacing(parent: ASTBlock, left: ASTBlock, right: ASTBlock): Spacing?
}
inner class BasicSpacingBuilder : SpacingBuilder(commonCodeStyleSettings), Builder {
override fun getSpacing(parent: ASTBlock, left: ASTBlock, right: ASTBlock): Spacing? {
return super.getSpacing(parent, left, right)
}
}
private data class Condition(
val parent: IElementType? = null,
val left: IElementType? = null,
val right: IElementType? = null,
val parentSet: TokenSet? = null,
val leftSet: TokenSet? = null,
val rightSet: TokenSet? = null
) : (ASTBlock, ASTBlock, ASTBlock) -> Boolean {
override fun invoke(p: ASTBlock, l: ASTBlock, r: ASTBlock): Boolean =
(parent == null || p.requireNode().elementType == parent) &&
(left == null || l.requireNode().elementType == left) &&
(right == null || r.requireNode().elementType == right) &&
(parentSet == null || parentSet.contains(p.requireNode().elementType)) &&
(leftSet == null || leftSet.contains(l.requireNode().elementType)) &&
(rightSet == null || rightSet.contains(r.requireNode().elementType))
}
private data class Rule(
val conditions: List<Condition>,
val action: (ASTBlock, ASTBlock, ASTBlock) -> Spacing?
) : (ASTBlock, ASTBlock, ASTBlock) -> Spacing? {
override fun invoke(p: ASTBlock, l: ASTBlock, r: ASTBlock): Spacing? =
if (conditions.all { it(p, l, r) }) action(p, l, r) else null
}
inner class CustomSpacingBuilder : Builder {
private val rules = ArrayList<Rule>()
private var conditions = ArrayList<Condition>()
override fun getSpacing(parent: ASTBlock, left: ASTBlock, right: ASTBlock): Spacing? {
for (rule in rules) {
val spacing = rule(parent, left, right)
if (spacing != null) {
return spacing
}
}
return null
}
fun inPosition(
parent: IElementType? = null, left: IElementType? = null, right: IElementType? = null,
parentSet: TokenSet? = null, leftSet: TokenSet? = null, rightSet: TokenSet? = null
): CustomSpacingBuilder {
conditions.add(Condition(parent, left, right, parentSet, leftSet, rightSet))
return this
}
fun lineBreakIfLineBreakInParent(numSpacesOtherwise: Int, allowBlankLines: Boolean = true) {
newRule { p, _, _ ->
Spacing.createDependentLFSpacing(
numSpacesOtherwise, numSpacesOtherwise, p.textRange,
commonCodeStyleSettings.KEEP_LINE_BREAKS,
if (allowBlankLines) commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE else 0
)
}
}
fun emptyLinesIfLineBreakInLeft(emptyLines: Int, numberOfLineFeedsOtherwise: Int = 1, numSpacesOtherwise: Int = 0) {
newRule { _: ASTBlock, left: ASTBlock, _: ASTBlock ->
val lastChild = left.node?.psi?.lastChild
val leftEndsWithComment = lastChild is PsiComment && lastChild.tokenType == KtTokens.EOL_COMMENT
val dependentSpacingRule = DependentSpacingRule(Trigger.HAS_LINE_FEEDS).registerData(Anchor.MIN_LINE_FEEDS, emptyLines + 1)
val textRange = left.node
?.startOfDeclaration()
?.startOffset
?.let { TextRange.create(it, left.textRange.endOffset) }
?: left.textRange
spacingBuilderUtil.createLineFeedDependentSpacing(
numSpacesOtherwise,
numSpacesOtherwise,
if (leftEndsWithComment) max(1, numberOfLineFeedsOtherwise) else numberOfLineFeedsOtherwise,
commonCodeStyleSettings.KEEP_LINE_BREAKS,
commonCodeStyleSettings.KEEP_BLANK_LINES_IN_DECLARATIONS,
textRange,
dependentSpacingRule
)
}
}
fun spacing(spacing: Spacing) {
newRule { _, _, _ -> spacing }
}
fun customRule(block: (parent: ASTBlock, left: ASTBlock, right: ASTBlock) -> Spacing?) {
newRule(block)
}
private fun newRule(rule: (ASTBlock, ASTBlock, ASTBlock) -> Spacing?) {
val savedConditions = ArrayList(conditions)
rules.add(Rule(savedConditions, rule))
conditions.clear()
}
}
fun getSpacing(parent: Block, child1: Block?, child2: Block): Spacing? {
if (parent !is ASTBlock || child1 !is ASTBlock || child2 !is ASTBlock) {
return null
}
for (builder in builders) {
val spacing = builder.getSpacing(parent, child1, child2)
if (spacing != null) {
// TODO: it's a severe hack but I don't know how to implement it in other way
if (child1.requireNode().elementType == KtTokens.EOL_COMMENT && spacing.toString().contains("minLineFeeds=0")) {
val isBeforeBlock =
child2.requireNode().elementType == KtNodeTypes.BLOCK || child2.requireNode().firstChildNode
?.elementType == KtNodeTypes.BLOCK
val keepBlankLines = if (isBeforeBlock) 0 else commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE
return createSpacing(0, minLineFeeds = 1, keepLineBreaks = true, keepBlankLines = keepBlankLines)
}
return spacing
}
}
return null
}
fun simple(init: BasicSpacingBuilder.() -> Unit) {
val builder = BasicSpacingBuilder()
builder.init()
builders.add(builder)
}
fun custom(init: CustomSpacingBuilder.() -> Unit) {
val builder = CustomSpacingBuilder()
builder.init()
builders.add(builder)
}
fun createSpacing(
minSpaces: Int,
maxSpaces: Int = minSpaces,
minLineFeeds: Int = 0,
keepLineBreaks: Boolean = commonCodeStyleSettings.KEEP_LINE_BREAKS,
keepBlankLines: Int = commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE
): Spacing {
return Spacing.createSpacing(minSpaces, maxSpaces, minLineFeeds, keepLineBreaks, keepBlankLines)
}
}
interface KotlinSpacingBuilderUtil {
fun createLineFeedDependentSpacing(
minSpaces: Int,
maxSpaces: Int,
minimumLineFeeds: Int,
keepLineBreaks: Boolean,
keepBlankLines: Int,
dependency: TextRange,
rule: DependentSpacingRule
): Spacing
fun getPreviousNonWhitespaceLeaf(node: ASTNode?): ASTNode?
fun isWhitespaceOrEmpty(node: ASTNode?): Boolean
}
fun rules(
commonCodeStyleSettings: CommonCodeStyleSettings,
builderUtil: KotlinSpacingBuilderUtil,
init: KotlinSpacingBuilder.() -> Unit
): KotlinSpacingBuilder {
val builder = KotlinSpacingBuilder(commonCodeStyleSettings, builderUtil)
builder.init()
return builder
}
internal fun ASTNode.startOfDeclaration(): ASTNode? = children().firstOrNull {
val elementType = it.elementType
elementType !is KtModifierListElementType<*> && elementType !in KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET
}

View File

@@ -1,81 +0,0 @@
/*
* Copyright 2010-2020 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.idea.formatter
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CommonCodeStyleSettings
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
class KotlinStyleGuideCodeStyle : KotlinPredefinedCodeStyle("Kotlin style guide", KotlinLanguage.INSTANCE) {
override val codeStyleId: String = CODE_STYLE_ID
override fun apply(settings: CodeStyleSettings) {
Companion.apply(settings)
}
companion object {
val INSTANCE = KotlinStyleGuideCodeStyle()
const val CODE_STYLE_ID = "KOTLIN_OFFICIAL"
const val CODE_STYLE_SETTING = "official"
const val CODE_STYLE_TITLE = "Kotlin Coding Conventions"
fun apply(settings: CodeStyleSettings) {
applyToKotlinCustomSettings(settings.kotlinCustomSettings)
applyToCommonSettings(settings.kotlinCommonSettings)
}
fun applyToKotlinCustomSettings(
kotlinCustomSettings: KotlinCodeStyleSettings,
modifyCodeStyle: Boolean = true
) {
kotlinCustomSettings.apply {
if (modifyCodeStyle) {
CODE_STYLE_DEFAULTS = CODE_STYLE_ID
}
CONTINUATION_INDENT_IN_PARAMETER_LISTS = false
CONTINUATION_INDENT_IN_ARGUMENT_LISTS = false
CONTINUATION_INDENT_FOR_EXPRESSION_BODIES = false
CONTINUATION_INDENT_FOR_CHAINED_CALLS = false
CONTINUATION_INDENT_IN_SUPERTYPE_LISTS = false
CONTINUATION_INDENT_IN_IF_CONDITIONS = false
CONTINUATION_INDENT_IN_ELVIS = false
WRAP_EXPRESSION_BODY_FUNCTIONS = CodeStyleSettings.WRAP_AS_NEEDED
IF_RPAREN_ON_NEW_LINE = true
ALLOW_TRAILING_COMMA = false
}
}
fun applyToCommonSettings(commonSettings: CommonCodeStyleSettings, modifyCodeStyle: Boolean = true) {
commonSettings.apply {
WHILE_ON_NEW_LINE = false
ELSE_ON_NEW_LINE = false
CATCH_ON_NEW_LINE = false
FINALLY_ON_NEW_LINE = false
CALL_PARAMETERS_WRAP = CodeStyleSettings.WRAP_AS_NEEDED + CodeStyleSettings.WRAP_ON_EVERY_ITEM
CALL_PARAMETERS_LPAREN_ON_NEXT_LINE = true
CALL_PARAMETERS_RPAREN_ON_NEXT_LINE = true
METHOD_PARAMETERS_WRAP = CodeStyleSettings.WRAP_AS_NEEDED + CodeStyleSettings.WRAP_ON_EVERY_ITEM
METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE = true
METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE = true
EXTENDS_LIST_WRAP = CodeStyleSettings.WRAP_AS_NEEDED
METHOD_CALL_CHAIN_WRAP = CodeStyleSettings.WRAP_AS_NEEDED
ASSIGNMENT_WRAP = CodeStyleSettings.WRAP_AS_NEEDED
ALIGN_MULTILINE_BINARY_OPERATION = false
}
if (modifyCodeStyle && commonSettings is KotlinCommonCodeStyleSettings) {
commonSettings.CODE_STYLE_DEFAULTS = CODE_STYLE_ID
}
}
}
}

View File

@@ -1,50 +0,0 @@
/*
* Copyright 2010-2018 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.idea.formatter
import com.intellij.application.options.CodeStyle
import com.intellij.openapi.project.Project
import com.intellij.psi.codeStyle.CodeStyleSettings
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
data class KtCodeStyleSettings(
val custom: KotlinCodeStyleSettings,
val common: KotlinCommonCodeStyleSettings,
val all: CodeStyleSettings
)
fun KtCodeStyleSettings.canRestore(): Boolean {
return custom.canRestore() || common.canRestore()
}
fun KtCodeStyleSettings.hasDefaultLoadScheme(): Boolean {
return custom.CODE_STYLE_DEFAULTS == null || common.CODE_STYLE_DEFAULTS == null
}
fun KtCodeStyleSettings.restore() {
custom.restore()
common.restore()
}
fun ktCodeStyleSettings(project: Project): KtCodeStyleSettings? {
val settings = CodeStyle.getSettings(project)
val ktCommonSettings = settings.getCommonSettings(KotlinLanguage.INSTANCE) as KotlinCommonCodeStyleSettings
val ktCustomSettings = settings.getCustomSettings(KotlinCodeStyleSettings::class.java)
return KtCodeStyleSettings(ktCustomSettings, ktCommonSettings, settings)
}
val CodeStyleSettings.kotlinCommonSettings: KotlinCommonCodeStyleSettings
get() = getCommonSettings(KotlinLanguage.INSTANCE) as KotlinCommonCodeStyleSettings
val CodeStyleSettings.kotlinCustomSettings: KotlinCodeStyleSettings
get() = getCustomSettings(KotlinCodeStyleSettings::class.java)
fun CodeStyleSettings.kotlinCodeStyleDefaults(): String? {
return kotlinCustomSettings.CODE_STYLE_DEFAULTS ?: kotlinCommonSettings.CODE_STYLE_DEFAULTS
}

View File

@@ -1,144 +0,0 @@
/*
* Copyright 2010-2019 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.idea.formatter
import com.intellij.formatting.Indent
import com.intellij.lang.ASTNode
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import org.jetbrains.annotations.NonNls
import kotlin.collections.ArrayList
abstract class NodeIndentStrategy {
abstract fun getIndent(node: ASTNode, settings: CodeStyleSettings): Indent?
class ConstIndentStrategy(private val indent: Indent) : NodeIndentStrategy() {
override fun getIndent(node: ASTNode, settings: CodeStyleSettings): Indent? {
return indent
}
}
class PositionStrategy(private val debugInfo: String?) : NodeIndentStrategy() {
private var indentCallback: (CodeStyleSettings) -> Indent = { Indent.getNoneIndent() }
private val within = ArrayList<IElementType>()
private var withinCallback: ((ASTNode) -> Boolean)? = null
private val notIn = ArrayList<IElementType>()
private val forElement = ArrayList<IElementType>()
private val notForElement = ArrayList<IElementType>()
private var forElementCallback: ((ASTNode) -> Boolean)? = null
override fun toString(): String {
return "PositionStrategy " + (debugInfo ?: "No debug info")
}
fun set(indent: Indent): PositionStrategy {
indentCallback = { indent }
return this
}
fun set(indentCallback: (CodeStyleSettings) -> Indent): PositionStrategy {
this.indentCallback = indentCallback
return this
}
fun within(parents: TokenSet): PositionStrategy {
val types = parents.types
if (types.isEmpty()) {
throw IllegalArgumentException("Empty token set is unexpected")
}
fillTypes(within, types[0], types.copyOfRange(1, types.size))
return this
}
fun within(parentType: IElementType, vararg orParentTypes: IElementType): PositionStrategy {
fillTypes(within, parentType, orParentTypes)
return this
}
fun within(callback: (ASTNode) -> Boolean): PositionStrategy {
withinCallback = callback
return this
}
fun notWithin(parentType: IElementType, vararg orParentTypes: IElementType): PositionStrategy {
fillTypes(notIn, parentType, orParentTypes)
return this
}
fun withinAny(): PositionStrategy {
within.clear()
notIn.clear()
return this
}
fun forType(elementType: IElementType, vararg otherTypes: IElementType): PositionStrategy {
fillTypes(forElement, elementType, otherTypes)
return this
}
fun notForType(elementType: IElementType, vararg otherTypes: IElementType): PositionStrategy {
fillTypes(notForElement, elementType, otherTypes)
return this
}
fun forAny(): PositionStrategy {
forElement.clear()
notForElement.clear()
return this
}
fun forElement(callback: (ASTNode) -> Boolean): PositionStrategy {
forElementCallback = callback
return this
}
override fun getIndent(node: ASTNode, settings: CodeStyleSettings): Indent? {
if (!isValidIndent(forElement, notForElement, node, forElementCallback)) return null
val parent = node.treeParent
if (parent != null) {
if (!isValidIndent(within, notIn, parent, withinCallback)) return null
} else if (within.isNotEmpty()) return null
return indentCallback(settings)
}
private fun fillTypes(resultCollection: MutableList<IElementType>, singleType: IElementType, otherTypes: Array<out IElementType>) {
resultCollection.clear()
resultCollection.add(singleType)
resultCollection.addAll(otherTypes)
}
}
companion object {
fun constIndent(indent: Indent): NodeIndentStrategy {
return ConstIndentStrategy(indent)
}
fun strategy(@NonNls debugInfo: String?): PositionStrategy {
return PositionStrategy(debugInfo)
}
}
}
private fun isValidIndent(
elements: ArrayList<IElementType>,
excludeElements: ArrayList<IElementType>,
node: ASTNode,
callback: ((ASTNode) -> Boolean)?
): Boolean {
if (elements.isNotEmpty() && !elements.contains(node.elementType)) return false
if (excludeElements.contains(node.elementType)) return false
if (callback?.invoke(node) == false) return false
return true
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2010-2019 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.idea.formatter
import com.intellij.application.options.CodeStyle
import com.intellij.openapi.project.Project
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
object ProjectCodeStyleImporter {
fun apply(project: Project, codeStyleStr: String?): Boolean {
return when (codeStyleStr) {
KotlinObsoleteCodeStyle.CODE_STYLE_SETTING -> {
apply(project, KotlinObsoleteCodeStyle.INSTANCE)
true
}
KotlinStyleGuideCodeStyle.CODE_STYLE_SETTING -> {
apply(project, KotlinStyleGuideCodeStyle.INSTANCE)
true
}
else -> false
}
}
fun apply(project: Project, predefinedCodeStyle: KotlinPredefinedCodeStyle) {
val settingsManager = CodeStyleSettingsManager.getInstance(project)
val customSettings = CodeStyle.getSettings(project)
if (predefinedCodeStyle.codeStyleId == customSettings.kotlinCodeStyleDefaults()) {
// Don't bother user that already have correct code style
return
}
val projectSettingsUpdated: CodeStyleSettings = if (settingsManager.USE_PER_PROJECT_SETTINGS) {
customSettings.clone()
} else {
CodeStyleSettings()
}
settingsManager.USE_PER_PROJECT_SETTINGS = true
predefinedCodeStyle.apply(projectSettingsUpdated)
settingsManager.mainProjectCodeStyle = projectSettingsUpdated
}
}

View File

@@ -1,63 +0,0 @@
/*
* Copyright 2010-2019 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.idea.formatter
import com.intellij.formatting.*
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.TextRange
class SyntheticKotlinBlock(
private val node: ASTNode,
private val subBlocks: List<ASTBlock>,
private val alignment: Alignment?,
private val indent: Indent?,
private val wrap: Wrap?,
private val spacingBuilder: KotlinSpacingBuilder,
private val createParentSyntheticSpacingBlock: (ASTNode) -> ASTBlock
) : ASTBlock {
private val textRange = TextRange(
subBlocks.first().textRange.startOffset,
subBlocks.last().textRange.endOffset
)
override fun getTextRange(): TextRange = textRange
override fun getSubBlocks() = subBlocks
override fun getWrap() = wrap
override fun getIndent() = indent
override fun getAlignment() = alignment
override fun getChildAttributes(newChildIndex: Int) = ChildAttributes(getIndent(), null)
override fun isIncomplete() = getSubBlocks().last().isIncomplete
override fun isLeaf() = false
override fun getNode() = node
override fun getSpacing(child1: Block?, child2: Block): Spacing? {
return spacingBuilder.getSpacing(createParentSyntheticSpacingBlock(node), child1, child2)
}
override fun toString(): String {
var child = subBlocks.first()
var treeNode: ASTNode? = null
loop@
while (treeNode == null) when (child) {
is SyntheticKotlinBlock -> child = child.getSubBlocks().first()
else -> treeNode = child.node
}
val textRange = getTextRange()
val psi = treeNode.psi
if (psi != null) {
val file = psi.containingFile
if (file != null) {
return file.text!!.subSequence(textRange.startOffset, textRange.endOffset).toString() + " " + textRange
}
}
return this::class.java.name + ": " + textRange
}
}

View File

@@ -1,690 +0,0 @@
/*
* Copyright 2000-2018 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.idea.formatter
import com.intellij.formatting.ASTBlock
import com.intellij.formatting.DependentSpacingRule
import com.intellij.formatting.Spacing
import com.intellij.formatting.SpacingBuilder
import com.intellij.formatting.SpacingBuilder.RuleBuilder
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import com.intellij.util.text.TextRangeUtil
import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.idea.formatter.KotlinSpacingBuilder.CustomSpacingBuilder
import org.jetbrains.kotlin.idea.util.requireNode
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.children
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.psi.psiUtil.textRangeWithoutComments
val MODIFIERS_LIST_ENTRIES = TokenSet.orSet(TokenSet.create(ANNOTATION_ENTRY, ANNOTATION), MODIFIER_KEYWORDS)
val EXTEND_COLON_ELEMENTS =
TokenSet.create(TYPE_CONSTRAINT, CLASS, OBJECT_DECLARATION, TYPE_PARAMETER, ENUM_ENTRY, SECONDARY_CONSTRUCTOR)
val DECLARATIONS = TokenSet.create(PROPERTY, FUN, CLASS, OBJECT_DECLARATION, ENUM_ENTRY, SECONDARY_CONSTRUCTOR, CLASS_INITIALIZER)
fun SpacingBuilder.beforeInside(element: IElementType, tokenSet: TokenSet, spacingFun: RuleBuilder.() -> Unit) {
tokenSet.types.forEach { inType -> beforeInside(element, inType).spacingFun() }
}
fun SpacingBuilder.afterInside(element: IElementType, tokenSet: TokenSet, spacingFun: RuleBuilder.() -> Unit) {
tokenSet.types.forEach { inType -> afterInside(element, inType).spacingFun() }
}
fun RuleBuilder.spacesNoLineBreak(spaces: Int): SpacingBuilder? =
spacing(spaces, spaces, 0, false, 0)
fun createSpacingBuilder(settings: CodeStyleSettings, builderUtil: KotlinSpacingBuilderUtil): KotlinSpacingBuilder {
val kotlinCommonSettings = settings.kotlinCommonSettings
val kotlinCustomSettings = settings.kotlinCustomSettings
return rules(kotlinCommonSettings, builderUtil) {
simple {
before(FILE_ANNOTATION_LIST).lineBreakInCode()
between(IMPORT_DIRECTIVE, IMPORT_DIRECTIVE).lineBreakInCode()
after(IMPORT_LIST).blankLines(1)
}
custom {
fun commentSpacing(minSpaces: Int): Spacing {
if (kotlinCommonSettings.KEEP_FIRST_COLUMN_COMMENT) {
return Spacing.createKeepingFirstColumnSpacing(
minSpaces,
Int.MAX_VALUE,
settings.KEEP_LINE_BREAKS,
kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE
)
}
return Spacing.createSpacing(
minSpaces,
Int.MAX_VALUE,
0,
settings.KEEP_LINE_BREAKS,
kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE
)
}
// Several line comments happened to be generated in one line
inPosition(parent = null, left = EOL_COMMENT, right = EOL_COMMENT).customRule { _, _, right ->
val nodeBeforeRight = right.requireNode().treePrev
if (nodeBeforeRight is PsiWhiteSpace && !nodeBeforeRight.textContains('\n')) {
createSpacing(0, minLineFeeds = 1)
} else {
null
}
}
inPosition(right = BLOCK_COMMENT).spacing(commentSpacing(0))
inPosition(right = EOL_COMMENT).spacing(commentSpacing(1))
inPosition(parent = FUNCTION_LITERAL, right = BLOCK).customRule { _, _, right ->
when (right.node?.children()?.firstOrNull()?.elementType) {
BLOCK_COMMENT -> commentSpacing(0)
EOL_COMMENT -> commentSpacing(1)
else -> null
}
}
}
simple {
after(FILE_ANNOTATION_LIST).blankLines(1)
after(PACKAGE_DIRECTIVE).blankLines(1)
}
custom {
inPosition(leftSet = DECLARATIONS, rightSet = DECLARATIONS).customRule(fun(
_: ASTBlock,
_: ASTBlock,
right: ASTBlock
): Spacing? {
val node = right.node ?: return null
val elementStart = node.startOfDeclaration() ?: return null
return if (StringUtil.containsLineBreak(
node.text.subSequence(0, elementStart.startOffset - node.startOffset).trimStart()
)
)
createSpacing(0, minLineFeeds = 1 + kotlinCustomSettings.BLANK_LINES_BEFORE_DECLARATION_WITH_COMMENT_OR_ANNOTATION_ON_SEPARATE_LINE)
else
null
})
inPosition(left = CLASS, right = CLASS).emptyLinesIfLineBreakInLeft(1)
inPosition(left = CLASS, right = OBJECT_DECLARATION).emptyLinesIfLineBreakInLeft(1)
inPosition(left = OBJECT_DECLARATION, right = OBJECT_DECLARATION).emptyLinesIfLineBreakInLeft(1)
inPosition(left = OBJECT_DECLARATION, right = CLASS).emptyLinesIfLineBreakInLeft(1)
inPosition(left = FUN, right = FUN).emptyLinesIfLineBreakInLeft(1)
inPosition(left = PROPERTY, right = FUN).emptyLinesIfLineBreakInLeft(1)
inPosition(left = FUN, right = PROPERTY).emptyLinesIfLineBreakInLeft(1)
inPosition(left = SECONDARY_CONSTRUCTOR, right = SECONDARY_CONSTRUCTOR).emptyLinesIfLineBreakInLeft(1)
inPosition(left = TYPEALIAS, right = TYPEALIAS).emptyLinesIfLineBreakInLeft(1)
// Case left for alternative constructors
inPosition(left = FUN, right = CLASS).emptyLinesIfLineBreakInLeft(1)
inPosition(left = ENUM_ENTRY, right = ENUM_ENTRY).emptyLinesIfLineBreakInLeft(
emptyLines = 0, numberOfLineFeedsOtherwise = 0, numSpacesOtherwise = 1
)
inPosition(parent = CLASS_BODY, left = SEMICOLON).customRule { parent, _, right ->
val klass = parent.requireNode().treeParent.psi as? KtClass ?: return@customRule null
if (klass.isEnum() && right.requireNode().elementType in DECLARATIONS) {
createSpacing(0, minLineFeeds = 2, keepBlankLines = kotlinCommonSettings.KEEP_BLANK_LINES_IN_DECLARATIONS)
} else null
}
inPosition(parent = CLASS_BODY, left = LBRACE).customRule { parent, left, right ->
if (right.requireNode().elementType == RBRACE) {
return@customRule createSpacing(0)
}
val classBody = parent.requireNode().psi as KtClassBody
val parentPsi = classBody.parent as? KtClassOrObject ?: return@customRule null
if (kotlinCommonSettings.BLANK_LINES_AFTER_CLASS_HEADER == 0 || parentPsi.isObjectLiteral()) {
null
} else {
val minLineFeeds = if (right.requireNode().elementType == FUN || right.requireNode().elementType == PROPERTY)
kotlinCommonSettings.BLANK_LINES_AFTER_CLASS_HEADER + 1
else
0
builderUtil.createLineFeedDependentSpacing(
1,
1,
minLineFeeds,
commonCodeStyleSettings.KEEP_LINE_BREAKS,
commonCodeStyleSettings.KEEP_BLANK_LINES_IN_DECLARATIONS,
TextRange(parentPsi.textRange.startOffset, left.requireNode().psi.textRange.startOffset),
DependentSpacingRule(DependentSpacingRule.Trigger.HAS_LINE_FEEDS)
.registerData(
DependentSpacingRule.Anchor.MIN_LINE_FEEDS,
kotlinCommonSettings.BLANK_LINES_AFTER_CLASS_HEADER + 1
)
)
}
}
val parameterWithDocCommentRule = { _: ASTBlock, _: ASTBlock, right: ASTBlock ->
if (right.requireNode().firstChildNode.elementType == DOC_COMMENT) {
createSpacing(0, minLineFeeds = 1, keepLineBreaks = true, keepBlankLines = settings.KEEP_BLANK_LINES_IN_DECLARATIONS)
} else {
null
}
}
inPosition(parent = VALUE_PARAMETER_LIST, right = VALUE_PARAMETER).customRule(parameterWithDocCommentRule)
inPosition(parent = PROPERTY, right = PROPERTY_ACCESSOR).customRule { parent, _, _ ->
val startNode = parent.requireNode().psi.firstChild
.siblings()
.dropWhile { it is PsiComment || it is PsiWhiteSpace }.firstOrNull() ?: parent.requireNode().psi
Spacing.createDependentLFSpacing(
1, 1,
TextRange(startNode.textRange.startOffset, parent.textRange.endOffset),
false, 0
)
}
if (!kotlinCustomSettings.ALLOW_TRAILING_COMMA) {
inPosition(parent = VALUE_ARGUMENT_LIST, left = LPAR).customRule { parent, _, _ ->
if (kotlinCommonSettings.CALL_PARAMETERS_LPAREN_ON_NEXT_LINE && needWrapArgumentList(parent.requireNode().psi)) {
Spacing.createDependentLFSpacing(
0, 0,
excludeLambdasAndObjects(parent),
commonCodeStyleSettings.KEEP_LINE_BREAKS,
commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE
)
} else {
createSpacing(0)
}
}
inPosition(parent = VALUE_ARGUMENT_LIST, right = RPAR).customRule { parent, left, _ ->
when {
kotlinCommonSettings.CALL_PARAMETERS_RPAREN_ON_NEXT_LINE ->
Spacing.createDependentLFSpacing(
0, 0,
excludeLambdasAndObjects(parent),
commonCodeStyleSettings.KEEP_LINE_BREAKS,
commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE
)
left.requireNode().elementType == COMMA -> // incomplete call being edited
createSpacing(1)
else ->
createSpacing(0)
}
}
}
inPosition(left = CONDITION, right = RPAR).customRule { _, left, _ ->
if (kotlinCustomSettings.IF_RPAREN_ON_NEW_LINE) {
Spacing.createDependentLFSpacing(
0, 0,
excludeLambdasAndObjects(left),
commonCodeStyleSettings.KEEP_LINE_BREAKS,
commonCodeStyleSettings.KEEP_BLANK_LINES_IN_CODE
)
} else {
createSpacing(0)
}
}
inPosition(left = VALUE_PARAMETER, right = COMMA).customRule { _, left, _ ->
if (left.node?.lastChildNode?.elementType === EOL_COMMENT)
createSpacing(0, minLineFeeds = 1)
else
null
}
inPosition(parent = LONG_STRING_TEMPLATE_ENTRY, right = LONG_TEMPLATE_ENTRY_END).lineBreakIfLineBreakInParent(0)
inPosition(parent = LONG_STRING_TEMPLATE_ENTRY, left = LONG_TEMPLATE_ENTRY_START).lineBreakIfLineBreakInParent(0)
}
simple {
// ============ Line breaks ==============
before(DOC_COMMENT).lineBreakInCode()
between(PROPERTY, PROPERTY).lineBreakInCode()
// CLASS - CLASS, CLASS - OBJECT_DECLARATION are exception
between(CLASS, DECLARATIONS).blankLines(1)
// FUN - FUN, FUN - PROPERTY, FUN - CLASS are exceptions
between(FUN, DECLARATIONS).blankLines(1)
// PROPERTY - PROPERTY, PROPERTY - FUN are exceptions
between(PROPERTY, DECLARATIONS).blankLines(1)
// OBJECT_DECLARATION - OBJECT_DECLARATION, CLASS - OBJECT_DECLARATION are exception
between(OBJECT_DECLARATION, DECLARATIONS).blankLines(1)
between(SECONDARY_CONSTRUCTOR, DECLARATIONS).blankLines(1)
between(CLASS_INITIALIZER, DECLARATIONS).blankLines(1)
// TYPEALIAS - TYPEALIAS is an exception
between(TYPEALIAS, DECLARATIONS).blankLines(1)
// ENUM_ENTRY - ENUM_ENTRY is exception
between(ENUM_ENTRY, DECLARATIONS).blankLines(1)
between(ENUM_ENTRY, SEMICOLON).spaces(0)
between(COMMA, SEMICOLON).lineBreakInCodeIf(kotlinCustomSettings.ALLOW_TRAILING_COMMA)
beforeInside(FUN, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
beforeInside(SECONDARY_CONSTRUCTOR, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
beforeInside(CLASS, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
beforeInside(OBJECT_DECLARATION, TokenSet.create(BODY, CLASS_BODY)).lineBreakInCode()
beforeInside(PROPERTY, WHEN).spaces(0)
beforeInside(PROPERTY, LABELED_EXPRESSION).spacesNoLineBreak(1)
before(PROPERTY).lineBreakInCode()
after(DOC_COMMENT).lineBreakInCode()
// =============== Spacing ================
between(EOL_COMMENT, COMMA).lineBreakInCode()
before(COMMA).spacesNoLineBreak(if (kotlinCommonSettings.SPACE_BEFORE_COMMA) 1 else 0)
after(COMMA).spaceIf(kotlinCommonSettings.SPACE_AFTER_COMMA)
val spacesAroundAssignment = if (kotlinCommonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS) 1 else 0
beforeInside(EQ, PROPERTY).spacesNoLineBreak(spacesAroundAssignment)
beforeInside(EQ, FUN).spacing(spacesAroundAssignment, spacesAroundAssignment, 0, false, 0)
around(
TokenSet.create(EQ, MULTEQ, DIVEQ, PLUSEQ, MINUSEQ, PERCEQ)
).spaceIf(kotlinCommonSettings.SPACE_AROUND_ASSIGNMENT_OPERATORS)
around(TokenSet.create(ANDAND, OROR)).spaceIf(kotlinCommonSettings.SPACE_AROUND_LOGICAL_OPERATORS)
around(TokenSet.create(EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ)).spaceIf(kotlinCommonSettings.SPACE_AROUND_EQUALITY_OPERATORS)
aroundInside(
TokenSet.create(LT, GT, LTEQ, GTEQ), BINARY_EXPRESSION
).spaceIf(kotlinCommonSettings.SPACE_AROUND_RELATIONAL_OPERATORS)
aroundInside(TokenSet.create(PLUS, MINUS), BINARY_EXPRESSION).spaceIf(kotlinCommonSettings.SPACE_AROUND_ADDITIVE_OPERATORS)
aroundInside(
TokenSet.create(MUL, DIV, PERC), BINARY_EXPRESSION
).spaceIf(kotlinCommonSettings.SPACE_AROUND_MULTIPLICATIVE_OPERATORS)
around(
TokenSet.create(PLUSPLUS, MINUSMINUS, EXCLEXCL, MINUS, PLUS, EXCL)
).spaceIf(kotlinCommonSettings.SPACE_AROUND_UNARY_OPERATOR)
before(ELVIS).spaces(1)
after(ELVIS).spacesNoLineBreak(1)
around(RANGE).spaceIf(kotlinCustomSettings.SPACE_AROUND_RANGE)
after(MODIFIER_LIST).spaces(1)
beforeInside(IDENTIFIER, CLASS).spaces(1)
beforeInside(IDENTIFIER, OBJECT_DECLARATION).spaces(1)
after(VAL_KEYWORD).spaces(1)
after(VAR_KEYWORD).spaces(1)
betweenInside(TYPE_PARAMETER_LIST, IDENTIFIER, PROPERTY).spaces(1)
betweenInside(TYPE_REFERENCE, DOT, PROPERTY).spacing(0, 0, 0, false, 0)
betweenInside(DOT, IDENTIFIER, PROPERTY).spacing(0, 0, 0, false, 0)
betweenInside(RETURN_KEYWORD, LABEL_QUALIFIER, RETURN).spaces(0)
afterInside(RETURN_KEYWORD, RETURN).spaces(1)
afterInside(LABEL_QUALIFIER, RETURN).spaces(1)
betweenInside(LABEL_QUALIFIER, EOL_COMMENT, LABELED_EXPRESSION).spacing(
0, Int.MAX_VALUE, 0, true, kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE
)
betweenInside(LABEL_QUALIFIER, BLOCK_COMMENT, LABELED_EXPRESSION).spacing(
0, Int.MAX_VALUE, 0, true, kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE
)
betweenInside(LABEL_QUALIFIER, LAMBDA_EXPRESSION, LABELED_EXPRESSION).spaces(0)
afterInside(LABEL_QUALIFIER, LABELED_EXPRESSION).spaces(1)
betweenInside(FUN_KEYWORD, VALUE_PARAMETER_LIST, FUN).spacing(0, 0, 0, false, 0)
after(FUN_KEYWORD).spaces(1)
betweenInside(TYPE_PARAMETER_LIST, TYPE_REFERENCE, FUN).spaces(1)
betweenInside(TYPE_PARAMETER_LIST, IDENTIFIER, FUN).spaces(1)
betweenInside(TYPE_REFERENCE, DOT, FUN).spacing(0, 0, 0, false, 0)
betweenInside(DOT, IDENTIFIER, FUN).spacing(0, 0, 0, false, 0)
afterInside(IDENTIFIER, FUN).spacing(0, 0, 0, false, 0)
aroundInside(DOT, USER_TYPE).spaces(0)
around(AS_KEYWORD).spaces(1)
around(AS_SAFE).spaces(1)
around(IS_KEYWORD).spaces(1)
around(NOT_IS).spaces(1)
around(IN_KEYWORD).spaces(1)
around(NOT_IN).spaces(1)
aroundInside(IDENTIFIER, BINARY_EXPRESSION).spaces(1)
// before LPAR in constructor(): this() {}
after(CONSTRUCTOR_DELEGATION_REFERENCE).spacing(0, 0, 0, false, 0)
// class A() - no space before LPAR of PRIMARY_CONSTRUCTOR
// class A private() - one space before modifier
custom {
inPosition(right = PRIMARY_CONSTRUCTOR).customRule { _, _, r ->
val spacesCount = if (r.requireNode().findLeafElementAt(0)?.elementType != LPAR) 1 else 0
createSpacing(spacesCount, minLineFeeds = 0, keepLineBreaks = true, keepBlankLines = 0)
}
}
afterInside(CONSTRUCTOR_KEYWORD, PRIMARY_CONSTRUCTOR).spaces(0)
betweenInside(IDENTIFIER, TYPE_PARAMETER_LIST, CLASS).spaces(0)
beforeInside(DOT, DOT_QUALIFIED_EXPRESSION).spaces(0)
afterInside(DOT, DOT_QUALIFIED_EXPRESSION).spacesNoLineBreak(0)
beforeInside(SAFE_ACCESS, SAFE_ACCESS_EXPRESSION).spaces(0)
afterInside(SAFE_ACCESS, SAFE_ACCESS_EXPRESSION).spacesNoLineBreak(0)
between(MODIFIERS_LIST_ENTRIES, MODIFIERS_LIST_ENTRIES).spaces(1)
after(LBRACKET).spaces(0)
before(RBRACKET).spaces(0)
afterInside(LPAR, VALUE_PARAMETER_LIST).spaces(0, kotlinCommonSettings.METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE)
beforeInside(RPAR, VALUE_PARAMETER_LIST).spaces(0, kotlinCommonSettings.METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE)
afterInside(LT, TYPE_PARAMETER_LIST).spaces(0)
beforeInside(GT, TYPE_PARAMETER_LIST).spaces(0)
afterInside(LT, TYPE_ARGUMENT_LIST).spaces(0)
beforeInside(GT, TYPE_ARGUMENT_LIST).spaces(0)
before(TYPE_ARGUMENT_LIST).spaces(0)
after(LPAR).spaces(0)
before(RPAR).spaces(0)
betweenInside(FOR_KEYWORD, LPAR, FOR).spaceIf(kotlinCommonSettings.SPACE_BEFORE_FOR_PARENTHESES)
betweenInside(IF_KEYWORD, LPAR, IF).spaceIf(kotlinCommonSettings.SPACE_BEFORE_IF_PARENTHESES)
betweenInside(WHILE_KEYWORD, LPAR, WHILE).spaceIf(kotlinCommonSettings.SPACE_BEFORE_WHILE_PARENTHESES)
betweenInside(WHILE_KEYWORD, LPAR, DO_WHILE).spaceIf(kotlinCommonSettings.SPACE_BEFORE_WHILE_PARENTHESES)
betweenInside(WHEN_KEYWORD, LPAR, WHEN).spaceIf(kotlinCustomSettings.SPACE_BEFORE_WHEN_PARENTHESES)
betweenInside(CATCH_KEYWORD, VALUE_PARAMETER_LIST, CATCH).spaceIf(kotlinCommonSettings.SPACE_BEFORE_CATCH_PARENTHESES)
betweenInside(LPAR, VALUE_PARAMETER, FOR).spaces(0)
betweenInside(LPAR, DESTRUCTURING_DECLARATION, FOR).spaces(0)
betweenInside(LOOP_RANGE, RPAR, FOR).spaces(0)
afterInside(ANNOTATION_ENTRY, ANNOTATED_EXPRESSION).spaces(1)
before(SEMICOLON).spaces(0)
beforeInside(INITIALIZER_LIST, ENUM_ENTRY).spaces(0)
beforeInside(QUEST, NULLABLE_TYPE).spaces(0)
val TYPE_COLON_ELEMENTS = TokenSet.create(PROPERTY, FUN, VALUE_PARAMETER, DESTRUCTURING_DECLARATION_ENTRY, FUNCTION_LITERAL)
beforeInside(COLON, TYPE_COLON_ELEMENTS) { spaceIf(kotlinCustomSettings.SPACE_BEFORE_TYPE_COLON) }
afterInside(COLON, TYPE_COLON_ELEMENTS) { spaceIf(kotlinCustomSettings.SPACE_AFTER_TYPE_COLON) }
afterInside(COLON, EXTEND_COLON_ELEMENTS) { spaceIf(kotlinCustomSettings.SPACE_AFTER_EXTEND_COLON) }
beforeInside(ARROW, FUNCTION_LITERAL).spaceIf(kotlinCustomSettings.SPACE_BEFORE_LAMBDA_ARROW)
aroundInside(ARROW, FUNCTION_TYPE).spaceIf(kotlinCustomSettings.SPACE_AROUND_FUNCTION_TYPE_ARROW)
before(VALUE_ARGUMENT_LIST).spaces(0)
between(VALUE_ARGUMENT_LIST, LAMBDA_ARGUMENT).spaces(1)
betweenInside(REFERENCE_EXPRESSION, LAMBDA_ARGUMENT, CALL_EXPRESSION).spaces(1)
betweenInside(TYPE_ARGUMENT_LIST, LAMBDA_ARGUMENT, CALL_EXPRESSION).spaces(1)
around(COLONCOLON).spaces(0)
around(BY_KEYWORD).spaces(1)
betweenInside(IDENTIFIER, PROPERTY_DELEGATE, PROPERTY).spaces(1)
betweenInside(TYPE_REFERENCE, PROPERTY_DELEGATE, PROPERTY).spaces(1)
before(INDICES).spaces(0)
before(WHERE_KEYWORD).spaces(1)
afterInside(GET_KEYWORD, PROPERTY_ACCESSOR).spaces(0)
afterInside(SET_KEYWORD, PROPERTY_ACCESSOR).spaces(0)
}
custom {
fun CustomSpacingBuilder.ruleForKeywordOnNewLine(
shouldBeOnNewLine: Boolean,
keyword: IElementType,
parent: IElementType,
afterBlockFilter: (wordParent: ASTNode, block: ASTNode) -> Boolean = { _, _ -> true }
) {
if (shouldBeOnNewLine) {
inPosition(parent = parent, right = keyword)
.lineBreakIfLineBreakInParent(numSpacesOtherwise = 1, allowBlankLines = false)
} else {
inPosition(parent = parent, right = keyword).customRule { _, _, right ->
val previousLeaf = builderUtil.getPreviousNonWhitespaceLeaf(right.requireNode())
val leftBlock = if (
previousLeaf != null &&
previousLeaf.elementType == RBRACE &&
previousLeaf.treeParent?.elementType == BLOCK
) {
previousLeaf.treeParent!!
} else null
val removeLineBreaks = leftBlock != null && afterBlockFilter(right.node?.treeParent!!, leftBlock)
createSpacing(1, minLineFeeds = 0, keepLineBreaks = !removeLineBreaks, keepBlankLines = 0)
}
}
}
ruleForKeywordOnNewLine(kotlinCommonSettings.ELSE_ON_NEW_LINE, keyword = ELSE_KEYWORD, parent = IF) { keywordParent, block ->
block.treeParent?.elementType == THEN && block.treeParent?.treeParent == keywordParent
}
ruleForKeywordOnNewLine(
kotlinCommonSettings.WHILE_ON_NEW_LINE,
keyword = WHILE_KEYWORD,
parent = DO_WHILE
) { keywordParent, block ->
block.treeParent?.elementType == BODY && block.treeParent?.treeParent == keywordParent
}
ruleForKeywordOnNewLine(kotlinCommonSettings.CATCH_ON_NEW_LINE, keyword = CATCH, parent = TRY)
ruleForKeywordOnNewLine(kotlinCommonSettings.FINALLY_ON_NEW_LINE, keyword = FINALLY, parent = TRY)
fun spacingForLeftBrace(block: ASTNode?, blockType: IElementType = BLOCK): Spacing? {
if (block != null && block.elementType == blockType) {
val leftBrace = block.findChildByType(LBRACE)
if (leftBrace != null) {
val previousLeaf = builderUtil.getPreviousNonWhitespaceLeaf(leftBrace)
val isAfterEolComment = previousLeaf != null && (previousLeaf.elementType == EOL_COMMENT)
val keepLineBreaks = kotlinCustomSettings.LBRACE_ON_NEXT_LINE || isAfterEolComment
val minimumLF = if (kotlinCustomSettings.LBRACE_ON_NEXT_LINE) 1 else 0
return createSpacing(1, minLineFeeds = minimumLF, keepLineBreaks = keepLineBreaks, keepBlankLines = 0)
}
}
return createSpacing(1)
}
fun leftBraceRule(blockType: IElementType = BLOCK) = { _: ASTBlock, _: ASTBlock, right: ASTBlock ->
spacingForLeftBrace(right.node, blockType)
}
val leftBraceRuleIfBlockIsWrapped = { _: ASTBlock, _: ASTBlock, right: ASTBlock ->
spacingForLeftBrace(right.requireNode().firstChildNode)
}
// Add space after a semicolon if there is another child at the same line
inPosition(left = SEMICOLON).customRule { _, left, _ ->
val nodeAfterLeft = left.requireNode().treeNext
if (nodeAfterLeft is PsiWhiteSpace && !nodeAfterLeft.textContains('\n')) {
createSpacing(1)
} else {
null
}
}
inPosition(parent = IF, right = THEN).customRule(leftBraceRuleIfBlockIsWrapped)
inPosition(parent = IF, right = ELSE).customRule(leftBraceRuleIfBlockIsWrapped)
inPosition(parent = FOR, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped)
inPosition(parent = WHILE, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped)
inPosition(parent = DO_WHILE, right = BODY).customRule(leftBraceRuleIfBlockIsWrapped)
inPosition(parent = TRY, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = CATCH, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = FINALLY, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = FUN, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = SECONDARY_CONSTRUCTOR, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = CLASS_INITIALIZER, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = PROPERTY_ACCESSOR, right = BLOCK).customRule(leftBraceRule())
inPosition(right = CLASS_BODY).customRule(leftBraceRule(blockType = CLASS_BODY))
inPosition(left = WHEN_ENTRY, right = WHEN_ENTRY).customRule { _, left, right ->
val leftEntry = left.requireNode().psi as KtWhenEntry
val rightEntry = right.requireNode().psi as KtWhenEntry
val blankLines = if (leftEntry.expression is KtBlockExpression || rightEntry.expression is KtBlockExpression)
settings.kotlinCustomSettings.BLANK_LINES_AROUND_BLOCK_WHEN_BRANCHES
else
0
createSpacing(0, minLineFeeds = blankLines + 1)
}
inPosition(parent = WHEN_ENTRY, right = BLOCK).customRule(leftBraceRule())
inPosition(parent = WHEN, right = LBRACE).customRule { parent, _, _ ->
spacingForLeftBrace(block = parent.requireNode(), blockType = WHEN)
}
inPosition(left = LBRACE, right = WHEN_ENTRY).customRule { _, _, _ ->
createSpacing(0, minLineFeeds = 1)
}
val spacesInSimpleFunction = if (kotlinCustomSettings.INSERT_WHITESPACES_IN_SIMPLE_ONE_LINE_METHOD) 1 else 0
inPosition(
parent = FUNCTION_LITERAL,
left = LBRACE,
right = BLOCK
).lineBreakIfLineBreakInParent(numSpacesOtherwise = spacesInSimpleFunction)
inPosition(
parent = FUNCTION_LITERAL,
left = ARROW,
right = BLOCK
).lineBreakIfLineBreakInParent(numSpacesOtherwise = 1)
inPosition(
parent = FUNCTION_LITERAL,
left = LBRACE,
right = RBRACE
).spacing(createSpacing(minSpaces = 0, maxSpaces = 1))
inPosition(
parent = FUNCTION_LITERAL,
right = RBRACE
).lineBreakIfLineBreakInParent(numSpacesOtherwise = spacesInSimpleFunction)
inPosition(
parent = FUNCTION_LITERAL,
left = LBRACE
).customRule { _, _, right ->
val rightNode = right.requireNode()
val rightType = rightNode.elementType
if (rightType == VALUE_PARAMETER_LIST) {
createSpacing(spacesInSimpleFunction, keepLineBreaks = false)
} else {
createSpacing(spacesInSimpleFunction)
}
}
inPosition(parent = CLASS_BODY, right = RBRACE).customRule { parent, _, _ ->
kotlinCommonSettings.createSpaceBeforeRBrace(1, parent.textRange)
}
inPosition(parent = BLOCK, right = RBRACE).customRule { block, left, _ ->
val psiElement = block.requireNode().treeParent.psi
val empty = left.requireNode().elementType == LBRACE
when (psiElement) {
is KtFunction -> {
if (psiElement.name != null && !empty) return@customRule null
}
is KtPropertyAccessor ->
if (!empty) return@customRule null
else ->
return@customRule null
}
val spaces = if (empty) 0 else spacesInSimpleFunction
kotlinCommonSettings.createSpaceBeforeRBrace(spaces, psiElement.textRangeWithoutComments)
}
inPosition(parent = BLOCK, left = LBRACE).customRule { parent, _, _ ->
val psiElement = parent.requireNode().treeParent.psi
val funNode = psiElement as? KtFunction ?: return@customRule null
if (funNode.name != null) return@customRule null
// Empty block is covered in above rule
Spacing.createDependentLFSpacing(
spacesInSimpleFunction, spacesInSimpleFunction, funNode.textRangeWithoutComments,
kotlinCommonSettings.KEEP_LINE_BREAKS,
kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE
)
}
inPosition(parentSet = EXTEND_COLON_ELEMENTS, left = PRIMARY_CONSTRUCTOR, right = COLON).customRule { _, left, _ ->
val primaryConstructor = left.requireNode().psi as KtPrimaryConstructor
val rightParenthesis = primaryConstructor.valueParameterList?.rightParenthesis
val prevSibling = rightParenthesis?.prevSibling
val spaces = if (kotlinCustomSettings.SPACE_BEFORE_EXTEND_COLON) 1 else 0
// TODO This should use DependentSpacingRule, but it doesn't set keepLineBreaks to false if max LFs is 0
if ((prevSibling as? PsiWhiteSpace)?.textContains('\n') == true || kotlinCommonSettings
.METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE
) {
createSpacing(spaces, keepLineBreaks = false)
} else {
createSpacing(spaces)
}
}
inPosition(
parent = CLASS_BODY,
left = LBRACE,
right = ENUM_ENTRY
).lineBreakIfLineBreakInParent(numSpacesOtherwise = 1)
}
simple {
afterInside(LBRACE, BLOCK).lineBreakInCode()
beforeInside(RBRACE, BLOCK).spacing(
1, 0, 1,
kotlinCommonSettings.KEEP_LINE_BREAKS,
kotlinCommonSettings.KEEP_BLANK_LINES_BEFORE_RBRACE
)
between(LBRACE, ENUM_ENTRY).spacing(1, 0, 0, true, kotlinCommonSettings.KEEP_BLANK_LINES_IN_CODE)
beforeInside(RBRACE, WHEN).lineBreakInCode()
between(RPAR, BODY).spaces(1)
// if when entry has block, spacing after arrow should be set by lbrace rule
aroundInside(ARROW, WHEN_ENTRY).spaceIf(kotlinCustomSettings.SPACE_AROUND_WHEN_ARROW)
beforeInside(COLON, EXTEND_COLON_ELEMENTS) { spaceIf(kotlinCustomSettings.SPACE_BEFORE_EXTEND_COLON) }
after(EOL_COMMENT).lineBreakInCode()
}
}
}
private fun excludeLambdasAndObjects(parent: ASTBlock): List<TextRange> {
val rangesToExclude = mutableListOf<TextRange>()
parent.requireNode().psi.accept(object : KtTreeVisitorVoid() {
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
super.visitLambdaExpression(lambdaExpression)
rangesToExclude.add(lambdaExpression.textRange)
}
override fun visitObjectLiteralExpression(expression: KtObjectLiteralExpression) {
super.visitObjectLiteralExpression(expression)
rangesToExclude.add(expression.textRange)
}
override fun visitNamedFunction(function: KtNamedFunction) {
super.visitNamedFunction(function)
if (function.name == null) {
rangesToExclude.add(function.textRange)
}
}
})
return TextRangeUtil.excludeRanges(parent.textRange, rangesToExclude).toList()
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright 2010-2020 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.idea.formatter.trailingComma
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.psi.KtElement
class TrailingCommaContext private constructor(val element: PsiElement, val state: TrailingCommaState) {
/**
* Return [KtElement] if [state] != [TrailingCommaState.NOT_APPLICABLE]
*/
val ktElement: KtElement get() = element as? KtElement ?: error("State is NOT_APPLICABLE")
companion object {
fun create(element: PsiElement): TrailingCommaContext = TrailingCommaContext(
element,
TrailingCommaState.stateForElement(element),
)
}
}
fun TrailingCommaContext.commaExistsOrMayExist(settings: KotlinCodeStyleSettings): Boolean = when (state) {
TrailingCommaState.EXISTS -> true
TrailingCommaState.MISSING -> settings.addTrailingCommaIsAllowedFor(element)
else -> false
}

View File

@@ -1,86 +0,0 @@
/*
* Copyright 2010-2020 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.idea.formatter.trailingComma
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiErrorElement
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.tree.TokenSet
import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.idea.formatter.kotlinCustomSettings
import org.jetbrains.kotlin.idea.util.isComma
import org.jetbrains.kotlin.idea.util.isLineBreak
import org.jetbrains.kotlin.idea.util.leafIgnoringWhitespace
import org.jetbrains.kotlin.idea.util.leafIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getPrevSiblingIgnoringWhitespaceAndComments
import org.jetbrains.kotlin.psi.psiUtil.prevLeaf
import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.utils.addToStdlib.cast
object TrailingCommaHelper {
fun findInvalidCommas(commaOwner: KtElement): List<PsiElement> = commaOwner.firstChild
?.siblings(withItself = false)
?.filter { it.isComma }
?.filter {
it.prevLeaf(true)?.isLineBreak() == true || it.leafIgnoringWhitespace(false) != it.leafIgnoringWhitespaceAndComments(false)
}?.toList().orEmpty()
fun trailingCommaExistsOrCanExist(psiElement: PsiElement, settings: CodeStyleSettings): Boolean =
TrailingCommaContext.create(psiElement).commaExistsOrMayExist(settings.kotlinCustomSettings)
fun trailingCommaExists(commaOwner: KtElement): Boolean = when (commaOwner) {
is KtFunctionLiteral -> commaOwner.valueParameterList?.trailingComma != null
is KtWhenEntry -> commaOwner.trailingComma != null
is KtDestructuringDeclaration -> commaOwner.trailingComma != null
else -> trailingCommaOrLastElement(commaOwner)?.isComma == true
}
fun trailingCommaOrLastElement(commaOwner: KtElement): PsiElement? {
val lastChild = commaOwner.lastSignificantChild ?: return null
val withSelf = when (PsiUtil.getElementType(lastChild)) {
KtTokens.COMMA -> return lastChild
in RIGHT_BARRIERS -> false
else -> true
}
return lastChild.getPrevSiblingIgnoringWhitespaceAndComments(withSelf)?.takeIf {
PsiUtil.getElementType(it) !in LEFT_BARRIERS
}?.takeIfIsNotError()
}
fun elementBeforeFirstElement(commaOwner: KtElement): PsiElement? = when (commaOwner) {
is KtParameterList -> {
val parent = commaOwner.parent
if (parent is KtFunctionLiteral) parent.lBrace else commaOwner.leftParenthesis
}
is KtWhenEntry -> commaOwner.parent.cast<KtWhenExpression>().openBrace
is KtDestructuringDeclaration -> commaOwner.lPar
else -> commaOwner.firstChild?.takeIfIsNotError()
}
fun elementAfterLastElement(commaOwner: KtElement): PsiElement? = when (commaOwner) {
is KtParameterList -> {
val parent = commaOwner.parent
if (parent is KtFunctionLiteral) parent.arrow else commaOwner.rightParenthesis
}
is KtWhenEntry -> commaOwner.arrow
is KtDestructuringDeclaration -> commaOwner.rPar
else -> commaOwner.lastChild?.takeIfIsNotError()
}
private fun PsiElement.takeIfIsNotError(): PsiElement? = takeIf { it !is PsiErrorElement }
private val RIGHT_BARRIERS = TokenSet.create(KtTokens.RBRACKET, KtTokens.RPAR, KtTokens.RBRACE, KtTokens.GT, KtTokens.ARROW)
private val LEFT_BARRIERS = TokenSet.create(KtTokens.LBRACKET, KtTokens.LPAR, KtTokens.LBRACE, KtTokens.LT)
private val PsiElement.lastSignificantChild: PsiElement?
get() = when (this) {
is KtWhenEntry -> arrow
is KtDestructuringDeclaration -> rPar
else -> lastChild
}
}

View File

@@ -1,90 +0,0 @@
/*
* Copyright 2010-2020 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.idea.formatter.trailingComma
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.util.containsLineBreakInChild
import org.jetbrains.kotlin.idea.util.isMultiline
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
enum class TrailingCommaState {
/**
* The trailing comma is needed and exists
*/
EXISTS,
/**
* The trailing comma is needed and doesn't exists
*/
MISSING,
/**
* The trailing comma isn't needed and doesn't exists
*/
NOT_EXISTS,
/**
* The trailing comma isn't needed, but exists
*/
REDUNDANT,
/**
* The trailing comma isn't applicable for this element
*/
NOT_APPLICABLE,
;
companion object {
fun stateForElement(element: PsiElement): TrailingCommaState = when {
element !is KtElement || !element.canAddTrailingComma() -> NOT_APPLICABLE
isMultiline(element) ->
if (TrailingCommaHelper.trailingCommaExists(element))
EXISTS
else
MISSING
else ->
if (TrailingCommaHelper.trailingCommaExists(element))
REDUNDANT
else
NOT_EXISTS
}
}
}
private fun isMultiline(ktElement: KtElement): Boolean = when {
ktElement.parent is KtFunctionLiteral -> isMultiline(ktElement.parent as KtElement)
ktElement is KtFunctionLiteral -> ktElement.isMultiline(
startOffsetGetter = { valueParameterList?.startOffset },
endOffsetGetter = { arrow?.endOffset },
)
ktElement is KtWhenEntry -> ktElement.isMultiline(
startOffsetGetter = { startOffset },
endOffsetGetter = { arrow?.endOffset },
)
ktElement is KtDestructuringDeclaration -> ktElement.isMultiline(
startOffsetGetter = { lPar?.startOffset },
endOffsetGetter = { rPar?.endOffset },
)
else -> ktElement.isMultiline()
}
private fun <T : PsiElement> T.isMultiline(
startOffsetGetter: T.() -> Int?,
endOffsetGetter: T.() -> Int?,
): Boolean {
val startOffset = startOffsetGetter() ?: startOffset
val endOffset = endOffsetGetter() ?: endOffset
return containsLineBreakInChild(startOffset, endOffset)
}

View File

@@ -1,66 +0,0 @@
/*
* Copyright 2010-2020 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.idea.formatter.trailingComma
import com.intellij.lang.ASTNode
import com.intellij.openapi.util.registry.Registry
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.TokenSet
import com.intellij.psi.util.PsiUtilCore
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.utils.addToStdlib.cast
fun trailingCommaIsAllowedOnCallSite(): Boolean = Registry.`is`("kotlin.formatter.allowTrailingCommaOnCallSite")
private val TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE = TokenSet.create(
KtNodeTypes.TYPE_PARAMETER_LIST,
KtNodeTypes.DESTRUCTURING_DECLARATION,
KtNodeTypes.WHEN_ENTRY,
KtNodeTypes.FUNCTION_LITERAL,
KtNodeTypes.VALUE_PARAMETER_LIST,
)
private val TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE = TokenSet.create(
KtNodeTypes.COLLECTION_LITERAL_EXPRESSION,
KtNodeTypes.TYPE_ARGUMENT_LIST,
KtNodeTypes.INDICES,
KtNodeTypes.VALUE_ARGUMENT_LIST,
)
private val TYPES_WITH_TRAILING_COMMA = TokenSet.orSet(
TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE,
TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE,
)
fun PsiElement.canAddTrailingCommaWithRegistryCheck(): Boolean {
val type = PsiUtilCore.getElementType(this) ?: return false
return type in TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE ||
trailingCommaIsAllowedOnCallSite() && type in TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE
}
fun KotlinCodeStyleSettings.addTrailingCommaIsAllowedFor(node: ASTNode): Boolean =
addTrailingCommaIsAllowedFor(PsiUtilCore.getElementType(node))
fun KotlinCodeStyleSettings.addTrailingCommaIsAllowedFor(element: PsiElement): Boolean =
addTrailingCommaIsAllowedFor(PsiUtilCore.getElementType(element))
private fun KotlinCodeStyleSettings.addTrailingCommaIsAllowedFor(type: IElementType?): Boolean = when (type) {
null -> false
in TYPES_WITH_TRAILING_COMMA_ON_DECLARATION_SITE -> ALLOW_TRAILING_COMMA
in TYPES_WITH_TRAILING_COMMA_ON_CALL_SITE -> ALLOW_TRAILING_COMMA_ON_CALL_SITE || trailingCommaIsAllowedOnCallSite()
else -> false
}
fun PsiElement.canAddTrailingComma(): Boolean = when {
this is KtWhenEntry && (isElse || parent.cast<KtWhenExpression>().leftParenthesis == null) -> false
this is KtFunctionLiteral && arrow == null -> false
else -> PsiUtilCore.getElementType(this) in TYPES_WITH_TRAILING_COMMA
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2010-2020 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.idea.util
import com.intellij.formatting.ASTBlock
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import com.intellij.psi.util.PsiUtil
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.psiUtil.*
/*
* ASTBlock.node is nullable, this extension was introduced to minimize changes
*/
fun ASTBlock.requireNode() = node ?: error("ASTBlock.getNode() returned null")
/**
* Can be removed with all usages after moving master to 1.3 with new default code style settings.
*/
val isDefaultOfficialCodeStyle by lazy { !KotlinCodeStyleSettings.defaultSettings().CONTINUATION_INDENT_FOR_CHAINED_CALLS }
// Copied from idea-core
fun PsiElement.getLineCount(): Int {
val spaceRange = textRange ?: TextRange.EMPTY_RANGE
return getLineCountByDocument(spaceRange.startOffset, spaceRange.endOffset)
?: StringUtil.getLineBreakCount(text ?: error("Cannot count number of lines")) + 1
}
fun PsiElement.getLineCountByDocument(startOffset: Int, endOffset: Int): Int? {
val doc = containingFile?.let { PsiDocumentManager.getInstance(project).getDocument(it) } ?: return null
if (endOffset > doc.textLength || startOffset >= endOffset) return null
val startLine = doc.getLineNumber(startOffset)
val endLine = doc.getLineNumber(endOffset)
return endLine - startLine + 1
}
fun PsiElement.isMultiline() = getLineCount() > 1
fun PsiElement?.isLineBreak() = this is PsiWhiteSpace && StringUtil.containsLineBreak(text)
fun PsiElement.leafIgnoringWhitespace(forward: Boolean = true, skipEmptyElements: Boolean = true) =
leaf(forward) { (!skipEmptyElements || it.textLength != 0) && it !is PsiWhiteSpace }
fun PsiElement.leafIgnoringWhitespaceAndComments(forward: Boolean = true, skipEmptyElements: Boolean = true) =
leaf(forward) { (!skipEmptyElements || it.textLength != 0) && it !is PsiWhiteSpace && it !is PsiComment }
fun PsiElement.leaf(forward: Boolean = true, filter: (PsiElement) -> Boolean): PsiElement? =
if (forward) nextLeaf(filter)
else prevLeaf(filter)
val PsiElement.isComma: Boolean get() = PsiUtil.getElementType(this) == KtTokens.COMMA
fun PsiElement.containsLineBreakInChild(globalStartOffset: Int, globalEndOffset: Int): Boolean =
getLineCountByDocument(globalStartOffset, globalEndOffset)?.let { it > 1 }
?: firstChild.siblings(forward = true, withItself = true)
.dropWhile { it.startOffset < globalStartOffset }
.takeWhile { it.endOffset <= globalEndOffset }
.any { it.textContains('\n') || it.textContains('\r') }

View File

@@ -1,61 +0,0 @@
/*
* Copyright 2010-2019 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.idea.util;
import com.intellij.openapi.util.Comparing;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Predicate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Set;
public class ReflectionUtil {
@Retention(RetentionPolicy.RUNTIME)
public @interface SkipInEquals {
}
public static boolean comparePublicNonFinalFieldsWithSkip(@NotNull Object first, @NotNull Object second) {
return comparePublicNonFinalFields(first, second, field -> field.getAnnotation(SkipInEquals.class) == null);
}
private static boolean comparePublicNonFinalFields(
@NotNull Object first,
@NotNull Object second,
@Nullable Predicate<Field> acceptPredicate
) {
Set<Field> firstFields = ContainerUtil.newHashSet(first.getClass().getFields());
for (Field field : second.getClass().getFields()) {
if (firstFields.contains(field)) {
if (isPublic(field) && !isFinal(field) && (acceptPredicate == null || acceptPredicate.apply(field))) {
try {
if (!Comparing.equal(field.get(first), field.get(second))) {
return false;
}
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
return true;
}
private static boolean isPublic(Field field) {
return (field.getModifiers() & Modifier.PUBLIC) != 0;
}
private static boolean isFinal(Field field) {
return (field.getModifiers() & Modifier.FINAL) != 0;
}
}

View File

@@ -1,25 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compileOnly(project(":compiler:util"))
compileOnly(project(":compiler:frontend"))
compileOnly(project(":compiler:frontend.java"))
compileOnly(project(":js:js.frontend"))
compileOnly(project(":js:js.serializer"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) }
}
sourceSets {
"main" { projectDefault() }
"test" {}
}
sourcesJar()
javadocJar()
apply(from = "$rootDir/gradle/kotlinPluginPublication.gradle.kts")

View File

@@ -1,62 +0,0 @@
/*
* Copyright 2010-2019 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.caches.project
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.openapi.util.UserDataHolder
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
fun <T> Module.cacheByClass(classForKey: Class<*>, vararg dependencies: Any, provider: () -> T): T {
return CachedValuesManager.getManager(project).cache(this, dependencies, classForKey, provider)
}
fun <T> Module.cacheByClassInvalidatingOnRootModifications(classForKey: Class<*>, provider: () -> T): T {
return cacheByClass(classForKey, ProjectRootModificationTracker.getInstance(project), provider = provider)
}
/**
* Note that it uses lambda's class for caching (essentially, anonymous class), which means that all invocations will be cached
* by the one and the same key.
* It is encouraged to use explicit class, just for the sake of readability.
*/
fun <T> Module.cacheInvalidatingOnRootModifications(provider: () -> T): T {
return cacheByClassInvalidatingOnRootModifications(provider::class.java, provider)
}
fun <T> Project.cacheByClass(classForKey: Class<*>, vararg dependencies: Any, provider: () -> T): T {
return CachedValuesManager.getManager(this).cache(this, dependencies, classForKey, provider)
}
fun <T> Project.cacheByClassInvalidatingOnRootModifications(classForKey: Class<*>, provider: () -> T): T {
return cacheByClass(classForKey, ProjectRootModificationTracker.getInstance(this), provider = provider)
}
/**
* Note that it uses lambda's class for caching (essentially, anonymous class), which means that all invocations will be cached
* by the one and the same key.
* It is encouraged to use explicit class, just for the sake of readability.
*/
fun <T> Project.cacheInvalidatingOnRootModifications(provider: () -> T): T {
return cacheByClassInvalidatingOnRootModifications(provider::class.java, provider)
}
private fun <T> CachedValuesManager.cache(
holder: UserDataHolder,
dependencies: Array<out Any>,
classForKey: Class<*>,
provider: () -> T
): T {
return getCachedValue(
holder,
getKeyForClass(classForKey),
{ CachedValueProvider.Result.create(provider(), dependencies) },
false
)
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.caches.resolve
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.diagnostics.KotlinSuppressCache
interface KotlinCacheService {
companion object {
fun getInstance(project: Project): KotlinCacheService = ServiceManager.getService(project, KotlinCacheService::class.java)!!
}
fun getResolutionFacade(elements: List<KtElement>): ResolutionFacade
fun getResolutionFacade(elements: List<KtElement>, platform: TargetPlatform): ResolutionFacade
fun getResolutionFacadeByFile(file: PsiFile, platform: TargetPlatform): ResolutionFacade?
fun getSuppressionCache(): KotlinSuppressCache
fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, platform: TargetPlatform): ResolutionFacade?
fun getResolutionFacadeByModuleInfo(moduleInfo: ModuleInfo, settings: PlatformAnalysisSettings): ResolutionFacade?
}

View File

@@ -1,22 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.caches.resolve
/**
* Regulates which sources should be analyzed together.
*
* There are exactly two descendants, which are in strong one-to-one correspondence with [ResolutionModeComponent.Mode] (meaning
* that after checking value of ResolutionMode, it's safe to downcast settings instance to the respective type):
* - [PlatformAnalysisSettingsImpl] should be used iff we're working under [Mode.SEPARATE], and will create separate
* facade for each platforms, sdk, builtIns settings and other stuff.
* This is the old and stable mode, which should be used by default.
*
* - [CompositeAnalysisSettings] should be used iff we're working under [Mode.COMPOSITE], and will analyze all sources
* together, in one facade.
* This mode is new and experimental, and works only together with TypeRefinement facilities in the compiler's frontend.
* This mode is currently enabled only for HMPP projects
*/
interface PlatformAnalysisSettings

View File

@@ -1,110 +0,0 @@
/*
* Copyright 2010-2019 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.idea.analysis
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
import org.jetbrains.kotlin.types.expressions.KotlinTypeInfo
import org.jetbrains.kotlin.types.expressions.PreliminaryDeclarationVisitor
@JvmOverloads
@OptIn(FrontendInternals::class)
fun KtExpression.computeTypeInfoInContext(
scope: LexicalScope,
contextExpression: KtExpression = this,
trace: BindingTrace = BindingTraceContext(),
dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY,
expectedType: KotlinType = TypeUtils.NO_EXPECTED_TYPE,
isStatement: Boolean = false,
contextDependency: ContextDependency = ContextDependency.INDEPENDENT,
expressionTypingServices: ExpressionTypingServices = contextExpression.getResolutionFacade().frontendService<ExpressionTypingServices>()
): KotlinTypeInfo {
PreliminaryDeclarationVisitor.createForExpression(this, trace, expressionTypingServices.languageVersionSettings)
return expressionTypingServices.getTypeInfo(
scope, this, expectedType, dataFlowInfo, InferenceSession.default, trace, isStatement, contextExpression, contextDependency
)
}
@JvmOverloads
@OptIn(FrontendInternals::class)
fun KtExpression.analyzeInContext(
scope: LexicalScope,
contextExpression: KtExpression = this,
trace: BindingTrace = BindingTraceContext(),
dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY,
expectedType: KotlinType = TypeUtils.NO_EXPECTED_TYPE,
isStatement: Boolean = false,
contextDependency: ContextDependency = ContextDependency.INDEPENDENT,
expressionTypingServices: ExpressionTypingServices = contextExpression.getResolutionFacade().frontendService<ExpressionTypingServices>()
): BindingContext {
computeTypeInfoInContext(
scope,
contextExpression,
trace,
dataFlowInfo,
expectedType,
isStatement,
contextDependency,
expressionTypingServices
)
return trace.bindingContext
}
@JvmOverloads
fun KtExpression.computeTypeInContext(
scope: LexicalScope,
contextExpression: KtExpression = this,
trace: BindingTrace = BindingTraceContext(),
dataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY,
expectedType: KotlinType = TypeUtils.NO_EXPECTED_TYPE
): KotlinType? = computeTypeInfoInContext(scope, contextExpression, trace, dataFlowInfo, expectedType).type
@JvmOverloads
fun KtExpression.analyzeAsReplacement(
expressionToBeReplaced: KtExpression,
bindingContext: BindingContext,
scope: LexicalScope,
trace: BindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace for analyzeAsReplacement()"),
contextDependency: ContextDependency = ContextDependency.INDEPENDENT
): BindingContext = analyzeInContext(
scope,
expressionToBeReplaced,
dataFlowInfo = bindingContext.getDataFlowInfoBefore(expressionToBeReplaced),
expectedType = bindingContext[BindingContext.EXPECTED_EXPRESSION_TYPE, expressionToBeReplaced] ?: TypeUtils.NO_EXPECTED_TYPE,
isStatement = expressionToBeReplaced.isUsedAsStatement(bindingContext),
trace = trace,
contextDependency = contextDependency
)
@JvmOverloads
fun KtExpression.analyzeAsReplacement(
expressionToBeReplaced: KtExpression,
bindingContext: BindingContext,
resolutionFacade: ResolutionFacade = expressionToBeReplaced.getResolutionFacade(),
trace: BindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace for analyzeAsReplacement()"),
contextDependency: ContextDependency = ContextDependency.INDEPENDENT
): BindingContext {
val scope = expressionToBeReplaced.getResolutionScope(bindingContext, resolutionFacade)
return analyzeAsReplacement(expressionToBeReplaced, bindingContext, scope, trace, contextDependency)
}

View File

@@ -1,116 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.caches.resolve
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.NoDescriptorForDeclarationException
/**
* This function throws exception when resolveToDescriptorIfAny returns null, otherwise works equivalently.
*/
fun KtDeclaration.unsafeResolveToDescriptor(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL
): DeclarationDescriptor =
resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) ?: throw NoDescriptorForDeclarationException(this)
/**
* This function first uses declaration resolvers to resolve this declaration and/or additional declarations (e.g. its parent),
* and then takes the relevant descriptor from binding context.
* The exact set of declarations to resolve depends on bodyResolveMode
*/
fun KtDeclaration.resolveToDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): DeclarationDescriptor? {
//TODO: BodyResolveMode.PARTIAL is not quite safe!
val context = analyze(resolutionFacade, bodyResolveMode)
return if (this is KtParameter && hasValOrVar()) {
context.get(BindingContext.PRIMARY_CONSTRUCTOR_PARAMETER, this)
} else {
context.get(BindingContext.DECLARATION_TO_DESCRIPTOR, this)
}
}
fun KtAnnotationEntry.resolveToDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): AnnotationDescriptor? {
//TODO: BodyResolveMode.PARTIAL is not quite safe!
val context = analyze(resolutionFacade, bodyResolveMode)
return context.get(BindingContext.ANNOTATION, this)
}
fun KtClassOrObject.resolveToDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): ClassDescriptor? {
return (this as KtDeclaration).resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) as? ClassDescriptor
}
fun KtNamedFunction.resolveToDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): FunctionDescriptor? {
return (this as KtDeclaration).resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) as? FunctionDescriptor
}
fun KtProperty.resolveToDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): VariableDescriptor? {
return (this as KtDeclaration).resolveToDescriptorIfAny(resolutionFacade, bodyResolveMode) as? VariableDescriptor
}
fun KtParameter.resolveToParameterDescriptorIfAny(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): ValueParameterDescriptor? {
val context = analyze(resolutionFacade, bodyResolveMode)
return context.get(BindingContext.VALUE_PARAMETER, this) as? ValueParameterDescriptor
}
fun KtElement.resolveToCall(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): ResolvedCall<out CallableDescriptor>? =
getResolvedCall(analyze(resolutionFacade, bodyResolveMode))
@JvmOverloads
fun KtElement.analyze(
resolutionFacade: ResolutionFacade,
bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL
): BindingContext =
resolutionFacade.analyze(this, bodyResolveMode)
fun KtElement.analyzeAndGetResult(resolutionFacade: ResolutionFacade): AnalysisResult =
AnalysisResult.success(resolutionFacade.analyze(this), resolutionFacade.moduleDescriptor)
// This function is used on declarations to make analysis not only declaration itself but also it content:
// body for declaration with body, initializer & accessors for properties
fun KtElement.analyzeWithContentAndGetResult(resolutionFacade: ResolutionFacade): AnalysisResult =
resolutionFacade.analyzeWithAllCompilerChecks(listOf(this))
// This function is used on declarations to make analysis not only declaration itself but also it content:
// body for declaration with body, initializer & accessors for properties
fun KtDeclaration.analyzeWithContent(resolutionFacade: ResolutionFacade): BindingContext =
resolutionFacade.analyzeWithAllCompilerChecks(listOf(this)).bindingContext
// This function is used to make full analysis of declaration container.
// All its declarations, including their content (see above), are analyzed.
inline fun <reified T> T.analyzeWithContent(resolutionFacade: ResolutionFacade): BindingContext where T : KtDeclarationContainer, T : KtElement =
resolutionFacade.analyzeWithAllCompilerChecks(listOf(this)).bindingContext

View File

@@ -1,218 +0,0 @@
/*
* Copyright 2010-2019 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:JvmName("ResolutionUtils")
package org.jetbrains.kotlin.idea.caches.resolve
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
fun KtElement.getResolutionFacade(): ResolutionFacade =
KotlinCacheService.getInstance(project).getResolutionFacade(listOf(this))
/**
* For local declarations is equivalent to unsafeResolveToDescriptor(bodyResolveMode)
*
* But for non-local declarations it ignores bodyResolveMode and uses LazyDeclarationResolver directly
*/
@Deprecated(
message = "This function has unclear semantics. Please use either unsafeResolveToDescriptor or resolveToDescriptorIfAny instead",
replaceWith = ReplaceWith("unsafeResolveToDescriptor")
)
fun KtDeclaration.resolveToDescriptor(bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): DeclarationDescriptor =
getResolutionFacade().resolveToDescriptor(this, bodyResolveMode)
/**
* This function throws exception when resolveToDescriptorIfAny returns null, otherwise works equivalently.
*
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtDeclaration.unsafeResolveToDescriptor(
bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL
): DeclarationDescriptor =
unsafeResolveToDescriptor(getResolutionFacade(), bodyResolveMode)
/**
* This function first uses declaration resolvers to resolve this declaration and/or additional declarations (e.g. its parent),
* and then takes the relevant descriptor from binding context.
* The exact set of declarations to resolve depends on bodyResolveMode
*
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtDeclaration.resolveToDescriptorIfAny(
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL
): DeclarationDescriptor? =
resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtClassOrObject.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtNamedFunction.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtProperty.resolveToDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtParameter.resolveToParameterDescriptorIfAny(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
resolveToParameterDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtElement.resolveToCall(bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL) =
resolveToCall(getResolutionFacade(), bodyResolveMode)
fun KtFile.resolveImportReference(fqName: FqName): Collection<DeclarationDescriptor> {
val facade = getResolutionFacade()
return facade.resolveImportReference(facade.moduleDescriptor, fqName)
}
fun KtAnnotationEntry.resolveToDescriptorIfAny(
bodyResolveMode: BodyResolveMode = BodyResolveMode.PARTIAL_NO_ADDITIONAL
): AnnotationDescriptor? =
resolveToDescriptorIfAny(getResolutionFacade(), bodyResolveMode)
// This and next functions are used for 'normal' element analysis
// This analysis *should* provide all information extractable from this KtElement except:
// - for declarations, it does not analyze their bodies
// - for classes, it does not analyze their content
// - for member / top-level properties, it does not analyze initializers / accessors
// This information includes related descriptors, resolved calls (but not inside body, see above!)
// and many other binding context slices.
// Normally, the function is used on local declarations or statements / expressions
// Any usage on non-local declaration is a bit suspicious,
// consider replacing it with resolveToDescriptorIfAny and
// remember that body / content is not analyzed;
// if it's necessary, use analyzeWithContent()
//
// If you need diagnostics in result context, use BodyResolveMode.PARTIAL_WITH_DIAGNOSTICS.
// BodyResolveMode.FULL analyzes all statements on the level of KtElement and above.
// BodyResolveMode.PARTIAL analyzes only statements necessary for this KtElement precise analysis.
//
// See also: ResolveSessionForBodies, ResolveElementCache
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
@JvmOverloads
fun KtElement.analyze(
bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL
): BindingContext =
analyze(getResolutionFacade(), bodyResolveMode)
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtElement.analyzeAndGetResult(): AnalysisResult {
return analyzeAndGetResult(getResolutionFacade())
}
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtElement.analyzeWithContentAndGetResult(): AnalysisResult =
analyzeWithContentAndGetResult(getResolutionFacade())
fun KtElement.findModuleDescriptor(): ModuleDescriptor = getResolutionFacade().moduleDescriptor
// This function is used on declarations to make analysis not only declaration itself but also it content:
// body for declaration with body, initializer & accessors for properties
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
fun KtDeclaration.analyzeWithContent(): BindingContext =
analyzeWithContent(getResolutionFacade())
// This function is used to make full analysis of declaration container.
// All its declarations, including their content (see above), are analyzed.
/**
* **Please, use overload with providing resolutionFacade for stable results of subsequent calls**
*/
inline fun <reified T> T.analyzeWithContent(): BindingContext where T : KtDeclarationContainer, T : KtElement =
analyzeWithContent(getResolutionFacade())
/**
* This function is expected to produce the same result as compiler for the whole file content (including diagnostics,
* trace slices, descriptors, etc.).
*
* It's not recommended to call this function without real need.
*
* @ref [KotlinCacheService]
* @ref [org.jetbrains.kotlin.idea.caches.resolve.PerFileAnalysisCache]
*/
fun KtFile.analyzeWithAllCompilerChecks(vararg extraFiles: KtFile): AnalysisResult =
this.analyzeWithAllCompilerChecks(null, *extraFiles)
fun KtFile.analyzeWithAllCompilerChecks(callback: ((Diagnostic) -> Unit)?, vararg extraFiles: KtFile): AnalysisResult =
KotlinCacheService.getInstance(project).getResolutionFacade(listOf(this) + extraFiles.toList())
.analyzeWithAllCompilerChecks(listOf(this), callback)
/**
* This function is expected to produce the same result as compiler for the given element and its children (including diagnostics,
* trace slices, descriptors, etc.). For some expression element it actually performs analyze for some parent (usually declaration).
*
* It's not recommended to call this function without real need.
*
* NB: for statements / expressions, usually should be replaced with analyze(),
* for declarations, analyzeWithContent() will do what you want.
*
* @ref [KotlinCacheService]
* @ref [org.jetbrains.kotlin.idea.caches.resolve.PerFileAnalysisCache]
*/
@Deprecated(
"Use either KtFile.analyzeWithAllCompilerChecks() or KtElement.analyzeAndGetResult()",
ReplaceWith("analyzeAndGetResult()")
)
fun KtElement.analyzeWithAllCompilerChecks(): AnalysisResult = getResolutionFacade().analyzeWithAllCompilerChecks(listOf(this))
// this method don't check visibility and collect all descriptors with given fqName
@OptIn(FrontendInternals::class)
fun ResolutionFacade.resolveImportReference(
moduleDescriptor: ModuleDescriptor,
fqName: FqName
): Collection<DeclarationDescriptor> {
val importDirective = KtPsiFactory(project).createImportDirective(ImportPath(fqName, false))
val qualifiedExpressionResolver = this.getFrontendService(moduleDescriptor, QualifiedExpressionResolver::class.java)
return qualifiedExpressionResolver.processImportReference(
importDirective,
moduleDescriptor,
BindingTraceContext(),
excludedImportNames = emptyList(),
packageFragmentForVisibilityCheck = null
)?.getContributedDescriptors() ?: emptyList()
}
@Suppress("DEPRECATION")
@Deprecated(
"This method is going to be removed in 1.3.0 release",
ReplaceWith("analyzeWithAllCompilerChecks().bindingContext"),
DeprecationLevel.ERROR
)
fun KtElement.analyzeFully(): BindingContext = analyzeWithAllCompilerChecks().bindingContext

View File

@@ -1,494 +0,0 @@
/*
* Copyright 2010-2019 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.idea.codeInsight
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
import org.jetbrains.kotlin.load.kotlin.toSourceElement
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
import org.jetbrains.kotlin.resolve.scopes.utils.collectAllFromMeAndParent
import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
import org.jetbrains.kotlin.types.typeUtil.isUnit
import java.util.*
@OptIn(FrontendInternals::class)
class ReferenceVariantsHelper(
private val bindingContext: BindingContext,
private val resolutionFacade: ResolutionFacade,
private val moduleDescriptor: ModuleDescriptor,
private val visibilityFilter: (DeclarationDescriptor) -> Boolean,
private val notProperties: Set<FqNameUnsafe> = setOf()
) {
fun getReferenceVariants(
expression: KtSimpleNameExpression,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
filterOutJavaGettersAndSetters: Boolean = true,
filterOutShadowed: Boolean = true,
excludeNonInitializedVariable: Boolean = true,
useReceiverType: KotlinType? = null
): Collection<DeclarationDescriptor> = getReferenceVariants(
expression, CallTypeAndReceiver.detect(expression),
kindFilter, nameFilter, filterOutJavaGettersAndSetters, filterOutShadowed, excludeNonInitializedVariable, useReceiverType
)
fun getReferenceVariants(
contextElement: PsiElement,
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
filterOutJavaGettersAndSetters: Boolean = true,
filterOutShadowed: Boolean = true,
excludeNonInitializedVariable: Boolean = true,
useReceiverType: KotlinType? = null
): Collection<DeclarationDescriptor> {
var variants: Collection<DeclarationDescriptor> =
getReferenceVariantsNoVisibilityFilter(contextElement, kindFilter, nameFilter, callTypeAndReceiver, useReceiverType)
.filter { !resolutionFacade.frontendService<DeprecationResolver>().isHiddenInResolution(it) && visibilityFilter(it) }
if (filterOutShadowed) {
ShadowedDeclarationsFilter.create(bindingContext, resolutionFacade, contextElement, callTypeAndReceiver)?.let {
variants = it.filter(variants)
}
}
if (filterOutJavaGettersAndSetters && kindFilter.kindMask.and(DescriptorKindFilter.FUNCTIONS_MASK) != 0) {
variants = filterOutJavaGettersAndSetters(variants)
}
if (excludeNonInitializedVariable && kindFilter.kindMask.and(DescriptorKindFilter.VARIABLES_MASK) != 0) {
variants = excludeNonInitializedVariable(variants, contextElement)
}
return variants
}
fun <TDescriptor : DeclarationDescriptor> filterOutJavaGettersAndSetters(variants: Collection<TDescriptor>): Collection<TDescriptor> {
val accessorMethodsToRemove = HashSet<FunctionDescriptor>()
val filteredVariants = variants.filter { it !is SyntheticJavaPropertyDescriptor || !it.suppressedByNotPropertyList(notProperties) }
for (variant in filteredVariants) {
if (variant is SyntheticJavaPropertyDescriptor) {
accessorMethodsToRemove.add(variant.getMethod.original)
val setter = variant.setMethod
if (setter != null && setter.returnType?.isUnit() == true) { // we do not filter out non-Unit setters
accessorMethodsToRemove.add(setter.original)
}
}
}
return filteredVariants.filter { it !is FunctionDescriptor || it.original !in accessorMethodsToRemove }
}
// filters out variable inside its initializer
fun excludeNonInitializedVariable(
variants: Collection<DeclarationDescriptor>,
contextElement: PsiElement
): Collection<DeclarationDescriptor> {
for (element in contextElement.parentsWithSelf) {
val parent = element.parent
if (parent is KtVariableDeclaration && element == parent.initializer) {
return variants.filter { it.findPsi() != parent }
}
if (element is KtDeclaration) break // we can use variable inside lambda or anonymous object located in its initializer
}
return variants
}
private fun getReferenceVariantsNoVisibilityFilter(
contextElement: PsiElement,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
callTypeAndReceiver: CallTypeAndReceiver<*, *>,
useReceiverType: KotlinType?
): Collection<DeclarationDescriptor> {
val callType = callTypeAndReceiver.callType
@Suppress("NAME_SHADOWING")
val kindFilter = kindFilter.intersect(callType.descriptorKindFilter)
val receiverExpression: KtExpression?
when (callTypeAndReceiver) {
is CallTypeAndReceiver.IMPORT_DIRECTIVE -> {
return getVariantsForImportOrPackageDirective(callTypeAndReceiver.receiver, kindFilter, nameFilter)
}
is CallTypeAndReceiver.PACKAGE_DIRECTIVE -> {
return getVariantsForImportOrPackageDirective(callTypeAndReceiver.receiver, kindFilter, nameFilter)
}
is CallTypeAndReceiver.TYPE -> {
return getVariantsForUserType(callTypeAndReceiver.receiver, contextElement, kindFilter, nameFilter)
}
is CallTypeAndReceiver.ANNOTATION -> {
return getVariantsForUserType(callTypeAndReceiver.receiver, contextElement, kindFilter, nameFilter)
}
is CallTypeAndReceiver.CALLABLE_REFERENCE -> {
return getVariantsForCallableReference(callTypeAndReceiver, contextElement, useReceiverType, kindFilter, nameFilter)
}
is CallTypeAndReceiver.DEFAULT -> receiverExpression = null
is CallTypeAndReceiver.DOT -> receiverExpression = callTypeAndReceiver.receiver
is CallTypeAndReceiver.SUPER_MEMBERS -> receiverExpression = callTypeAndReceiver.receiver
is CallTypeAndReceiver.SAFE -> receiverExpression = callTypeAndReceiver.receiver
is CallTypeAndReceiver.INFIX -> receiverExpression = callTypeAndReceiver.receiver
is CallTypeAndReceiver.OPERATOR -> return emptyList()
is CallTypeAndReceiver.UNKNOWN -> return emptyList()
else -> throw RuntimeException() //TODO: see KT-9394
}
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(contextElement)
val containingDeclaration = resolutionScope.ownerDescriptor
val smartCastManager = resolutionFacade.frontendService<SmartCastManager>()
val languageVersionSettings = resolutionFacade.frontendService<LanguageVersionSettings>()
val implicitReceiverTypes = resolutionScope.getImplicitReceiversWithInstance(
languageVersionSettings.supportsFeature(LanguageFeature.DslMarkersSupport)
).flatMap {
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(
it.value,
bindingContext,
containingDeclaration,
dataFlowInfo,
languageVersionSettings,
resolutionFacade.frontendService<DataFlowValueFactory>()
)
}.toSet()
val descriptors = LinkedHashSet<DeclarationDescriptor>()
val filterWithoutExtensions = kindFilter exclude DescriptorKindExclude.Extensions
if (receiverExpression != null) {
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression]
if (qualifier != null) {
descriptors.addAll(qualifier.staticScope.collectStaticMembers(resolutionFacade, filterWithoutExtensions, nameFilter))
}
val explicitReceiverTypes = if (useReceiverType != null) {
listOf(useReceiverType)
} else {
callTypeAndReceiver.receiverTypes(
bindingContext,
contextElement,
moduleDescriptor,
resolutionFacade,
stableSmartCastsOnly = false
)!!
}
descriptors.processAll(implicitReceiverTypes, explicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter)
} else {
assert(useReceiverType == null) { "'useReceiverType' parameter is not supported for implicit receiver" }
descriptors.processAll(implicitReceiverTypes, implicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter)
// add non-instance members
descriptors.addAll(
resolutionScope.collectDescriptorsFiltered(
filterWithoutExtensions,
nameFilter,
changeNamesForAliased = true
)
)
descriptors.addAll(resolutionScope.collectAllFromMeAndParent { scope ->
scope.collectSyntheticStaticMembersAndConstructors(resolutionFacade, kindFilter, nameFilter)
})
}
if (callType == CallType.SUPER_MEMBERS) { // we need to unwrap fake overrides in case of "super." because ShadowedDeclarationsFilter does not work correctly
return descriptors.flatMapTo(LinkedHashSet<DeclarationDescriptor>()) {
if (it is CallableMemberDescriptor && it.kind == CallableMemberDescriptor.Kind.FAKE_OVERRIDE)
it.overriddenDescriptors
else
listOf(it)
}
}
return descriptors
}
private fun getVariantsForUserType(
receiverExpression: KtExpression?,
contextElement: PsiElement,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
if (receiverExpression != null) {
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
return qualifier.staticScope.collectStaticMembers(resolutionFacade, kindFilter, nameFilter)
} else {
val scope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
return scope.collectDescriptorsFiltered(kindFilter, nameFilter, changeNamesForAliased = true)
}
}
private fun getVariantsForCallableReference(
callTypeAndReceiver: CallTypeAndReceiver.CALLABLE_REFERENCE,
contextElement: PsiElement,
useReceiverType: KotlinType?,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
val descriptors = LinkedHashSet<DeclarationDescriptor>()
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
val receiver = callTypeAndReceiver.receiver
if (receiver != null) {
val isStatic = bindingContext[BindingContext.DOUBLE_COLON_LHS, receiver] is DoubleColonLHS.Type
val explicitReceiverTypes = if (useReceiverType != null) {
listOf(useReceiverType)
} else {
callTypeAndReceiver.receiverTypes(
bindingContext,
contextElement,
moduleDescriptor,
resolutionFacade,
stableSmartCastsOnly = false
)!!
}
val constructorFilter = { descriptor: ClassDescriptor -> if (isStatic) true else descriptor.isInner }
descriptors.addNonExtensionMembers(explicitReceiverTypes, kindFilter, nameFilter, constructorFilter)
descriptors.addScopeAndSyntheticExtensions(
resolutionScope,
explicitReceiverTypes,
CallType.CALLABLE_REFERENCE,
kindFilter,
nameFilter
)
if (isStatic) {
explicitReceiverTypes
.mapNotNull { (it.constructor.declarationDescriptor as? ClassDescriptor)?.staticScope }
.flatMapTo(descriptors) { it.collectStaticMembers(resolutionFacade, kindFilter, nameFilter) }
}
} else {
// process non-instance members and class constructors
descriptors.addNonExtensionCallablesAndConstructors(
resolutionScope,
kindFilter, nameFilter, constructorFilter = { !it.isInner },
classesOnly = false
)
}
return descriptors
}
private fun getVariantsForImportOrPackageDirective(
receiverExpression: KtExpression?,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
if (receiverExpression != null) {
val qualifier = bindingContext[BindingContext.QUALIFIER, receiverExpression] ?: return emptyList()
val staticDescriptors = qualifier.staticScope.collectStaticMembers(resolutionFacade, kindFilter, nameFilter)
val objectDescriptor =
(qualifier as? ClassQualifier)?.descriptor?.takeIf { it.kind == ClassKind.OBJECT } ?: return staticDescriptors
return staticDescriptors + objectDescriptor.defaultType.memberScope.getDescriptorsFiltered(kindFilter, nameFilter)
} else {
val rootPackage = resolutionFacade.moduleDescriptor.getPackage(FqName.ROOT)
return rootPackage.memberScope.getDescriptorsFiltered(kindFilter, nameFilter)
}
}
private fun MutableSet<DeclarationDescriptor>.processAll(
implicitReceiverTypes: Collection<KotlinType>,
receiverTypes: Collection<KotlinType>,
resolutionScope: LexicalScope,
callType: CallType<*>,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
) {
addNonExtensionMembers(receiverTypes, kindFilter, nameFilter, constructorFilter = { it.isInner })
addMemberExtensions(implicitReceiverTypes, receiverTypes, callType, kindFilter, nameFilter)
addScopeAndSyntheticExtensions(resolutionScope, receiverTypes, callType, kindFilter, nameFilter)
}
private fun MutableSet<DeclarationDescriptor>.addMemberExtensions(
dispatchReceiverTypes: Collection<KotlinType>,
extensionReceiverTypes: Collection<KotlinType>,
callType: CallType<*>,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
) {
val memberFilter = kindFilter exclude DescriptorKindExclude.NonExtensions
for (dispatchReceiverType in dispatchReceiverTypes) {
for (member in dispatchReceiverType.memberScope.getDescriptorsFiltered(memberFilter, nameFilter)) {
addAll((member as CallableDescriptor).substituteExtensionIfCallable(extensionReceiverTypes, callType))
}
}
}
private fun MutableSet<DeclarationDescriptor>.addNonExtensionMembers(
receiverTypes: Collection<KotlinType>,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
constructorFilter: (ClassDescriptor) -> Boolean
) {
for (receiverType in receiverTypes) {
addNonExtensionCallablesAndConstructors(
receiverType.memberScope.memberScopeAsImportingScope(),
kindFilter, nameFilter, constructorFilter,
false
)
receiverType.constructor.supertypes.forEach {
addNonExtensionCallablesAndConstructors(
it.memberScope.memberScopeAsImportingScope(),
kindFilter, nameFilter, constructorFilter,
true
)
}
}
}
private fun MutableSet<DeclarationDescriptor>.addNonExtensionCallablesAndConstructors(
scope: HierarchicalScope,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
constructorFilter: (ClassDescriptor) -> Boolean,
classesOnly: Boolean
) {
var filterToUse =
DescriptorKindFilter(kindFilter.kindMask and DescriptorKindFilter.CALLABLES.kindMask).exclude(DescriptorKindExclude.Extensions)
// should process classes if we need constructors
if (filterToUse.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) {
filterToUse = filterToUse.withKinds(DescriptorKindFilter.NON_SINGLETON_CLASSIFIERS_MASK)
}
for (descriptor in scope.collectDescriptorsFiltered(filterToUse, nameFilter, changeNamesForAliased = true)) {
if (descriptor is ClassDescriptor) {
if (descriptor.modality == Modality.ABSTRACT || descriptor.modality == Modality.SEALED) continue
if (!constructorFilter(descriptor)) continue
descriptor.constructors.filterTo(this) { kindFilter.accepts(it) }
} else if (!classesOnly && kindFilter.accepts(descriptor)) {
this.add(descriptor)
}
}
}
private fun MutableSet<DeclarationDescriptor>.addScopeAndSyntheticExtensions(
scope: LexicalScope,
receiverTypes: Collection<KotlinType>,
callType: CallType<*>,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
) {
if (kindFilter.excludes.contains(DescriptorKindExclude.Extensions)) return
if (receiverTypes.isEmpty()) return
fun process(extensionOrSyntheticMember: CallableDescriptor) {
if (kindFilter.accepts(extensionOrSyntheticMember) && nameFilter(extensionOrSyntheticMember.name)) {
if (extensionOrSyntheticMember.isExtension) {
addAll(extensionOrSyntheticMember.substituteExtensionIfCallable(receiverTypes, callType))
} else {
add(extensionOrSyntheticMember)
}
}
}
for (descriptor in scope.collectDescriptorsFiltered(
kindFilter exclude DescriptorKindExclude.NonExtensions,
nameFilter,
changeNamesForAliased = true
)) {
// todo: sometimes resolution scope here is LazyJavaClassMemberScope. see ea.jetbrains.com/browser/ea_problems/72572
process(descriptor as CallableDescriptor)
}
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java).forceEnableSamAdapters()
if (kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK)) {
val lookupLocation = (scope.ownerDescriptor.toSourceElement.getPsi() as? KtElement)?.let { KotlinLookupLocation(it) }
?: NoLookupLocation.FROM_IDE
for (extension in syntheticScopes.collectSyntheticExtensionProperties(receiverTypes, lookupLocation)) {
process(extension)
}
}
if (kindFilter.acceptsKinds(DescriptorKindFilter.FUNCTIONS_MASK)) {
for (syntheticMember in syntheticScopes.collectSyntheticMemberFunctions(receiverTypes)) {
process(syntheticMember)
}
}
}
}
private fun MemberScope.collectStaticMembers(
resolutionFacade: ResolutionFacade,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
return getDescriptorsFiltered(kindFilter, nameFilter) + collectSyntheticStaticMembersAndConstructors(
resolutionFacade,
kindFilter,
nameFilter
)
}
@OptIn(FrontendInternals::class)
fun ResolutionScope.collectSyntheticStaticMembersAndConstructors(
resolutionFacade: ResolutionFacade,
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): List<FunctionDescriptor> {
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java)
val functionDescriptors = getContributedDescriptors(DescriptorKindFilter.FUNCTIONS)
val classifierDescriptors = getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS)
return (syntheticScopes.forceEnableSamAdapters().collectSyntheticStaticFunctions(functionDescriptors) +
syntheticScopes.collectSyntheticConstructors(classifierDescriptors))
.filter { kindFilter.accepts(it) && nameFilter(it.name) }
}
// New Inference disables scope with synthetic SAM-adapters because it uses conversions for resolution
// However, sometimes we need to pretend that we have those synthetic members, for example:
// - to show both option (with SAM-conversion signature, and without) in completion
// - for various intentions and checks (see RedundantSamConstructorInspection, ConflictingExtensionPropertyIntention and other)
// TODO(dsavvinov): review clients, rewrite them to not rely on synthetic adapetrs
fun SyntheticScopes.forceEnableSamAdapters(): SyntheticScopes {
return if (this !is JavaSyntheticScopes)
this
else
object : SyntheticScopes {
override val scopes: Collection<SyntheticScope> = this@forceEnableSamAdapters.scopesWithForceEnabledSamAdapters
}
}

View File

@@ -1,198 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.core.quickfix;
import com.intellij.extapi.psi.ASTDelegatePsiElement;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.CallableDescriptor;
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.idea.caches.resolve.ResolutionUtils;
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode;
import org.jetbrains.kotlin.types.DeferredType;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
public class QuickFixUtil {
private QuickFixUtil() {
}
public static boolean removePossiblyWhiteSpace(ASTDelegatePsiElement element, PsiElement possiblyWhiteSpace) {
if (possiblyWhiteSpace instanceof PsiWhiteSpace) {
element.deleteChildInternal(possiblyWhiteSpace.getNode());
return true;
}
return false;
}
@Nullable
public static <T extends PsiElement> T getParentElementOfType(Diagnostic diagnostic, Class<T> aClass) {
return PsiTreeUtil.getParentOfType(diagnostic.getPsiElement(), aClass, false);
}
@Nullable
public static KotlinType getDeclarationReturnType(KtNamedDeclaration declaration) {
PsiFile file = declaration.getContainingFile();
if (!(file instanceof KtFile)) return null;
DeclarationDescriptor descriptor = ResolutionUtils.unsafeResolveToDescriptor(declaration, BodyResolveMode.FULL);
if (!(descriptor instanceof CallableDescriptor)) return null;
KotlinType type = ((CallableDescriptor) descriptor).getReturnType();
if (type instanceof DeferredType) {
type = ((DeferredType) type).getDelegate();
}
return type;
}
@Nullable
public static KotlinType findLowerBoundOfOverriddenCallablesReturnTypes(@NotNull CallableDescriptor descriptor) {
KotlinType matchingReturnType = null;
for (CallableDescriptor overriddenDescriptor : ((CallableDescriptor) descriptor).getOverriddenDescriptors()) {
KotlinType overriddenReturnType = overriddenDescriptor.getReturnType();
if (overriddenReturnType == null) {
return null;
}
if (matchingReturnType == null || KotlinTypeChecker.DEFAULT.isSubtypeOf(overriddenReturnType, matchingReturnType)) {
matchingReturnType = overriddenReturnType;
}
else if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(matchingReturnType, overriddenReturnType)) {
return null;
}
}
return matchingReturnType;
}
@Nullable
public static PsiElement safeGetDeclaration(@Nullable CallableDescriptor descriptor) {
//do not create fix if descriptor has more than one overridden declaration
if (descriptor == null || descriptor.getOverriddenDescriptors().size() > 1) return null;
return DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
}
@Nullable
public static KtParameter getParameterDeclarationForValueArgument(
@NotNull ResolvedCall<?> resolvedCall,
@Nullable ValueArgument valueArgument
) {
PsiElement declaration = safeGetDeclaration(CallUtilKt.getParameterForArgument(resolvedCall, valueArgument));
return declaration instanceof KtParameter ? (KtParameter) declaration : null;
}
private static boolean equalOrLastInBlock(KtExpression block, KtExpression expression) {
if (block == expression) return true;
return block instanceof KtBlockExpression && expression.getParent() == block &&
PsiTreeUtil.getNextSiblingOfType(expression, KtExpression.class) == null;
}
@Nullable
public static KtIfExpression getParentIfForBranch(@Nullable KtExpression expression) {
KtIfExpression ifExpression = PsiTreeUtil.getParentOfType(expression, KtIfExpression.class, true);
if (ifExpression == null) return null;
if (equalOrLastInBlock(ifExpression.getThen(), expression)
|| equalOrLastInBlock(ifExpression.getElse(), expression)) {
return ifExpression;
}
return null;
}
@Nullable
private static KtWhenExpression getParentWhenForBranch(@Nullable KtExpression expression) {
KtWhenEntry whenEntry = PsiTreeUtil.getParentOfType(expression, KtWhenEntry.class, true);
if (whenEntry == null) return null;
KtExpression whenEntryExpression = whenEntry.getExpression();
if (whenEntryExpression == null) return null;
if (!equalOrLastInBlock(whenEntryExpression, expression)) return null;
return PsiTreeUtil.getParentOfType(whenEntry, KtWhenExpression.class, true);
}
@Nullable
private static KtExpression getParentForBranch(@Nullable KtExpression expression) {
KtExpression parent = getParentIfForBranch(expression);
if (parent != null) return parent;
return getParentWhenForBranch(expression);
}
// Returns true iff parent's value always or sometimes is evaluable to child's value, e.g.
// parent = (x), child = x;
// parent = if (...) x else y, child = x;
// parent = y.x, child = x
public static boolean canEvaluateTo(KtExpression parent, KtExpression child) {
if (parent == null || child == null) {
return false;
}
while (parent != child) {
PsiElement childParent = child.getParent();
if (childParent instanceof KtParenthesizedExpression) {
child = (KtExpression) childParent;
continue;
}
if (childParent instanceof KtDotQualifiedExpression &&
(child instanceof KtCallExpression || child instanceof KtDotQualifiedExpression)) {
child = (KtExpression) childParent;
continue;
}
child = getParentForBranch(child);
if (child == null) return false;
}
return true;
}
public static boolean canFunctionOrGetterReturnExpression(@NotNull KtDeclaration functionOrGetter, @NotNull KtExpression expression) {
if (functionOrGetter instanceof KtFunctionLiteral) {
KtBlockExpression functionLiteralBody = ((KtFunctionLiteral) functionOrGetter).getBodyExpression();
PsiElement returnedElement = null;
if (functionLiteralBody != null) {
PsiElement[] children = functionLiteralBody.getChildren();
int length = children.length;
if (length > 0) {
returnedElement = children[length - 1];
}
}
return returnedElement instanceof KtExpression && canEvaluateTo((KtExpression) returnedElement, expression);
}
else {
if (functionOrGetter instanceof KtDeclarationWithInitializer && canEvaluateTo(((KtDeclarationWithInitializer) functionOrGetter).getInitializer(), expression)) {
return true;
}
KtReturnExpression returnExpression = PsiTreeUtil.getParentOfType(expression, KtReturnExpression.class);
return returnExpression != null && canEvaluateTo(returnExpression.getReturnedExpression(), expression);
}
}
public static String renderTypeWithFqNameOnClash(KotlinType type, String nameToCheckAgainst) {
FqName fqNameToCheckAgainst = new FqName(nameToCheckAgainst);
ClassifierDescriptor typeClassifierDescriptor = type.getConstructor().getDeclarationDescriptor();
FqName typeFqName = typeClassifierDescriptor != null ? DescriptorUtils.getFqNameSafe(typeClassifierDescriptor) : fqNameToCheckAgainst;
DescriptorRenderer renderer = typeFqName.shortName().equals(fqNameToCheckAgainst.shortName())
? IdeDescriptorRenderers.SOURCE_CODE
: IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS;
return renderer.renderType(type);
}
}

View File

@@ -1,372 +0,0 @@
/*
* Copyright 2010-2020 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.idea.imports
import com.intellij.openapi.progress.ProgressManager
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
import org.jetbrains.kotlin.resolve.scopes.ImportingScope
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf
import org.jetbrains.kotlin.resolve.scopes.utils.replaceImportingScopes
class OptimizedImportsBuilder(
private val file: KtFile,
private val data: InputData,
private val options: Options
) {
companion object {
@get:TestOnly
@set:TestOnly
var testLog: StringBuilder? = null
}
interface AbstractReference {
val element: KtElement
val dependsOnNames: Collection<Name>
fun resolve(bindingContext: BindingContext): Collection<DeclarationDescriptor>
}
class InputData(
val descriptorsToImport: Set<DeclarationDescriptor>,
val namesToImport: Map<FqName, Set<Name>>,
val references: Collection<AbstractReference>,
val unresolvedNames: Set<Name>,
)
class Options(
val nameCountToUseStarImport: Int,
val nameCountToUseStarImportForMembers: Int,
val isInPackagesToUseStarImport: (FqName) -> Boolean
)
private val importInsertHelper = ImportInsertHelper.getInstance(file.project)
private sealed class ImportRule {
// force presence of this import
data class Add(val importPath: ImportPath) : ImportRule() {
override fun toString() = "+$importPath"
}
// force absence of this import
data class DoNotAdd(val importPath: ImportPath) : ImportRule() {
override fun toString() = "-$importPath"
}
}
private val importRules = HashSet<ImportRule>()
fun buildOptimizedImports(): List<ImportPath>? {
val facade = file.getResolutionFacade()
file.importDirectives
.asSequence()
.filter { it.mayReferToSomeUnresolvedName() || it.isExistedUnresolvedName(facade) }
.mapNotNull { it.importPath }
.mapNotNullTo(importRules) { ImportRule.Add(it) }
while (true) {
ProgressManager.checkCanceled()
val importRulesBefore = importRules.size
val result = tryBuildOptimizedImports()
if (importRules.size == importRulesBefore) return result
testLog?.append("Trying to build import list again with import rules: ${importRules.joinToString()}\n")
}
}
private fun KtImportDirective.mayReferToSomeUnresolvedName() = isAllUnder && data.unresolvedNames.isNotEmpty()
private fun KtImportDirective.isExistedUnresolvedName(facade: ResolutionFacade) =
importedName in data.unresolvedNames && !canResolve(facade)
private fun getExpressionToAnalyze(element: KtElement): KtExpression? {
val parent = element.parent
return when {
parent is KtQualifiedExpression && element == parent.selectorExpression -> parent
parent is KtCallExpression && element == parent.calleeExpression -> getExpressionToAnalyze(parent)
parent is KtOperationExpression && element == parent.operationReference -> parent
parent is KtUserType -> null //TODO: is it always correct?
else -> element as? KtExpression //TODO: what if not expression? Example: KtPropertyDelegationMethodsReference
}
}
private fun tryBuildOptimizedImports(): List<ImportPath>? {
val importsToGenerate = hashSetOf<ImportPath>()
importRules.filterIsInstance<ImportRule.Add>().mapTo(importsToGenerate) { it.importPath }
val descriptorsByParentFqName = HashMap<FqName, MutableSet<DeclarationDescriptor>>()
for (descriptor in data.descriptorsToImport) {
val fqName = descriptor.importableFqName!!
for (name in data.namesToImport.getValue(fqName)) {
val alias = if (name != fqName.shortName()) name else null
val explicitImportPath = ImportPath(fqName, false, alias)
if (explicitImportPath in importsToGenerate) continue
val parentFqName = fqName.parent()
if (alias == null && canUseStarImport(descriptor, fqName) && ImportPath(parentFqName, true).isAllowedByRules()) {
descriptorsByParentFqName.getOrPut(parentFqName) { hashSetOf() }.add(descriptor)
} else {
importsToGenerate.add(explicitImportPath)
}
}
}
val classNamesToCheck = hashSetOf<FqName>()
for (parentFqName in descriptorsByParentFqName.keys) {
ProgressManager.checkCanceled()
val starImportPath = ImportPath(parentFqName, true)
if (starImportPath in importsToGenerate) continue
val descriptors = descriptorsByParentFqName[parentFqName]!!
val fqNames = descriptors.map { it.importableFqName!! }.toSet()
val nameCountToUseStar = descriptors.first().nameCountToUseStar()
val useExplicitImports = fqNames.size < nameCountToUseStar && !options.isInPackagesToUseStarImport(parentFqName)
|| !starImportPath.isAllowedByRules()
if (useExplicitImports) {
fqNames.filter(this::needExplicitImport).mapTo(importsToGenerate) { ImportPath(it, false) }
} else {
descriptors.asSequence()
.filterIsInstance<ClassDescriptor>()
.map { it.importableFqName!! }
.filterTo(classNamesToCheck, this::needExplicitImport)
if (fqNames.all(this::needExplicitImport)) {
importsToGenerate.add(starImportPath)
}
}
}
// now check that there are no conflicts and all classes are really imported
addExplicitImportsForClassesWhenRequired(classNamesToCheck, descriptorsByParentFqName, importsToGenerate, file)
val sortedImportsToGenerate = importsToGenerate.sortedWith(importInsertHelper.importSortComparator)
// check if no changes to imports required
val oldImports = file.importDirectives
if (oldImports.size == sortedImportsToGenerate.size && oldImports.map { it.importPath } == sortedImportsToGenerate) return null
val originalFileScope = file.getFileResolutionScope()
val newFileScope = buildScopeByImports(file, sortedImportsToGenerate)
var references = data.references
if (testLog != null) {
// to make log the same for all runs
references = references.sortedBy { it.toString() }
}
for ((names, refs) in references.groupBy { it.dependsOnNames }) {
if (!areScopeSlicesEqual(originalFileScope, newFileScope, names)) {
for (ref in refs) {
ProgressManager.checkCanceled()
val element = ref.element
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
val expressionToAnalyze = getExpressionToAnalyze(element) ?: continue
val newScope = element.getResolutionScope(
bindingContext,
file.getResolutionFacade()
).replaceImportingScopes(newFileScope)
val newBindingContext = expressionToAnalyze.analyzeAsReplacement(
expressionToAnalyze,
bindingContext,
newScope,
trace = BindingTraceContext()
)
testLog?.append("Additional checking of reference $ref\n")
val oldTargets = ref.resolve(bindingContext)
val newTargets = ref.resolve(newBindingContext)
if (!areTargetsEqual(oldTargets, newTargets)) {
testLog?.append("Changed resolve of $ref\n")
(oldTargets + newTargets).forEach {
lockImportForDescriptor(it, names)
}
}
}
}
}
return sortedImportsToGenerate
}
private fun lockImportForDescriptor(descriptor: DeclarationDescriptor, existingNames: Collection<Name>) {
val fqName = descriptor.importableFqName ?: return
val names = data.namesToImport.getOrElse(fqName) { listOf(descriptor.name) }.intersect(existingNames)
val starImportPath = ImportPath(fqName.parent(), true)
val importPaths = file.importDirectives.map { it.importPath }
for (name in names) {
val alias = if (name != fqName.shortName()) name else null
val explicitImportPath = ImportPath(fqName, false, alias)
when {
explicitImportPath in importPaths ->
importRules.add(ImportRule.Add(explicitImportPath))
alias == null && starImportPath in importPaths ->
importRules.add(ImportRule.Add(starImportPath))
else -> // there is no import for this descriptor in the original import list, so do not allow to import it by star-import
importRules.add(ImportRule.DoNotAdd(starImportPath))
}
}
}
private fun addExplicitImportsForClassesWhenRequired(
classNamesToCheck: Collection<FqName>,
descriptorsByParentFqName: Map<FqName, MutableSet<DeclarationDescriptor>>,
importsToGenerate: MutableSet<ImportPath>,
originalFile: KtFile
) {
val scope = buildScopeByImports(originalFile, importsToGenerate.filter { it.isAllUnder })
for (fqName in classNamesToCheck) {
if (scope.findClassifier(fqName.shortName(), NoLookupLocation.FROM_IDE)?.importableFqName != fqName) {
// add explicit import if failed to import with * (or from current package)
importsToGenerate.add(ImportPath(fqName, false))
val parentFqName = fqName.parent()
val siblingsToImport = descriptorsByParentFqName.getValue(parentFqName)
for (descriptor in siblingsToImport.filter { it.importableFqName == fqName }) {
siblingsToImport.remove(descriptor)
}
if (siblingsToImport.isEmpty()) { // star import is not really needed
importsToGenerate.remove(ImportPath(parentFqName, true))
}
}
}
}
private fun buildScopeByImports(originalFile: KtFile, importsToGenerate: Collection<ImportPath>): ImportingScope {
val fileText = buildString {
append("package ")
append(originalFile.packageFqName.toUnsafe().render())
append("\n")
for (importPath in importsToGenerate) {
append("import ")
append(importPath.pathStr)
if (importPath.hasAlias()) {
append("=")
append(importPath.alias!!.render())
}
append("\n")
}
}
val fileWithImports = KtPsiFactory(originalFile).createAnalyzableFile("Dummy_" + originalFile.name, fileText, originalFile)
if (file.isScript()) {
fileWithImports.originalFile = originalFile
}
return fileWithImports.getFileResolutionScope()
}
@OptIn(FrontendInternals::class)
private fun KtFile.getFileResolutionScope() =
getResolutionFacade().frontendService<FileScopeProvider>().getFileScopes(this).importingScope
private fun areScopeSlicesEqual(scope1: ImportingScope, scope2: ImportingScope, names: Collection<Name>): Boolean {
val tower1 = scope1.extractSliceTower(names)
val tower2 = scope2.extractSliceTower(names)
val iterator1 = tower1.iterator()
val iterator2 = tower2.iterator()
while (true) {
when {
!iterator1.hasNext() -> return !iterator2.hasNext()
!iterator2.hasNext() -> return false
else -> if (!areTargetsEqual(iterator1.next(), iterator2.next())) return false
}
}
}
private fun ImportingScope.extractSliceTower(names: Collection<Name>): Sequence<Collection<DeclarationDescriptor>> {
return parentsWithSelf
.map { scope ->
names.flatMap { name ->
ProgressManager.checkCanceled()
val contributedFunctions = scope.getContributedFunctions(name, NoLookupLocation.FROM_IDE)
ProgressManager.checkCanceled()
val contributedVariables = scope.getContributedVariables(name, NoLookupLocation.FROM_IDE)
ProgressManager.checkCanceled()
val contributedClassifier = scope.getContributedClassifier(name, NoLookupLocation.FROM_IDE)
contributedFunctions + contributedVariables + listOfNotNull(contributedClassifier)
}
}
.filter { it.isNotEmpty() }
}
private fun canUseStarImport(descriptor: DeclarationDescriptor, fqName: FqName): Boolean = when {
fqName.parent().isRoot -> false
(descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.OBJECT -> false
else -> true
}
private fun needExplicitImport(fqName: FqName): Boolean = hasAlias(fqName) || !isImportedByDefault(fqName)
private fun hasAlias(fqName: FqName) = data.namesToImport[fqName]?.let {
it.singleOrNull() == null
} ?: false
private fun isImportedByDefault(fqName: FqName) = importInsertHelper.isImportedWithDefault(ImportPath(fqName, false), file)
private fun isImportedByLowPriorityDefault(fqName: FqName) =
importInsertHelper.isImportedWithLowPriorityDefaultImport(ImportPath(fqName, false), file)
private fun DeclarationDescriptor.nameCountToUseStar(): Int {
val isMember = containingDeclaration is ClassDescriptor
return if (isMember)
options.nameCountToUseStarImportForMembers
else
options.nameCountToUseStarImport
}
private fun areTargetsEqual(descriptors1: Collection<DeclarationDescriptor>, descriptors2: Collection<DeclarationDescriptor>): Boolean {
return descriptors1.size == descriptors2.size &&
descriptors1.zip(descriptors2).all { (first, second) -> areTargetsEqual(first, second) } //TODO: can have different order?
}
private fun areTargetsEqual(first: DeclarationDescriptor, second: DeclarationDescriptor): Boolean {
if (first == second) return true
val firstFqName = first.importableFqName
val secondFqName = second.importableFqName
return firstFqName == secondFqName ||
(first.isAliasTo(second) && secondFqName != null && isImportedByLowPriorityDefault(secondFqName)) ||
(second.isAliasTo(first) && firstFqName != null && isImportedByLowPriorityDefault(firstFqName))
}
private fun DeclarationDescriptor.isAliasTo(other: DeclarationDescriptor): Boolean =
this is TypeAliasDescriptor && classDescriptor == other ||
this is TypeAliasConstructorDescriptor && underlyingConstructorDescriptor == other
private fun ImportPath.isAllowedByRules(): Boolean = importRules.none { it is ImportRule.DoNotAdd && it.importPath == this }
}

View File

@@ -1,36 +0,0 @@
/*
* Copyright 2010-2019 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.idea.kdoc
import com.intellij.openapi.components.ServiceManager
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.resolve.BindingContext
interface SampleResolutionService {
fun resolveSample(
context: BindingContext,
fromDescriptor: DeclarationDescriptor,
resolutionFacade: ResolutionFacade,
qualifiedName: List<String>
): Collection<DeclarationDescriptor>
companion object {
/**
* It's internal implementation, please use [resolveKDocSampleLink], or [resolveKDocLink]
*/
internal fun resolveSample(
context: BindingContext,
fromDescriptor: DeclarationDescriptor,
resolutionFacade: ResolutionFacade,
qualifiedName: List<String>
): Collection<DeclarationDescriptor> {
val instance = ServiceManager.getService(resolutionFacade.project, SampleResolutionService::class.java)
return instance?.resolveSample(context, fromDescriptor, resolutionFacade, qualifiedName) ?: emptyList()
}
}
}

View File

@@ -1,110 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.kdoc
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
import org.jetbrains.kotlin.kdoc.psi.api.KDoc
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
fun DeclarationDescriptor.findKDoc(
descriptorToPsi: (DeclarationDescriptorWithSource) -> PsiElement? = { DescriptorToSourceUtils.descriptorToDeclaration(it) }
): KDocTag? {
if (this is DeclarationDescriptorWithSource) {
val psiDeclaration = descriptorToPsi(this)?.navigationElement
return (psiDeclaration as? KtElement)?.findKDoc(descriptorToPsi)
}
return null
}
private typealias DescriptorToPsi = (DeclarationDescriptorWithSource) -> PsiElement?
fun KtElement.findKDoc(descriptorToPsi: DescriptorToPsi): KDocTag? {
return this.lookupOwnedKDoc()
?: this.lookupKDocInContainer()
?: this.lookupInheritedKDoc(descriptorToPsi)
}
private fun KtElement.lookupOwnedKDoc(): KDocTag? {
// KDoc for primary constructor is located inside of its class KDoc
val psiDeclaration = when (this) {
is KtPrimaryConstructor -> getContainingClassOrObject()
else -> this
}
if (psiDeclaration is KtDeclaration) {
val kdoc = psiDeclaration.docComment
if (kdoc != null) {
if (this is KtConstructor<*>) {
// ConstructorDescriptor resolves to the same JetDeclaration
val constructorSection = kdoc.findSectionByTag(KDocKnownTag.CONSTRUCTOR)
if (constructorSection != null) {
return constructorSection
}
}
return kdoc.getDefaultSection()
}
}
return null
}
private fun KtElement.lookupKDocInContainer(): KDocTag? {
val subjectName = name
val containingDeclaration =
PsiTreeUtil.findFirstParent(this, true) {
it is KtDeclarationWithBody && it !is KtPrimaryConstructor
|| it is KtClassOrObject
}
val containerKDoc = containingDeclaration?.getChildOfType<KDoc>()
if (containerKDoc == null || subjectName == null) return null
val propertySection = containerKDoc.findSectionByTag(KDocKnownTag.PROPERTY, subjectName)
val paramTag = containerKDoc.findDescendantOfType<KDocTag> { it.knownTag == KDocKnownTag.PARAM && it.getSubjectName() == subjectName }
return when {
this is KtParameter && this.isPropertyParameter() -> propertySection ?: paramTag
this is KtParameter || this is KtTypeParameter -> paramTag
this is KtProperty && containingDeclaration is KtClassOrObject -> propertySection
else -> null
}
}
private fun KtElement.lookupInheritedKDoc(descriptorToPsi: DescriptorToPsi): KDocTag? {
if (this is KtCallableDeclaration) {
val descriptor = this.resolveToDescriptorIfAny() as? CallableDescriptor ?: return null
for (baseDescriptor in descriptor.overriddenDescriptors) {
val baseKDoc = baseDescriptor.original.findKDoc(descriptorToPsi)
if (baseKDoc != null) {
return baseKDoc
}
}
}
return null
}

View File

@@ -1,287 +0,0 @@
/*
* Copyright 2010-2019 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.idea.kdoc
import com.intellij.openapi.components.ServiceManager
import org.jetbrains.kotlin.caches.resolve.KotlinCacheService
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.getFileResolutionScope
import org.jetbrains.kotlin.idea.util.substituteExtensionIfCallable
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtQualifiedExpression
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.FunctionDescriptorUtil
import org.jetbrains.kotlin.resolve.QualifiedExpressionResolver
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.resolve.scopes.*
import org.jetbrains.kotlin.resolve.scopes.utils.*
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
fun resolveKDocLink(
context: BindingContext,
resolutionFacade: ResolutionFacade,
fromDescriptor: DeclarationDescriptor,
fromSubjectOfTag: KDocTag?,
qualifiedName: List<String>
): Collection<DeclarationDescriptor> = when (fromSubjectOfTag?.knownTag) {
KDocKnownTag.PARAM -> resolveParamLink(fromDescriptor, qualifiedName)
KDocKnownTag.SAMPLE -> resolveKDocSampleLink(context, resolutionFacade, fromDescriptor, qualifiedName)
else -> resolveDefaultKDocLink(context, resolutionFacade, fromDescriptor, qualifiedName)
}
fun getParamDescriptors(fromDescriptor: DeclarationDescriptor): List<DeclarationDescriptor> {
// TODO resolve parameters of functions passed as parameters
when (fromDescriptor) {
is CallableDescriptor -> {
return fromDescriptor.valueParameters + fromDescriptor.typeParameters
}
is ClassifierDescriptor -> {
val typeParams = fromDescriptor.typeConstructor.parameters
if (fromDescriptor is ClassDescriptor) {
val constructorDescriptor = fromDescriptor.unsubstitutedPrimaryConstructor
if (constructorDescriptor != null) {
return typeParams + constructorDescriptor.valueParameters
}
}
return typeParams
}
else -> {
return emptyList()
}
}
}
private fun resolveParamLink(fromDescriptor: DeclarationDescriptor, qualifiedName: List<String>): List<DeclarationDescriptor> {
val name = qualifiedName.singleOrNull() ?: return emptyList()
return getParamDescriptors(fromDescriptor).filter { it.name.asString() == name }
}
fun resolveKDocSampleLink(
context: BindingContext,
resolutionFacade: ResolutionFacade,
fromDescriptor: DeclarationDescriptor,
qualifiedName: List<String>
): Collection<DeclarationDescriptor> {
val resolvedViaService = SampleResolutionService.resolveSample(context, fromDescriptor, resolutionFacade, qualifiedName)
if (resolvedViaService.isNotEmpty()) return resolvedViaService
return resolveDefaultKDocLink(context, resolutionFacade, fromDescriptor, qualifiedName)
}
private fun resolveDefaultKDocLink(
context: BindingContext,
resolutionFacade: ResolutionFacade,
fromDescriptor: DeclarationDescriptor,
qualifiedName: List<String>
): Collection<DeclarationDescriptor> {
val contextScope = getKDocLinkResolutionScope(resolutionFacade, fromDescriptor)
if (qualifiedName.size == 1) {
val shortName = Name.identifier(qualifiedName.single())
val descriptorsByName = SmartList<DeclarationDescriptor>()
descriptorsByName.addIfNotNull(contextScope.findClassifier(shortName, NoLookupLocation.FROM_IDE))
descriptorsByName.addIfNotNull(contextScope.findPackage(shortName))
descriptorsByName.addAll(contextScope.collectFunctions(shortName, NoLookupLocation.FROM_IDE))
descriptorsByName.addAll(contextScope.collectVariables(shortName, NoLookupLocation.FROM_IDE))
if (fromDescriptor is FunctionDescriptor && fromDescriptor.isExtension && shortName.asString() == "this") {
return listOfNotNull(fromDescriptor.extensionReceiverParameter)
}
// Try to find a matching local descriptor (parameter or type parameter) first
val localDescriptors = descriptorsByName.filter { it.containingDeclaration == fromDescriptor }
if (localDescriptors.isNotEmpty()) return localDescriptors
return descriptorsByName
}
val moduleDescriptor = fromDescriptor.module
@OptIn(FrontendInternals::class)
val qualifiedExpressionResolver = resolutionFacade.getFrontendService(moduleDescriptor, QualifiedExpressionResolver::class.java)
val contextElement = DescriptorToSourceUtils.descriptorToDeclaration(fromDescriptor)
val factory = KtPsiFactory(resolutionFacade.project)
// TODO escape identifiers
val codeFragment = factory.createExpressionCodeFragment(qualifiedName.joinToString("."), contextElement)
val qualifiedExpression =
codeFragment.findElementAt(codeFragment.textLength - 1)?.getStrictParentOfType<KtQualifiedExpression>() ?: return emptyList()
val (descriptor, memberName) = qualifiedExpressionResolver.resolveClassOrPackageInQualifiedExpression(
qualifiedExpression,
contextScope,
context
)
if (descriptor == null) return emptyList()
if (memberName != null) {
val memberScope = getKDocLinkMemberScope(descriptor, contextScope)
return memberScope.getContributedFunctions(memberName, NoLookupLocation.FROM_IDE) +
memberScope.getContributedVariables(memberName, NoLookupLocation.FROM_IDE) +
listOfNotNull(memberScope.getContributedClassifier(memberName, NoLookupLocation.FROM_IDE))
}
return listOf(descriptor)
}
private fun getPackageInnerScope(descriptor: PackageFragmentDescriptor): MemberScope {
return descriptor.containingDeclaration.getPackage(descriptor.fqName).memberScope
}
private fun getClassInnerScope(outerScope: LexicalScope, descriptor: ClassDescriptor): LexicalScope {
val headerScope = LexicalScopeImpl(
outerScope, descriptor, false, descriptor.thisAsReceiverParameter,
LexicalScopeKind.SYNTHETIC
) {
descriptor.declaredTypeParameters.forEach { addClassifierDescriptor(it) }
descriptor.constructors.forEach { addFunctionDescriptor(it) }
}
return LexicalChainedScope.create(
headerScope, descriptor, false, null, LexicalScopeKind.SYNTHETIC,
descriptor.defaultType.memberScope,
descriptor.staticScope,
descriptor.companionObjectDescriptor?.defaultType?.memberScope
)
}
fun getKDocLinkResolutionScope(resolutionFacade: ResolutionFacade, contextDescriptor: DeclarationDescriptor): LexicalScope {
return when (contextDescriptor) {
is PackageFragmentDescriptor ->
LexicalScope.Base(getPackageInnerScope(contextDescriptor).memberScopeAsImportingScope(), contextDescriptor)
is PackageViewDescriptor ->
LexicalScope.Base(contextDescriptor.memberScope.memberScopeAsImportingScope(), contextDescriptor)
is ClassDescriptor ->
getClassInnerScope(getOuterScope(contextDescriptor, resolutionFacade), contextDescriptor)
is FunctionDescriptor -> FunctionDescriptorUtil.getFunctionInnerScope(
getOuterScope(contextDescriptor, resolutionFacade),
contextDescriptor, LocalRedeclarationChecker.DO_NOTHING
)
is PropertyDescriptor ->
ScopeUtils.makeScopeForPropertyHeader(getOuterScope(contextDescriptor, resolutionFacade), contextDescriptor)
is DeclarationDescriptorNonRoot ->
getOuterScope(contextDescriptor, resolutionFacade)
else -> throw IllegalArgumentException("Cannot find resolution scope for root $contextDescriptor")
}
}
private fun getOuterScope(descriptor: DeclarationDescriptorWithSource, resolutionFacade: ResolutionFacade): LexicalScope {
val parent = descriptor.containingDeclaration!!
if (parent is PackageFragmentDescriptor) {
val containingFile = (descriptor.source as? PsiSourceElement)?.psi?.containingFile as? KtFile ?: return LexicalScope.Base(
ImportingScope.Empty,
parent
)
val kotlinCacheService = ServiceManager.getService(containingFile.project, KotlinCacheService::class.java)
val facadeToUse = kotlinCacheService?.getResolutionFacade(listOf(containingFile)) ?: resolutionFacade
return facadeToUse.getFileResolutionScope(containingFile)
} else {
return getKDocLinkResolutionScope(resolutionFacade, parent)
}
}
fun getKDocLinkMemberScope(descriptor: DeclarationDescriptor, contextScope: LexicalScope): MemberScope {
return when (descriptor) {
is PackageFragmentDescriptor -> getPackageInnerScope(descriptor)
is PackageViewDescriptor -> descriptor.memberScope
is ClassDescriptor -> {
ChainedMemberScope.create(
"Member scope for KDoc resolve", listOfNotNull(
descriptor.unsubstitutedMemberScope,
descriptor.staticScope,
descriptor.companionObjectDescriptor?.unsubstitutedMemberScope,
ExtensionsScope(descriptor, contextScope)
)
)
}
else -> MemberScope.Empty
}
}
private class ExtensionsScope(
private val receiverClass: ClassDescriptor,
private val contextScope: LexicalScope
) : MemberScope {
private val receiverTypes = listOf(receiverClass.defaultType)
override fun getContributedFunctions(name: Name, location: LookupLocation): Collection<SimpleFunctionDescriptor> {
return contextScope.collectFunctions(name, location).flatMap {
if (it is SimpleFunctionDescriptor && it.isExtension) it.substituteExtensionIfCallable(
receiverTypes,
CallType.DOT
) else emptyList()
}
}
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
return contextScope.collectVariables(name, location).flatMap {
if (it is PropertyDescriptor && it.isExtension) it.substituteExtensionIfCallable(
receiverTypes,
CallType.DOT
) else emptyList()
}
}
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? = null
override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): Collection<DeclarationDescriptor> {
if (DescriptorKindExclude.Extensions in kindFilter.excludes) return emptyList()
return contextScope.collectDescriptorsFiltered(
kindFilter exclude DescriptorKindExclude.NonExtensions,
nameFilter,
changeNamesForAliased = true
).flatMap {
if (it is CallableDescriptor && it.isExtension) it.substituteExtensionIfCallable(
receiverTypes,
CallType.DOT
) else emptyList()
}
}
override fun getFunctionNames(): Set<Name> =
getContributedDescriptors(kindFilter = DescriptorKindFilter.FUNCTIONS).map { it.name }.toSet()
override fun getVariableNames(): Set<Name> =
getContributedDescriptors(kindFilter = DescriptorKindFilter.VARIABLES).map { it.name }.toSet()
override fun getClassifierNames() = null
override fun printScopeStructure(p: Printer) {
p.println("Extensions for ${receiverClass.name} in:")
contextScope.printStructure(p)
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2010-2019 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.idea.refactoring.introduce
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.resolve.getLanguageVersionSettings
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.nextSiblingOfSameType
import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
class ExtractableSubstringInfo(
val startEntry: KtStringTemplateEntry,
val endEntry: KtStringTemplateEntry,
val prefix: String,
val suffix: String,
type: KotlinType? = null
) {
private fun guessLiteralType(literal: String): KotlinType {
val facade = template.getResolutionFacade()
val module = facade.moduleDescriptor
val stringType = module.builtIns.stringType
if (startEntry != endEntry || startEntry !is KtLiteralStringTemplateEntry) return stringType
val expr = KtPsiFactory(startEntry).createExpressionIfPossible(literal) ?: return stringType
val context = facade.analyze(template, BodyResolveMode.PARTIAL)
val scope = template.getResolutionScope(context, facade)
val tempContext = expr.analyzeInContext(scope, template)
val trace = DelegatingBindingTrace(tempContext, "Evaluate '$literal'")
val languageVersionSettings = facade.getLanguageVersionSettings()
val value = ConstantExpressionEvaluator(module, languageVersionSettings, facade.project).evaluateExpression(expr, trace)
if (value == null || value.isError) return stringType
return value.toConstantValue(TypeUtils.NO_EXPECTED_TYPE).getType(module)
}
val template: KtStringTemplateExpression = startEntry.parent as KtStringTemplateExpression
val content = with(entries.map { it.text }.joinToString(separator = "")) { substring(prefix.length, length - suffix.length) }
val type = type ?: guessLiteralType(content)
val contentRange: TextRange
get() = TextRange(startEntry.startOffset + prefix.length, endEntry.endOffset - suffix.length)
val relativeContentRange: TextRange
get() = contentRange.shiftRight(-template.startOffset)
val entries: Sequence<KtStringTemplateEntry>
get() = generateSequence(startEntry) { if (it != endEntry) it.nextSiblingOfSameType() else null }
fun createExpression(): KtExpression {
val quote = template.firstChild.text
val literalValue = if (KotlinBuiltIns.isString(type)) "$quote$content$quote" else content
return KtPsiFactory(startEntry).createExpression(literalValue).apply { extractableSubstringInfo = this@ExtractableSubstringInfo }
}
fun copy(newTemplate: KtStringTemplateExpression): ExtractableSubstringInfo {
val oldEntries = template.entries
val newEntries = newTemplate.entries
val startIndex = oldEntries.indexOf(startEntry)
val endIndex = oldEntries.indexOf(endEntry)
if (startIndex < 0 || startIndex >= newEntries.size || endIndex < 0 || endIndex >= newEntries.size) {
throw AssertionError("Old template($startIndex..$endIndex): ${template.text}, new template: ${newTemplate.text}")
}
return ExtractableSubstringInfo(newEntries[startIndex], newEntries[endIndex], prefix, suffix, type)
}
}
var KtExpression.extractableSubstringInfo: ExtractableSubstringInfo? by UserDataProperty(Key.create("EXTRACTED_SUBSTRING_INFO"))
val KtExpression.substringContextOrThis: KtExpression
get() = extractableSubstringInfo?.template ?: this
val PsiElement.substringContextOrThis: PsiElement
get() = (this as? KtExpression)?.extractableSubstringInfo?.template ?: this

View File

@@ -1,57 +0,0 @@
/*
* Copyright 2010-2019 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.idea.resolve
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.analyzer.AnalysisResult
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
interface ResolutionFacade {
val project: Project
fun analyze(element: KtElement, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): BindingContext
fun analyze(elements: Collection<KtElement>, bodyResolveMode: BodyResolveMode): BindingContext
fun analyzeWithAllCompilerChecks(elements: Collection<KtElement>, callback: DiagnosticSink.DiagnosticsCallback? = null): AnalysisResult
fun resolveToDescriptor(declaration: KtDeclaration, bodyResolveMode: BodyResolveMode = BodyResolveMode.FULL): DeclarationDescriptor
val moduleDescriptor: ModuleDescriptor
// get service for the module this resolution was created for
@FrontendInternals
fun <T : Any> getFrontendService(serviceClass: Class<T>): T
fun <T : Any> getIdeService(serviceClass: Class<T>): T
// get service for the module defined by PsiElement/ModuleDescriptor passed as parameter
@FrontendInternals
fun <T : Any> getFrontendService(element: PsiElement, serviceClass: Class<T>): T
@FrontendInternals
fun <T : Any> tryGetFrontendService(element: PsiElement, serviceClass: Class<T>): T?
@FrontendInternals
fun <T : Any> getFrontendService(moduleDescriptor: ModuleDescriptor, serviceClass: Class<T>): T
fun getResolverForProject(): ResolverForProject<out ModuleInfo>
}
@FrontendInternals
inline fun <reified T : Any> ResolutionFacade.frontendService(): T = this.getFrontendService(T::class.java)
inline fun <reified T : Any> ResolutionFacade.ideService(): T = this.getIdeService(T::class.java)

View File

@@ -1,24 +0,0 @@
/*
* Copyright 2010-2020 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.idea.resolve
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
/**
* Helper methods for commonly used frontend components.
* Use them to avoid explicit opt-ins.
* Before adding a new helper method please make sure component doesn't have fragile invariants that can be violated by external use.
*/
@OptIn(FrontendInternals::class)
fun ResolutionFacade.getLanguageVersionSettings(): LanguageVersionSettings =
frontendService<LanguageVersionSettings>()
@OptIn(FrontendInternals::class)
fun ResolutionFacade.getDataFlowValueFactory(): DataFlowValueFactory =
frontendService<DataFlowValueFactory>()

View File

@@ -1,29 +0,0 @@
/*
* Copyright 2010-2020 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.idea.util
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.command.CommandProcessor
enum class ActionRunningMode {
RUN_IN_CURRENT_THREAD,
RUN_IN_EDT
}
inline fun <T> ActionRunningMode.runAction(crossinline action: () -> T): T = when (this) {
ActionRunningMode.RUN_IN_CURRENT_THREAD -> {
action()
}
ActionRunningMode.RUN_IN_EDT -> {
var result: T? = null
ApplicationManager.getApplication().invokeAndWait {
CommandProcessor.getInstance().runUndoTransparentAction {
result = ApplicationManager.getApplication().runWriteAction<T> { action() }
}
}
result!!
}
}

View File

@@ -1,376 +0,0 @@
/*
* Copyright 2010-2019 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.idea.util
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.resolve.getDataFlowValueFactory
import org.jetbrains.kotlin.idea.resolve.getLanguageVersionSettings
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression
import org.jetbrains.kotlin.psi.psiUtil.isPackageDirectiveExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.DslMarkerUtils
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
import org.jetbrains.kotlin.resolve.descriptorUtil.classValueType
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindExclude
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.receivers.TypeAliasQualifier
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
import org.jetbrains.kotlin.util.supertypesWithAny
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.util.*
sealed class CallType<TReceiver : KtElement?>(val descriptorKindFilter: DescriptorKindFilter) {
object UNKNOWN : CallType<Nothing?>(DescriptorKindFilter.ALL)
object DEFAULT : CallType<Nothing?>(DescriptorKindFilter.ALL)
object DOT : CallType<KtExpression>(DescriptorKindFilter.ALL)
object SAFE : CallType<KtExpression>(DescriptorKindFilter.ALL)
object SUPER_MEMBERS : CallType<KtSuperExpression>(
DescriptorKindFilter.CALLABLES exclude DescriptorKindExclude.Extensions exclude AbstractMembersExclude
)
object INFIX : CallType<KtExpression>(DescriptorKindFilter.FUNCTIONS exclude NonInfixExclude)
object OPERATOR : CallType<KtExpression>(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude)
object CALLABLE_REFERENCE : CallType<KtExpression?>(DescriptorKindFilter.CALLABLES exclude CallableReferenceExclude)
object IMPORT_DIRECTIVE : CallType<KtExpression?>(DescriptorKindFilter.ALL)
object PACKAGE_DIRECTIVE : CallType<KtExpression?>(DescriptorKindFilter.PACKAGES)
object TYPE : CallType<KtExpression?>(
DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)
exclude DescriptorKindExclude.EnumEntry
)
object DELEGATE : CallType<KtExpression?>(DescriptorKindFilter.FUNCTIONS exclude NonOperatorExclude)
object ANNOTATION : CallType<KtExpression?>(
DescriptorKindFilter(DescriptorKindFilter.CLASSIFIERS_MASK or DescriptorKindFilter.PACKAGES_MASK)
exclude NonAnnotationClassifierExclude
)
private object NonInfixExclude : DescriptorKindExclude() {
override fun excludes(descriptor: DeclarationDescriptor) =
!(descriptor is SimpleFunctionDescriptor && descriptor.isInfix)
override val fullyExcludedDescriptorKinds: Int
get() = 0
}
private object NonOperatorExclude : DescriptorKindExclude() {
override fun excludes(descriptor: DeclarationDescriptor) =
!(descriptor is SimpleFunctionDescriptor && descriptor.isOperator)
override val fullyExcludedDescriptorKinds: Int
get() = 0
}
private object CallableReferenceExclude : DescriptorKindExclude() {
override fun excludes(descriptor: DeclarationDescriptor) /* currently not supported for locals and synthetic */ =
descriptor !is CallableMemberDescriptor || descriptor.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
override val fullyExcludedDescriptorKinds: Int
get() = 0
}
private object NonAnnotationClassifierExclude : DescriptorKindExclude() {
override fun excludes(descriptor: DeclarationDescriptor): Boolean {
if (descriptor !is ClassifierDescriptor) return false
return descriptor !is ClassDescriptor || descriptor.kind != ClassKind.ANNOTATION_CLASS
}
override val fullyExcludedDescriptorKinds: Int get() = 0
}
private object AbstractMembersExclude : DescriptorKindExclude() {
override fun excludes(descriptor: DeclarationDescriptor) =
descriptor is CallableMemberDescriptor && descriptor.modality == Modality.ABSTRACT
override val fullyExcludedDescriptorKinds: Int
get() = 0
}
}
sealed class CallTypeAndReceiver<TReceiver : KtElement?, out TCallType : CallType<TReceiver>>(
val callType: TCallType,
val receiver: TReceiver
) {
object UNKNOWN : CallTypeAndReceiver<Nothing?, CallType.UNKNOWN>(CallType.UNKNOWN, null)
object DEFAULT : CallTypeAndReceiver<Nothing?, CallType.DEFAULT>(CallType.DEFAULT, null)
class DOT(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.DOT>(CallType.DOT, receiver)
class SAFE(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.SAFE>(CallType.SAFE, receiver)
class SUPER_MEMBERS(receiver: KtSuperExpression) : CallTypeAndReceiver<KtSuperExpression, CallType.SUPER_MEMBERS>(
CallType.SUPER_MEMBERS, receiver
)
class INFIX(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.INFIX>(CallType.INFIX, receiver)
class OPERATOR(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.OPERATOR>(CallType.OPERATOR, receiver)
class CALLABLE_REFERENCE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.CALLABLE_REFERENCE>(
CallType.CALLABLE_REFERENCE, receiver
)
class IMPORT_DIRECTIVE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.IMPORT_DIRECTIVE>(
CallType.IMPORT_DIRECTIVE, receiver
)
class PACKAGE_DIRECTIVE(receiver: KtExpression?) :
CallTypeAndReceiver<KtExpression?, CallType.PACKAGE_DIRECTIVE>(CallType.PACKAGE_DIRECTIVE, receiver)
class TYPE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.TYPE>(CallType.TYPE, receiver)
class DELEGATE(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.DELEGATE>(CallType.DELEGATE, receiver)
class ANNOTATION(receiver: KtExpression?) : CallTypeAndReceiver<KtExpression?, CallType.ANNOTATION>(CallType.ANNOTATION, receiver)
companion object {
fun detect(expression: KtSimpleNameExpression): CallTypeAndReceiver<*, *> {
val parent = expression.parent
if (parent is KtCallableReferenceExpression && expression == parent.callableReference) {
return CALLABLE_REFERENCE(parent.receiverExpression)
}
val receiverExpression = expression.getReceiverExpression()
if (expression.isImportDirectiveExpression()) {
return IMPORT_DIRECTIVE(receiverExpression)
}
if (expression.isPackageDirectiveExpression()) {
return PACKAGE_DIRECTIVE(receiverExpression)
}
if (parent is KtUserType) {
val constructorCallee = (parent.parent as? KtTypeReference)?.parent as? KtConstructorCalleeExpression
if (constructorCallee != null && constructorCallee.parent is KtAnnotationEntry) {
return ANNOTATION(receiverExpression)
}
return TYPE(receiverExpression)
}
when (expression) {
is KtOperationReferenceExpression -> {
if (receiverExpression == null) {
return UNKNOWN // incomplete code
}
return when (parent) {
is KtBinaryExpression -> {
if (parent.operationToken == KtTokens.IDENTIFIER)
INFIX(receiverExpression)
else
OPERATOR(receiverExpression)
}
is KtUnaryExpression -> OPERATOR(receiverExpression)
else -> error("Unknown parent for JetOperationReferenceExpression: $parent with text '${parent.text}'")
}
}
is KtNameReferenceExpression -> {
if (receiverExpression == null) {
return DEFAULT
}
if (receiverExpression is KtSuperExpression) {
return SUPER_MEMBERS(receiverExpression)
}
return when (parent) {
is KtCallExpression -> {
if ((parent.parent as KtQualifiedExpression).operationSign == KtTokens.SAFE_ACCESS)
SAFE(receiverExpression)
else
DOT(receiverExpression)
}
is KtQualifiedExpression -> {
if (parent.operationSign == KtTokens.SAFE_ACCESS)
SAFE(receiverExpression)
else
DOT(receiverExpression)
}
else -> error("Unknown parent for JetNameReferenceExpression with receiver: $parent")
}
}
else -> return UNKNOWN
}
}
}
}
data class ReceiverType(
val type: KotlinType,
val receiverIndex: Int,
val implicitValue: ReceiverValue? = null
) {
val implicit: Boolean get() = implicitValue != null
fun extractDslMarkers() =
implicitValue?.let(DslMarkerUtils::extractDslMarkerFqNames)?.all()
?: DslMarkerUtils.extractDslMarkerFqNames(type)
}
fun CallTypeAndReceiver<*, *>.receiverTypes(
bindingContext: BindingContext,
contextElement: PsiElement,
moduleDescriptor: ModuleDescriptor,
resolutionFacade: ResolutionFacade,
stableSmartCastsOnly: Boolean
): List<KotlinType>? {
return receiverTypesWithIndex(bindingContext, contextElement, moduleDescriptor, resolutionFacade, stableSmartCastsOnly)?.map { it.type }
}
fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex(
bindingContext: BindingContext,
contextElement: PsiElement,
moduleDescriptor: ModuleDescriptor,
resolutionFacade: ResolutionFacade,
stableSmartCastsOnly: Boolean,
withImplicitReceiversWhenExplicitPresent: Boolean = false
): List<ReceiverType>? {
val languageVersionSettings = resolutionFacade.getLanguageVersionSettings()
val receiverExpression: KtExpression?
when (this) {
is CallTypeAndReceiver.CALLABLE_REFERENCE -> {
if (receiver != null) {
return when (val lhs = bindingContext[BindingContext.DOUBLE_COLON_LHS, receiver] ?: return emptyList()) {
is DoubleColonLHS.Type -> listOf(ReceiverType(lhs.type, 0))
is DoubleColonLHS.Expression -> {
val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext)
receiverValueTypes(
receiverValue, lhs.dataFlowInfo, bindingContext,
moduleDescriptor, stableSmartCastsOnly,
resolutionFacade
).map { ReceiverType(it, 0) }
}
}
} else {
return emptyList()
}
}
is CallTypeAndReceiver.DEFAULT -> receiverExpression = null
is CallTypeAndReceiver.DOT -> receiverExpression = receiver
is CallTypeAndReceiver.SAFE -> receiverExpression = receiver
is CallTypeAndReceiver.INFIX -> receiverExpression = receiver
is CallTypeAndReceiver.OPERATOR -> receiverExpression = receiver
is CallTypeAndReceiver.DELEGATE -> receiverExpression = receiver
is CallTypeAndReceiver.SUPER_MEMBERS -> {
val qualifier = receiver.superTypeQualifier
return if (qualifier != null) {
listOfNotNull(bindingContext.getType(receiver)).map { ReceiverType(it, 0) }
} else {
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
val classDescriptor =
resolutionScope.ownerDescriptor.parentsWithSelf.firstIsInstanceOrNull<ClassDescriptor>() ?: return emptyList()
classDescriptor.typeConstructor.supertypesWithAny().map { ReceiverType(it, 0) }
}
}
is CallTypeAndReceiver.IMPORT_DIRECTIVE,
is CallTypeAndReceiver.PACKAGE_DIRECTIVE,
is CallTypeAndReceiver.TYPE,
is CallTypeAndReceiver.ANNOTATION,
is CallTypeAndReceiver.UNKNOWN ->
return null
}
val resolutionScope = contextElement.getResolutionScope(bindingContext, resolutionFacade)
val expressionReceiver = receiverExpression?.let {
val receiverType =
bindingContext.getType(receiverExpression) ?: (bindingContext.get(
BindingContext.QUALIFIER,
receiverExpression
) as? ClassQualifier)?.descriptor?.classValueType ?: (bindingContext.get(
BindingContext.QUALIFIER,
receiverExpression
) as? TypeAliasQualifier)?.classDescriptor?.classValueType ?: return emptyList()
ExpressionReceiver.create(receiverExpression, receiverType, bindingContext)
}
val implicitReceiverValues = resolutionScope.getImplicitReceiversWithInstance(
excludeShadowedByDslMarkers = languageVersionSettings.supportsFeature(LanguageFeature.DslMarkersSupport)
).map { it.value }
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(contextElement)
val result = ArrayList<ReceiverType>()
var receiverIndex = 0
fun addReceiverType(receiverValue: ReceiverValue, implicit: Boolean) {
val types = receiverValueTypes(
receiverValue, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly,
resolutionFacade
)
types.mapTo(result) { type -> ReceiverType(type, receiverIndex, receiverValue.takeIf { implicit }) }
receiverIndex++
}
if (withImplicitReceiversWhenExplicitPresent || expressionReceiver == null) {
implicitReceiverValues.forEach { addReceiverType(it, true) }
}
if (expressionReceiver != null) {
addReceiverType(expressionReceiver, false)
}
return result
}
@OptIn(FrontendInternals::class)
private fun receiverValueTypes(
receiverValue: ReceiverValue,
dataFlowInfo: DataFlowInfo,
bindingContext: BindingContext,
moduleDescriptor: ModuleDescriptor,
stableSmartCastsOnly: Boolean,
resolutionFacade: ResolutionFacade
): List<KotlinType> {
val languageVersionSettings = resolutionFacade.getLanguageVersionSettings()
val dataFlowValueFactory = resolutionFacade.getDataFlowValueFactory()
val smartCastManager = resolutionFacade.frontendService<SmartCastManager>()
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
return if (dataFlowValue.isStable || !stableSmartCastsOnly) { // we don't include smart cast receiver types for "unstable" receiver value to mark members grayed
smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(
receiverValue,
bindingContext,
moduleDescriptor,
dataFlowInfo,
languageVersionSettings,
dataFlowValueFactory
)
} else {
listOf(receiverValue.type)
}
}

View File

@@ -1,194 +0,0 @@
/*
* Copyright 2010-2019 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:JvmName("FuzzyTypeUtils")
package org.jetbrains.kotlin.idea.util
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.inference.CallHandle
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.StrictEqualityTypeChecker
import org.jetbrains.kotlin.types.typeUtil.*
import java.util.*
fun CallableDescriptor.fuzzyReturnType() = returnType?.toFuzzyType(typeParameters)
fun CallableDescriptor.fuzzyExtensionReceiverType() = extensionReceiverParameter?.type?.toFuzzyType(typeParameters)
fun FuzzyType.makeNotNullable() = type.makeNotNullable().toFuzzyType(freeParameters)
fun FuzzyType.makeNullable() = type.makeNullable().toFuzzyType(freeParameters)
fun FuzzyType.nullability() = type.nullability()
fun FuzzyType.isAlmostEverything(): Boolean {
if (freeParameters.isEmpty()) return false
val typeParameter = type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return false
if (typeParameter !in freeParameters) return false
return typeParameter.upperBounds.singleOrNull()?.isAnyOrNullableAny() ?: false
}
/**
* Replaces free parameters inside the type with corresponding type parameters of the class (when possible)
*/
fun FuzzyType.presentationType(): KotlinType {
if (freeParameters.isEmpty()) return type
val map = HashMap<TypeConstructor, TypeProjection>()
for ((argument, typeParameter) in type.arguments.zip(type.constructor.parameters)) {
if (argument.projectionKind == Variance.INVARIANT) {
val equalToFreeParameter = freeParameters.firstOrNull {
StrictEqualityTypeChecker.strictEqualTypes(it.defaultType, argument.type.unwrap())
} ?: continue
map[equalToFreeParameter.typeConstructor] = createProjection(typeParameter.defaultType, Variance.INVARIANT, null)
}
}
val substitutor = TypeSubstitutor.create(map)
return substitutor.substitute(type, Variance.INVARIANT)!!
}
fun KotlinType.toFuzzyType(freeParameters: Collection<TypeParameterDescriptor>) = FuzzyType(this, freeParameters)
class FuzzyType(
val type: KotlinType,
freeParameters: Collection<TypeParameterDescriptor>
) {
val freeParameters: Set<TypeParameterDescriptor>
init {
if (freeParameters.isNotEmpty()) {
// we allow to pass type parameters from another function with the same original in freeParameters
val usedTypeParameters = HashSet<TypeParameterDescriptor>().apply { addUsedTypeParameters(type) }
if (usedTypeParameters.isNotEmpty()) {
val originalFreeParameters = freeParameters.map { it.toOriginal() }.toSet()
this.freeParameters = usedTypeParameters.filter { it.toOriginal() in originalFreeParameters }.toSet()
} else {
this.freeParameters = emptySet()
}
} else {
this.freeParameters = emptySet()
}
}
// Diagnostic for EA-109046
@Suppress("USELESS_ELVIS")
private fun TypeParameterDescriptor.toOriginal(): TypeParameterDescriptor {
val callableDescriptor = containingDeclaration as? CallableMemberDescriptor ?: return this
val original = callableDescriptor.original ?: error("original = null for $callableDescriptor")
val typeParameters = original.typeParameters ?: error("typeParameters = null for $original")
return typeParameters[index]
}
override fun equals(other: Any?) = other is FuzzyType && other.type == type && other.freeParameters == freeParameters
override fun hashCode() = type.hashCode()
private fun MutableSet<TypeParameterDescriptor>.addUsedTypeParameters(type: KotlinType) {
val typeParameter = type.constructor.declarationDescriptor as? TypeParameterDescriptor
if (typeParameter != null && add(typeParameter)) {
typeParameter.upperBounds.forEach { addUsedTypeParameters(it) }
}
for (argument in type.arguments) {
if (!argument.isStarProjection) { // otherwise we can fall into infinite recursion
addUsedTypeParameters(argument.type)
}
}
}
fun checkIsSubtypeOf(otherType: FuzzyType): TypeSubstitutor? = matchedSubstitutor(otherType, MatchKind.IS_SUBTYPE)
fun checkIsSuperTypeOf(otherType: FuzzyType): TypeSubstitutor? = matchedSubstitutor(otherType, MatchKind.IS_SUPERTYPE)
fun checkIsSubtypeOf(otherType: KotlinType): TypeSubstitutor? = checkIsSubtypeOf(otherType.toFuzzyType(emptyList()))
fun checkIsSuperTypeOf(otherType: KotlinType): TypeSubstitutor? = checkIsSuperTypeOf(otherType.toFuzzyType(emptyList()))
private enum class MatchKind {
IS_SUBTYPE,
IS_SUPERTYPE
}
private fun matchedSubstitutor(otherType: FuzzyType, matchKind: MatchKind): TypeSubstitutor? {
if (type.isError) return null
if (otherType.type.isError) return null
if (otherType.type.isUnit() && matchKind == MatchKind.IS_SUBTYPE) return TypeSubstitutor.EMPTY
fun KotlinType.checkInheritance(otherType: KotlinType): Boolean {
return when (matchKind) {
MatchKind.IS_SUBTYPE -> this.isSubtypeOf(otherType)
MatchKind.IS_SUPERTYPE -> otherType.isSubtypeOf(this)
}
}
if (freeParameters.isEmpty() && otherType.freeParameters.isEmpty()) {
return if (type.checkInheritance(otherType.type)) TypeSubstitutor.EMPTY else null
}
val builder = ConstraintSystemBuilderImpl()
val typeVariableSubstitutor = builder.registerTypeVariables(CallHandle.NONE, freeParameters + otherType.freeParameters)
val typeInSystem = typeVariableSubstitutor.substitute(type, Variance.INVARIANT)
val otherTypeInSystem = typeVariableSubstitutor.substitute(otherType.type, Variance.INVARIANT)
when (matchKind) {
MatchKind.IS_SUBTYPE ->
builder.addSubtypeConstraint(typeInSystem, otherTypeInSystem, ConstraintPositionKind.RECEIVER_POSITION.position())
MatchKind.IS_SUPERTYPE ->
builder.addSubtypeConstraint(otherTypeInSystem, typeInSystem, ConstraintPositionKind.RECEIVER_POSITION.position())
}
builder.fixVariables()
val constraintSystem = builder.build()
if (constraintSystem.status.hasContradiction()) return null
// currently ConstraintSystem return successful status in case there are problems with nullability
// that's why we have to check subtyping manually
val substitutor = constraintSystem.resultingSubstitutor
val substitutedType = substitutor.substitute(type, Variance.INVARIANT) ?: return null
if (substitutedType.isError) return TypeSubstitutor.EMPTY
val otherSubstitutedType = substitutor.substitute(otherType.type, Variance.INVARIANT) ?: return null
if (otherSubstitutedType.isError) return TypeSubstitutor.EMPTY
if (!substitutedType.checkInheritance(otherSubstitutedType)) return null
val substitutorToKeepCapturedTypes = object : DelegatedTypeSubstitution(substitutor.substitution) {
override fun approximateCapturedTypes() = false
}.buildSubstitutor()
val substitutionMap: Map<TypeConstructor, TypeProjection> = constraintSystem.typeVariables
.map { it.originalTypeParameter }
.associateBy(
keySelector = { it.typeConstructor },
valueTransform = {
val typeProjection = TypeProjectionImpl(Variance.INVARIANT, it.defaultType)
val substitutedProjection = substitutorToKeepCapturedTypes.substitute(typeProjection)
substitutedProjection?.takeUnless { ErrorUtils.containsUninferredParameter(it.type) } ?: typeProjection
})
return TypeConstructorSubstitution.createByConstructorsMap(substitutionMap, approximateCapturedTypes = true).buildSubstitutor()
}
}
fun TypeSubstitution.hasConflictWith(other: TypeSubstitution, freeParameters: Collection<TypeParameterDescriptor>): Boolean {
return freeParameters.any { parameter ->
val type = parameter.defaultType
val substituted1 = this[type] ?: return@any false
val substituted2 = other[type] ?: return@any false
!StrictEqualityTypeChecker.strictEqualTypes(
substituted1.type.unwrap(),
substituted2.type.unwrap()
) || substituted1.projectionKind != substituted2.projectionKind
}
}
fun TypeSubstitutor.combineIfNoConflicts(other: TypeSubstitutor, freeParameters: Collection<TypeParameterDescriptor>): TypeSubstitutor? {
if (this.substitution.hasConflictWith(other.substitution, freeParameters)) return null
return TypeSubstitutor.createChainedSubstitutor(this.substitution, other.substitution)
}

View File

@@ -1,108 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.util
import org.jetbrains.kotlin.descriptors.annotations.BuiltInAnnotationDescriptor
import org.jetbrains.kotlin.renderer.AnnotationArgumentsRenderingPolicy
import org.jetbrains.kotlin.renderer.ClassifierNamePolicy
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.renderer.DescriptorRenderer.Companion.FQ_NAMES_IN_TYPES
import org.jetbrains.kotlin.renderer.DescriptorRendererModifier
import org.jetbrains.kotlin.renderer.OverrideRenderingPolicy
import org.jetbrains.kotlin.resolve.calls.inference.isCaptured
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.NewCapturedTypeConstructor
import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.types.typeUtil.builtIns
object IdeDescriptorRenderers {
@JvmField
val APPROXIMATE_FLEXIBLE_TYPES: (KotlinType) -> KotlinType = { it.approximateFlexibleTypes(preferNotNull = false) }
@JvmField
val APPROXIMATE_FLEXIBLE_TYPES_NOT_NULL: (KotlinType) -> KotlinType = { it.approximateFlexibleTypes(preferNotNull = true) }
private fun unwrapAnonymousType(type: KotlinType): KotlinType {
if (type.isDynamic()) return type
if (type.constructor is NewCapturedTypeConstructor) return type
val classifier = type.constructor.declarationDescriptor
if (classifier != null && !classifier.name.isSpecial) return type
type.constructor.supertypes.singleOrNull()?.let { return it }
val builtIns = type.builtIns
return if (type.isMarkedNullable)
builtIns.nullableAnyType
else
builtIns.anyType
}
private val BASE: DescriptorRenderer = DescriptorRenderer.withOptions {
normalizedVisibilities = true
withDefinedIn = false
renderDefaultVisibility = false
overrideRenderingPolicy = OverrideRenderingPolicy.RENDER_OVERRIDE
unitReturnType = false
enhancedTypes = true
modifiers = DescriptorRendererModifier.ALL
renderUnabbreviatedType = false
annotationArgumentsRenderingPolicy = AnnotationArgumentsRenderingPolicy.UNLESS_EMPTY
}
@JvmField
val SOURCE_CODE: DescriptorRenderer = BASE.withOptions {
classifierNamePolicy = ClassifierNamePolicy.SOURCE_CODE_QUALIFIED
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) }
}
@JvmField
val FQ_NAMES_IN_TYPES_WITH_NORMALIZER: DescriptorRenderer = FQ_NAMES_IN_TYPES.withOptions {
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) }
}
@JvmField
val SOURCE_CODE_TYPES: DescriptorRenderer = BASE.withOptions {
classifierNamePolicy = ClassifierNamePolicy.SOURCE_CODE_QUALIFIED
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) }
annotationFilter = { it !is BuiltInAnnotationDescriptor }
parameterNamesInFunctionalTypes = false
}
@JvmField
val SOURCE_CODE_TYPES_WITH_SHORT_NAMES: DescriptorRenderer = BASE.withOptions {
classifierNamePolicy = ClassifierNamePolicy.SHORT
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) }
modifiers -= DescriptorRendererModifier.ANNOTATIONS
parameterNamesInFunctionalTypes = false
}
@JvmField
val SOURCE_CODE_NOT_NULL_TYPE_APPROXIMATION: DescriptorRenderer = BASE.withOptions {
classifierNamePolicy = ClassifierNamePolicy.SOURCE_CODE_QUALIFIED
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES_NOT_NULL(unwrapAnonymousType(it)) }
presentableUnresolvedTypes = true
informativeErrorType = false
}
@JvmField
val SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS: DescriptorRenderer = BASE.withOptions {
classifierNamePolicy = ClassifierNamePolicy.SHORT
typeNormalizer = { APPROXIMATE_FLEXIBLE_TYPES(unwrapAnonymousType(it)) }
modifiers -= DescriptorRendererModifier.ANNOTATIONS
}
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright 2010-2019 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.idea.util
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.ImportPath
import java.util.*
abstract class ImportInsertHelper {
/*TODO: implementation is not quite correct*/
abstract fun isImportedWithDefault(importPath: ImportPath, contextFile: KtFile): Boolean
abstract fun isImportedWithLowPriorityDefaultImport(importPath: ImportPath, contextFile: KtFile): Boolean
abstract fun mayImportOnShortenReferences(descriptor: DeclarationDescriptor): Boolean
abstract val importSortComparator: Comparator<ImportPath>
abstract fun importDescriptor(
file: KtFile,
descriptor: DeclarationDescriptor,
actionRunningMode: ActionRunningMode = ActionRunningMode.RUN_IN_CURRENT_THREAD,
forceAllUnderImport: Boolean = false
): ImportDescriptorResult
fun importDescriptor(
file: KtFile,
descriptor: DeclarationDescriptor,
forceAllUnderImport: Boolean = false
): ImportDescriptorResult = importDescriptor(
file,
descriptor,
ActionRunningMode.RUN_IN_CURRENT_THREAD,
forceAllUnderImport
)
companion object {
@JvmStatic
fun getInstance(project: Project): ImportInsertHelper =
ServiceManager.getService<ImportInsertHelper>(project, ImportInsertHelper::class.java)
}
}
enum class ImportDescriptorResult {
FAIL,
IMPORT_ADDED,
ALREADY_IMPORTED
}

View File

@@ -1,79 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:JvmName("ImportsUtils")
package org.jetbrains.kotlin.idea.imports
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType
val DeclarationDescriptor.importableFqName: FqName?
get() {
if (!canBeReferencedViaImport()) return null
return getImportableDescriptor().fqNameSafe
}
fun DeclarationDescriptor.canBeReferencedViaImport(): Boolean {
if (this is PackageViewDescriptor ||
DescriptorUtils.isTopLevelDeclaration(this) ||
this is CallableDescriptor && DescriptorUtils.isStaticDeclaration(this)
) {
return !name.isSpecial
}
//Both TypeAliasDescriptor and ClassDescriptor
val parentClassifier = containingDeclaration as? ClassifierDescriptorWithTypeParameters ?: return false
if (!parentClassifier.canBeReferencedViaImport()) return false
return when (this) {
is ConstructorDescriptor -> !parentClassifier.isInner // inner class constructors can't be referenced via import
is ClassDescriptor, is TypeAliasDescriptor -> true
else -> parentClassifier is ClassDescriptor && parentClassifier.kind == ClassKind.OBJECT
}
}
fun DeclarationDescriptor.canBeAddedToImport(): Boolean = this !is PackageViewDescriptor && canBeReferencedViaImport()
fun KotlinType.canBeReferencedViaImport(): Boolean {
val descriptor = constructor.declarationDescriptor
return descriptor != null && descriptor.canBeReferencedViaImport()
}
// for cases when class qualifier refers companion object treats it like reference to class itself
fun KtReferenceExpression.getImportableTargets(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
val targets = bindingContext[BindingContext.SHORT_REFERENCE_TO_COMPANION_OBJECT, this]?.let { listOf(it) }
?: getReferenceTargets(bindingContext)
return targets.map { it.getImportableDescriptor() }.toSet()
}
fun KtImportDirective.canResolve(facade: ResolutionFacade): Boolean {
return (importedReference?.getQualifiedElementSelector() as? KtSimpleNameExpression)?.let { nameExpression ->
nameExpression.getImportableTargets(facade.analyze(nameExpression, BodyResolveMode.PARTIAL)).isNotEmpty()
} ?: false
}

View File

@@ -1,21 +0,0 @@
/*
* Copyright 2010-2019 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.idea.util
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
fun FunctionDescriptor.shouldNotConvertToProperty(notProperties: Set<FqNameUnsafe>): Boolean {
if (fqNameUnsafe in notProperties) return true
return this.overriddenTreeUniqueAsSequence(false).any { fqNameUnsafe in notProperties }
}
fun SyntheticJavaPropertyDescriptor.suppressedByNotPropertyList(set: Set<FqNameUnsafe>) =
getMethod.shouldNotConvertToProperty(set) || setMethod?.shouldNotConvertToProperty(set) ?: false

View File

@@ -1,256 +0,0 @@
/*
* Copyright 2010-2019 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.idea.util
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.resolve.getDataFlowValueFactory
import org.jetbrains.kotlin.idea.resolve.getLanguageVersionSettings
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.scopes.ExplicitImportsScope
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.resolve.scopes.utils.addImportingScope
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.util.descriptorsEqualWithSubstitution
import java.util.*
class ShadowedDeclarationsFilter(
private val bindingContext: BindingContext,
private val resolutionFacade: ResolutionFacade,
private val context: PsiElement,
private val explicitReceiverValue: ReceiverValue?
) {
companion object {
fun create(
bindingContext: BindingContext,
resolutionFacade: ResolutionFacade,
context: PsiElement,
callTypeAndReceiver: CallTypeAndReceiver<*, *>
): ShadowedDeclarationsFilter? {
val receiverExpression = when (callTypeAndReceiver) {
is CallTypeAndReceiver.DEFAULT -> null
is CallTypeAndReceiver.DOT -> callTypeAndReceiver.receiver
is CallTypeAndReceiver.SAFE -> callTypeAndReceiver.receiver
is CallTypeAndReceiver.SUPER_MEMBERS -> callTypeAndReceiver.receiver
is CallTypeAndReceiver.INFIX -> callTypeAndReceiver.receiver
is CallTypeAndReceiver.TYPE, is CallTypeAndReceiver.ANNOTATION -> null // need filtering of classes with the same FQ-name
else -> return null // TODO: support shadowed declarations filtering for callable references
}
val explicitReceiverValue = receiverExpression?.let {
val type = bindingContext.getType(it) ?: return null
ExpressionReceiver.create(it, type, bindingContext)
}
return ShadowedDeclarationsFilter(bindingContext, resolutionFacade, context, explicitReceiverValue)
}
}
private val psiFactory = KtPsiFactory(resolutionFacade.project)
private val dummyExpressionFactory = DummyExpressionFactory(psiFactory)
fun <TDescriptor : DeclarationDescriptor> filter(declarations: Collection<TDescriptor>): Collection<TDescriptor> =
declarations.groupBy { signature(it) }.values.flatMap { group -> filterEqualSignatureGroup(group) }
fun <TDescriptor : DeclarationDescriptor> createNonImportedDeclarationsFilter(
importedDeclarations: Collection<DeclarationDescriptor>
): (Collection<TDescriptor>) -> Collection<TDescriptor> {
val importedDeclarationsSet = importedDeclarations.toSet()
val importedDeclarationsBySignature = importedDeclarationsSet.groupBy { signature(it) }
return filter@{ declarations ->
// optimization
if (declarations.size == 1 && importedDeclarationsBySignature[signature(declarations.single())] == null) return@filter declarations
val nonImportedDeclarations = declarations.filter { it !in importedDeclarationsSet }
val notShadowed = HashSet<DeclarationDescriptor>()
// same signature non-imported declarations from different packages do not shadow each other
for ((pair, group) in nonImportedDeclarations.groupBy { signature(it) to packageName(it) }) {
val imported = importedDeclarationsBySignature[pair.first]
val all = if (imported != null) group + imported else group
notShadowed.addAll(filterEqualSignatureGroup(all, descriptorsToImport = group))
}
declarations.filter { it in notShadowed }
}
}
private fun signature(descriptor: DeclarationDescriptor): Any = when (descriptor) {
is SimpleFunctionDescriptor -> FunctionSignature(descriptor)
is VariableDescriptor -> descriptor.name
is ClassDescriptor -> descriptor.importableFqName ?: descriptor
else -> descriptor
}
private fun packageName(descriptor: DeclarationDescriptor) = descriptor.importableFqName?.parent()
private fun <TDescriptor : DeclarationDescriptor> filterEqualSignatureGroup(
descriptors: Collection<TDescriptor>,
descriptorsToImport: Collection<TDescriptor> = emptyList()
): Collection<TDescriptor> {
if (descriptors.size == 1) return descriptors
val first = descriptors.firstOrNull {
it is ClassDescriptor || it is ConstructorDescriptor || it is CallableDescriptor && !it.name.isSpecial
} ?: return descriptors
if (first is ClassDescriptor) { // for classes with the same FQ-name we simply take the first one
return listOf(first)
}
val isFunction = first is FunctionDescriptor
val name = when (first) {
is ConstructorDescriptor -> first.constructedClass.name
else -> first.name
}
val parameters = (first as CallableDescriptor).valueParameters
val dummyArgumentExpressions = dummyExpressionFactory.createDummyExpressions(parameters.size)
val bindingTrace = DelegatingBindingTrace(bindingContext, "Temporary trace for filtering shadowed declarations")
for ((expression, parameter) in dummyArgumentExpressions.zip(parameters)) {
bindingTrace.recordType(expression, parameter.varargElementType ?: parameter.type)
bindingTrace.record(BindingContext.PROCESSED, expression, true)
}
val firstVarargIndex = parameters.withIndex().firstOrNull { it.value.varargElementType != null }?.index
val useNamedFromIndex =
if (firstVarargIndex != null && firstVarargIndex != parameters.lastIndex) firstVarargIndex else parameters.size
class DummyArgument(val index: Int) : ValueArgument {
private val expression = dummyArgumentExpressions[index]
private val argumentName: ValueArgumentName? = if (isNamed()) {
object : ValueArgumentName {
override val asName = parameters[index].name
override val referenceExpression = null
}
} else {
null
}
override fun getArgumentExpression() = expression
override fun isNamed() = index >= useNamedFromIndex
override fun getArgumentName() = argumentName
override fun asElement() = expression
override fun getSpreadElement() = null
override fun isExternal() = false
}
val arguments = ArrayList<DummyArgument>()
for (i in parameters.indices) {
arguments.add(DummyArgument(i))
}
val newCall = object : Call {
//TODO: compiler crash (KT-8011)
//val arguments = parameters.indices.map { DummyArgument(it) }
val callee = psiFactory.createExpressionByPattern("$0", name, reformat = false)
override fun getCalleeExpression() = callee
override fun getValueArgumentList() = null
override fun getValueArguments() = arguments
override fun getFunctionLiteralArguments() = emptyList<LambdaArgument>()
override fun getTypeArguments() = emptyList<KtTypeProjection>()
override fun getTypeArgumentList() = null
override fun getDispatchReceiver() = null
override fun getCallOperationNode() = null
override fun getExplicitReceiver() = explicitReceiverValue
override fun getCallElement() = callee
override fun getCallType() = Call.CallType.DEFAULT
}
var scope = context.getResolutionScope(bindingContext, resolutionFacade)
if (descriptorsToImport.isNotEmpty()) {
scope = scope.addImportingScope(ExplicitImportsScope(descriptorsToImport))
}
val dataFlowInfo = bindingContext.getDataFlowInfoBefore(context)
val context = BasicCallResolutionContext.create(
bindingTrace, scope, newCall, TypeUtils.NO_EXPECTED_TYPE, dataFlowInfo,
ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
false, resolutionFacade.getLanguageVersionSettings(),
resolutionFacade.getDataFlowValueFactory()
)
@OptIn(FrontendInternals::class)
val callResolver = resolutionFacade.frontendService<CallResolver>()
val results = if (isFunction) callResolver.resolveFunctionCall(context) else callResolver.resolveSimpleProperty(context)
val resultingDescriptors = results.resultingCalls.map { it.resultingDescriptor }
val resultingOriginals = resultingDescriptors.mapTo(HashSet<DeclarationDescriptor>()) { it.original }
val filtered = descriptors.filter { candidateDescriptor ->
candidateDescriptor.original in resultingOriginals /* optimization */ && resultingDescriptors.any {
descriptorsEqualWithSubstitution(
it,
candidateDescriptor
)
}
}
return if (filtered.isNotEmpty()) filtered else descriptors /* something went wrong, none of our declarations among resolve candidates, let's not filter anything */
}
private class DummyExpressionFactory(val factory: KtPsiFactory) {
private val expressions = ArrayList<KtExpression>()
fun createDummyExpressions(count: Int): List<KtExpression> {
while (expressions.size < count) {
expressions.add(factory.createExpression("dummy"))
}
return expressions.take(count)
}
}
private class FunctionSignature(val function: FunctionDescriptor) {
override fun equals(other: Any?): Boolean {
if (other === this) return true
if (other !is FunctionSignature) return false
if (function.name != other.function.name) return false
val parameters1 = function.valueParameters
val parameters2 = other.function.valueParameters
if (parameters1.size != parameters2.size) return false
for (i in parameters1.indices) {
val p1 = parameters1[i]
val p2 = parameters2[i]
if (p1.varargElementType != p2.varargElementType) return false // both should be vararg or or both not
if (p1.type != p2.type) return false
}
val typeParameters1 = function.typeParameters
val typeParameters2 = other.function.typeParameters
if (typeParameters1.size != typeParameters2.size) return false
for (i in typeParameters1.indices) {
val t1 = typeParameters1[i]
val t2 = typeParameters2[i]
if (t1.upperBounds != t2.upperBounds) return false
}
return true
}
override fun hashCode() = function.name.hashCode() * 17 + function.valueParameters.size
}
}

View File

@@ -1,261 +0,0 @@
/*
* Copyright 2010-2019 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:JvmName("TypeUtils")
package org.jetbrains.kotlin.idea.util
import com.intellij.psi.*
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMapper
import org.jetbrains.kotlin.builtins.replaceReturnType
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.MutablePackageFragmentDescriptor
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.components.TypeUsage
import org.jetbrains.kotlin.load.java.lazy.JavaResolverComponents
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.TypeParameterResolver
import org.jetbrains.kotlin.load.java.lazy.child
import org.jetbrains.kotlin.load.java.lazy.descriptors.LazyJavaTypeParameterDescriptor
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeAttributes
import org.jetbrains.kotlin.load.java.lazy.types.JavaTypeResolver
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeImpl
import org.jetbrains.kotlin.load.java.structure.impl.JavaTypeParameterImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.*
import org.jetbrains.kotlin.utils.SmartSet
fun KotlinType.approximateFlexibleTypes(
preferNotNull: Boolean = false,
preferStarForRaw: Boolean = false
): KotlinType {
if (isDynamic()) return this
return unwrapEnhancement().approximateNonDynamicFlexibleTypes(preferNotNull, preferStarForRaw)
}
private fun KotlinType.approximateNonDynamicFlexibleTypes(
preferNotNull: Boolean = false,
preferStarForRaw: Boolean = false
): SimpleType {
if (this is ErrorType) return this
if (isFlexible()) {
val flexible = asFlexibleType()
val lowerClass = flexible.lowerBound.constructor.declarationDescriptor as? ClassDescriptor?
val isCollection = lowerClass != null && JavaToKotlinClassMapper.isMutable(lowerClass)
// (Mutable)Collection<T>! -> MutableCollection<T>?
// Foo<(Mutable)Collection<T>!>! -> Foo<Collection<T>>?
// Foo! -> Foo?
// Foo<Bar!>! -> Foo<Bar>?
var approximation =
if (isCollection)
flexible.lowerBound.makeNullableAsSpecified(!preferNotNull)
else
if (this is RawType && preferStarForRaw) flexible.upperBound.makeNullableAsSpecified(!preferNotNull)
else
if (preferNotNull) flexible.lowerBound else flexible.upperBound
approximation = approximation.approximateNonDynamicFlexibleTypes()
approximation = if (nullability() == TypeNullability.NOT_NULL) approximation.makeNullableAsSpecified(false) else approximation
if (approximation.isMarkedNullable && !flexible.lowerBound
.isMarkedNullable && TypeUtils.isTypeParameter(approximation) && TypeUtils.hasNullableSuperType(approximation)
) {
approximation = approximation.makeNullableAsSpecified(false)
}
return approximation
}
(unwrap() as? AbbreviatedType)?.let {
return AbbreviatedType(it.expandedType, it.abbreviation.approximateNonDynamicFlexibleTypes(preferNotNull))
}
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
annotations,
constructor,
arguments.map { it.substitute { type -> type.approximateFlexibleTypes(preferNotNull = true) } },
isMarkedNullable,
ErrorUtils.createErrorScope("This type is not supposed to be used in member resolution", true)
)
}
fun KotlinType.isResolvableInScope(scope: LexicalScope?, checkTypeParameters: Boolean, allowIntersections: Boolean = false): Boolean {
if (constructor is IntersectionTypeConstructor) {
if (!allowIntersections) return false
return constructor.supertypes.all { it.isResolvableInScope(scope, checkTypeParameters, allowIntersections) }
}
if (canBeReferencedViaImport()) return true
val descriptor = constructor.declarationDescriptor
if (descriptor == null || descriptor.name.isSpecial) return false
if (!checkTypeParameters && descriptor is TypeParameterDescriptor) return true
return scope != null && scope.findClassifier(descriptor.name, NoLookupLocation.FROM_IDE) == descriptor
}
fun KotlinType.approximateWithResolvableType(scope: LexicalScope?, checkTypeParameters: Boolean): KotlinType {
if (isError || isResolvableInScope(scope, checkTypeParameters)) return this
return supertypes().firstOrNull { it.isResolvableInScope(scope, checkTypeParameters) }
?: builtIns.anyType
}
fun KotlinType.anonymousObjectSuperTypeOrNull(): KotlinType? {
val classDescriptor = constructor.declarationDescriptor
if (classDescriptor != null && DescriptorUtils.isAnonymousObject(classDescriptor)) {
return immediateSupertypes().firstOrNull() ?: classDescriptor.builtIns.anyType
}
return null
}
fun KotlinType.getResolvableApproximations(
scope: LexicalScope?,
checkTypeParameters: Boolean,
allowIntersections: Boolean = false
): Sequence<KotlinType> {
return (listOf(this) + TypeUtils.getAllSupertypes(this))
.asSequence()
.mapNotNull {
it.asTypeProjection()
.fixTypeProjection(scope, checkTypeParameters, allowIntersections, isOutVariance = true)
?.type
}
}
private fun TypeProjection.fixTypeProjection(
scope: LexicalScope?,
checkTypeParameters: Boolean,
allowIntersections: Boolean,
isOutVariance: Boolean
): TypeProjection? {
if (!type.isResolvableInScope(scope, checkTypeParameters, allowIntersections)) return null
if (type.arguments.isEmpty()) return this
val resolvableArgs = type.arguments.filterTo(SmartSet.create()) { typeProjection ->
typeProjection.type.isResolvableInScope(scope, checkTypeParameters, allowIntersections)
}
if (resolvableArgs.containsAll(type.arguments)) {
fun fixArguments(type: KotlinType): KotlinType? = type.replace(
(type.arguments zip type.constructor.parameters).map { (arg, param) ->
if (arg.isStarProjection) arg
else arg.fixTypeProjection(
scope,
checkTypeParameters,
allowIntersections,
isOutVariance = isOutVariance && param.variance == Variance.OUT_VARIANCE
) ?: when {
!isOutVariance -> return null
param.variance == Variance.OUT_VARIANCE -> arg.type.approximateWithResolvableType(
scope,
checkTypeParameters
).asTypeProjection()
else -> type.replaceArgumentsWithStarProjections().arguments.first()
}
})
return if (type.isBuiltinFunctionalType) {
val returnType = type.getReturnTypeFromFunctionType()
type.replaceReturnType(fixArguments(returnType) ?: return null).asTypeProjection()
} else fixArguments(type)?.asTypeProjection()
}
if (!isOutVariance) return null
val newArguments = (type.arguments zip type.constructor.parameters).map { (arg, param) ->
when {
arg in resolvableArgs -> arg
arg.projectionKind == Variance.OUT_VARIANCE ||
param.variance == Variance.OUT_VARIANCE -> TypeProjectionImpl(
arg.projectionKind,
arg.type.approximateWithResolvableType(scope, checkTypeParameters)
)
else -> return if (isOutVariance) type.replaceArgumentsWithStarProjections().asTypeProjection() else null
}
}
return type.replace(newArguments).asTypeProjection()
}
fun KotlinType.isAbstract(): Boolean {
val modality = (constructor.declarationDescriptor as? ClassDescriptor)?.modality
return modality == Modality.ABSTRACT || modality == Modality.SEALED
}
/**
* NOTE: this is a very shaky implementation of [PsiType] to [KotlinType] conversion,
* produced types are fakes and are usable only for code generation. Please be careful using this method.
*/
@OptIn(FrontendInternals::class)
fun PsiType.resolveToKotlinType(resolutionFacade: ResolutionFacade): KotlinType {
if (this == PsiType.NULL) {
return resolutionFacade.moduleDescriptor.builtIns.nullableAnyType
}
val typeParameters = collectTypeParameters()
val components = resolutionFacade.getFrontendService(JavaResolverComponents::class.java)
val rootContext = LazyJavaResolverContext(components, TypeParameterResolver.EMPTY) { null }
val dummyPackageDescriptor = MutablePackageFragmentDescriptor(resolutionFacade.moduleDescriptor, FqName("dummy"))
val dummyClassDescriptor = ClassDescriptorImpl(
dummyPackageDescriptor,
Name.identifier("Dummy"),
Modality.FINAL,
ClassKind.CLASS,
emptyList(),
SourceElement.NO_SOURCE,
false,
LockBasedStorageManager.NO_LOCKS
)
val typeParameterResolver = object : TypeParameterResolver {
override fun resolveTypeParameter(javaTypeParameter: JavaTypeParameter): TypeParameterDescriptor? {
val psiTypeParameter = (javaTypeParameter as JavaTypeParameterImpl).psi
val index = typeParameters.indexOf(psiTypeParameter)
if (index < 0) return null
return LazyJavaTypeParameterDescriptor(rootContext.child(this), javaTypeParameter, index, dummyClassDescriptor)
}
}
val typeResolver = JavaTypeResolver(rootContext, typeParameterResolver)
val attributes = JavaTypeAttributes(TypeUsage.COMMON)
return typeResolver.transformJavaType(JavaTypeImpl.create(this), attributes).approximateFlexibleTypes(preferNotNull = true)
}
private fun PsiType.collectTypeParameters(): List<PsiTypeParameter> {
val results = ArrayList<PsiTypeParameter>()
accept(
object : PsiTypeVisitor<Unit>() {
override fun visitArrayType(arrayType: PsiArrayType) {
arrayType.componentType.accept(this)
}
override fun visitClassType(classType: PsiClassType) {
(classType.resolve() as? PsiTypeParameter)?.let { results += it }
classType.parameters.forEach { it.accept(this) }
}
override fun visitWildcardType(wildcardType: PsiWildcardType) {
wildcardType.bound?.accept(this)
}
}
)
return results
}

View File

@@ -1,89 +0,0 @@
/*
* Copyright 2010-2019 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.idea.util
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.FlexibleType
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
fun KtFunctionLiteral.findLabelAndCall(): Pair<Name?, KtCallExpression?> {
val literalParent = (this.parent as KtLambdaExpression).parent
fun KtValueArgument.callExpression(): KtCallExpression? {
val parent = parent
return (if (parent is KtValueArgumentList) parent else this).parent as? KtCallExpression
}
when (literalParent) {
is KtLabeledExpression -> {
val callExpression = (literalParent.parent as? KtValueArgument)?.callExpression()
return Pair(literalParent.getLabelNameAsName(), callExpression)
}
is KtValueArgument -> {
val callExpression = literalParent.callExpression()
val label = (callExpression?.calleeExpression as? KtSimpleNameExpression)?.getReferencedNameAsName()
return Pair(label, callExpression)
}
else -> {
return Pair(null, null)
}
}
}
fun SmartCastManager.getSmartCastVariantsWithLessSpecificExcluded(
receiverToCast: ReceiverValue,
bindingContext: BindingContext,
containingDeclarationOrModule: DeclarationDescriptor,
dataFlowInfo: DataFlowInfo,
languageVersionSettings: LanguageVersionSettings,
dataFlowValueFactory: DataFlowValueFactory
): List<KotlinType> {
val variants = getSmartCastVariants(
receiverToCast,
bindingContext,
containingDeclarationOrModule,
dataFlowInfo,
languageVersionSettings,
dataFlowValueFactory
)
return variants.filter { type ->
variants.all { another -> another === type || chooseMoreSpecific(type, another).let { it == null || it === type } }
}
}
private fun chooseMoreSpecific(type1: KotlinType, type2: KotlinType): KotlinType? {
val type1IsSubtype = KotlinTypeChecker.DEFAULT.isSubtypeOf(type1, type2)
val type2IsSubtype = KotlinTypeChecker.DEFAULT.isSubtypeOf(type2, type1)
when {
type1IsSubtype && !type2IsSubtype -> return type1
type2IsSubtype && !type1IsSubtype -> return type2
!type1IsSubtype && !type2IsSubtype -> return null
else -> { // type1IsSubtype && type2IsSubtype
val flexible1 = type1.unwrap() as? FlexibleType
val flexible2 = type2.unwrap() as? FlexibleType
return when {
flexible1 != null && flexible2 == null -> type2
flexible2 != null && flexible1 == null -> type1
else -> null //TODO?
}
}
}
}

View File

@@ -1,16 +0,0 @@
/*
* Copyright 2010-2018 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:JvmName("CidrUtil")
package org.jetbrains.kotlin.idea.util
import com.intellij.util.PlatformUtils
// Currently CIDR IDEs (CLion and AppCode) have no Java support.
// Use this property to bypass Java-specific logic in CIDR.
val isRunningInCidrIde: Boolean by lazy(LazyThreadSafetyMode.PUBLICATION) {
PlatformUtils.isCidr()
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright 2010-2019 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:JvmName("ExtensionUtils")
package org.jetbrains.kotlin.idea.util
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.psi.KtThisExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ImplicitReceiver
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.TypeNullability
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.types.typeUtil.nullability
fun <TCallable : CallableDescriptor> TCallable.substituteExtensionIfCallable(
receiverTypes: Collection<KotlinType>,
callType: CallType<*>
): Collection<TCallable> {
if (!callType.descriptorKindFilter.accepts(this)) return listOf()
var types = receiverTypes.asSequence()
if (callType == CallType.SAFE) {
types = types.map { it.makeNotNullable() }
}
val extensionReceiverType = fuzzyExtensionReceiverType()!!
val substitutors = types.mapNotNull {
var substitutor = extensionReceiverType.checkIsSuperTypeOf(it)
// check if we may fail due to receiver expression being nullable
if (substitutor == null && it.nullability() == TypeNullability.NULLABLE && extensionReceiverType.nullability() == TypeNullability.NOT_NULL) {
substitutor = extensionReceiverType.checkIsSuperTypeOf(it.makeNotNullable())
}
substitutor
}
return if (typeParameters.isEmpty()) { // optimization for non-generic callables
if (substitutors.any()) listOf(this) else listOf()
} else {
substitutors
.mapNotNull { @Suppress("UNCHECKED_CAST") (substitute(it) as TCallable?) }
.toList()
}
}
fun ReceiverValue?.getThisReceiverOwner(bindingContext: BindingContext): DeclarationDescriptor? {
return when (this) {
is ExpressionReceiver -> {
val thisRef = (KtPsiUtil.deparenthesize(this.expression) as? KtThisExpression)?.instanceReference ?: return null
bindingContext[BindingContext.REFERENCE_TARGET, thisRef]
}
is ImplicitReceiver -> this.declarationDescriptor
else -> null
}
}
fun ReceiverValue?.getReceiverTargetDescriptor(bindingContext: BindingContext): DeclarationDescriptor? = when (this) {
is ExpressionReceiver -> when (val expression = KtPsiUtil.deparenthesize(this.expression)) {
is KtThisExpression -> expression.instanceReference
is KtReferenceExpression -> expression
else -> null
}?.let { referenceExpression ->
bindingContext[BindingContext.REFERENCE_TARGET, referenceExpression]
}
is ImplicitReceiver -> this.declarationDescriptor
else -> null
}

View File

@@ -1,121 +0,0 @@
/*
* Copyright 2010-2019 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.idea.util
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.DslMarkerUtils
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.typeUtil.isSubtypeOf
import java.util.*
import kotlin.collections.LinkedHashSet
fun LexicalScope.getImplicitReceiversWithInstance(excludeShadowedByDslMarkers: Boolean = false): Collection<ReceiverParameterDescriptor> =
getImplicitReceiversWithInstanceToExpression(excludeShadowedByDslMarkers).keys
interface ReceiverExpressionFactory {
val isImmediate: Boolean
val expressionText: String
fun createExpression(psiFactory: KtPsiFactory, shortThis: Boolean = true): KtExpression
}
fun LexicalScope.getFactoryForImplicitReceiverWithSubtypeOf(receiverType: KotlinType): ReceiverExpressionFactory? =
getImplicitReceiversWithInstanceToExpression().entries.firstOrNull { (receiverDescriptor, _) ->
receiverDescriptor.type.isSubtypeOf(receiverType)
}?.value
fun LexicalScope.getImplicitReceiversWithInstanceToExpression(
excludeShadowedByDslMarkers: Boolean = false
): Map<ReceiverParameterDescriptor, ReceiverExpressionFactory?> {
val allReceivers = getImplicitReceiversHierarchy()
// we use a set to workaround a bug with receiver for companion object present twice in the result of getImplicitReceiversHierarchy()
val receivers = LinkedHashSet(
if (excludeShadowedByDslMarkers) {
allReceivers - allReceivers.shadowedByDslMarkers()
} else {
allReceivers
}
)
val outerDeclarationsWithInstance = LinkedHashSet<DeclarationDescriptor>()
var current: DeclarationDescriptor? = ownerDescriptor
while (current != null) {
if (current is PropertyAccessorDescriptor) {
current = current.correspondingProperty
}
outerDeclarationsWithInstance.add(current)
val classDescriptor = current as? ClassDescriptor
if (classDescriptor != null && !classDescriptor.isInner && !DescriptorUtils.isLocal(classDescriptor)) break
current = current.containingDeclaration
}
val result = LinkedHashMap<ReceiverParameterDescriptor, ReceiverExpressionFactory?>()
for ((index, receiver) in receivers.withIndex()) {
val owner = receiver.containingDeclaration
if (owner is ScriptDescriptor) {
result[receiver] = null
outerDeclarationsWithInstance.addAll(owner.implicitReceivers)
continue
}
val (expressionText, isImmediateThis) = if (owner in outerDeclarationsWithInstance) {
val thisWithLabel = thisQualifierName(receiver)?.let { "this@${it.render()}" }
if (index == 0)
(thisWithLabel ?: "this") to true
else
thisWithLabel to false
} else if (owner is ClassDescriptor && owner.kind.isSingleton) {
IdeDescriptorRenderers.SOURCE_CODE.renderClassifierName(owner) to false
} else {
continue
}
val factory = if (expressionText != null)
object : ReceiverExpressionFactory {
override val isImmediate = isImmediateThis
override val expressionText: String get() = expressionText
override fun createExpression(psiFactory: KtPsiFactory, shortThis: Boolean): KtExpression {
return psiFactory.createExpression(if (shortThis && isImmediateThis) "this" else expressionText)
}
}
else
null
result[receiver] = factory
}
return result
}
private fun thisQualifierName(receiver: ReceiverParameterDescriptor): Name? {
val descriptor = receiver.containingDeclaration
val name = descriptor.name
if (!name.isSpecial) return name
val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtFunctionLiteral
return functionLiteral?.findLabelAndCall()?.first
}
private fun List<ReceiverParameterDescriptor>.shadowedByDslMarkers(): Set<ReceiverParameterDescriptor> {
val typesByDslScopes = mutableMapOf<FqName, MutableList<ReceiverParameterDescriptor>>()
for (receiver in this) {
val dslMarkers = DslMarkerUtils.extractDslMarkerFqNames(receiver.value).all()
for (marker in dslMarkers) {
typesByDslScopes.getOrPut(marker) { mutableListOf() } += receiver
}
}
// for each DSL marker, all receivers except the closest one are shadowed by it; that is why we drop it
return typesByDslScopes.values.flatMapTo(mutableSetOf()) { it.drop(1) }
}

View File

@@ -1,87 +0,0 @@
/*
* Copyright 2010-2019 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.idea.util.psi.patternMatching
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtTreeVisitorVoid
import org.jetbrains.kotlin.psi.psiUtil.siblings
import java.util.*
private val SIGNIFICANT_FILTER = { e: PsiElement -> e !is PsiWhiteSpace && e !is PsiComment && e.textLength > 0 }
interface KotlinPsiRange {
object Empty : KotlinPsiRange {
override val elements: List<PsiElement> get() = Collections.emptyList<PsiElement>()
override fun getTextRange(): TextRange = TextRange.EMPTY_RANGE
}
class ListRange(override val elements: List<PsiElement>) : KotlinPsiRange {
val startElement: PsiElement = elements.first()
val endElement: PsiElement = elements.last()
override fun getTextRange(): TextRange {
val startRange = startElement.textRange
val endRange = endElement.textRange
if (startRange == null || endRange == null) return TextRange.EMPTY_RANGE
return TextRange(startRange.startOffset, endRange.endOffset)
}
}
val elements: List<PsiElement>
fun getTextRange(): TextRange
fun isValid(): Boolean = elements.all { it.isValid }
val empty: Boolean get() = this is Empty
operator fun contains(element: PsiElement): Boolean = getTextRange().contains(element.textRange ?: TextRange.EMPTY_RANGE)
fun match(scope: PsiElement, unifier: KotlinPsiUnifier): List<UnificationResult.Matched> {
val elements = elements.filter(SIGNIFICANT_FILTER)
if (elements.isEmpty()) return Collections.emptyList()
val matches = ArrayList<UnificationResult.Matched>()
scope.accept(
object : KtTreeVisitorVoid() {
override fun visitKtElement(element: KtElement) {
val range = element
.siblings()
.filter(SIGNIFICANT_FILTER)
.take(elements.size)
.toList()
.toRange()
val result = unifier.unify(range, this@KotlinPsiRange)
if (result is UnificationResult.StronglyMatched) {
matches.add(result)
} else {
val matchCountSoFar = matches.size
super.visitKtElement(element)
if (result is UnificationResult.WeaklyMatched && matches.size == matchCountSoFar) {
matches.add(result)
}
}
}
}
)
return matches
}
}
fun List<PsiElement>.toRange(significantOnly: Boolean = true): KotlinPsiRange {
val elements = if (significantOnly) filter(SIGNIFICANT_FILTER) else this
return if (elements.isEmpty()) KotlinPsiRange.Empty else KotlinPsiRange.ListRange(elements)
}
fun PsiElement?.toRange(): KotlinPsiRange = this?.let { KotlinPsiRange.ListRange(Collections.singletonList(it)) } ?: KotlinPsiRange.Empty

View File

@@ -1,92 +0,0 @@
/*
* Copyright 2010-2019 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:JvmName("ScopeUtils")
package org.jetbrains.kotlin.idea.util
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.ClassDescriptorWithResolutionScopes
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassBody
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions
import org.jetbrains.kotlin.resolve.scopes.utils.collectVariables
fun LexicalScope.getAllAccessibleVariables(name: Name): Collection<VariableDescriptor> {
return getVariablesFromImplicitReceivers(name) + collectVariables(name, NoLookupLocation.FROM_IDE)
}
fun LexicalScope.getAllAccessibleFunctions(name: Name): Collection<FunctionDescriptor> {
return getImplicitReceiversWithInstance().flatMap {
it.type.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_IDE)
} + collectFunctions(name, NoLookupLocation.FROM_IDE)
}
fun LexicalScope.getVariablesFromImplicitReceivers(name: Name): Collection<VariableDescriptor> =
getImplicitReceiversWithInstance().flatMap {
it.type.memberScope.getContributedVariables(name, NoLookupLocation.FROM_IDE)
}
fun LexicalScope.getVariableFromImplicitReceivers(name: Name): VariableDescriptor? {
getImplicitReceiversWithInstance().forEach {
it.type.memberScope.getContributedVariables(name, NoLookupLocation.FROM_IDE).singleOrNull()?.let { return it }
}
return null
}
fun PsiElement.getResolutionScope(bindingContext: BindingContext): LexicalScope? {
for (parent in parentsWithSelf) {
if (parent is KtElement) {
val scope = bindingContext[BindingContext.LEXICAL_SCOPE, parent]
if (scope != null) return scope
}
if (parent is KtClassBody) {
val classDescriptor = bindingContext[BindingContext.CLASS, parent.getParent()] as? ClassDescriptorWithResolutionScopes
if (classDescriptor != null) {
return classDescriptor.scopeForMemberDeclarationResolution
}
}
if (parent is KtFile) {
break
}
}
return null
}
fun PsiElement.getResolutionScope(
bindingContext: BindingContext,
resolutionFacade: ResolutionFacade/*TODO: get rid of this parameter*/
): LexicalScope = getResolutionScope(bindingContext) ?: when (containingFile) {
is KtFile -> resolutionFacade.getFileResolutionScope(containingFile as KtFile)
else -> error("Not in KtFile")
}
fun KtElement.getResolutionScope(): LexicalScope {
val resolutionFacade = getResolutionFacade()
val context = resolutionFacade.analyze(this, BodyResolveMode.FULL)
return getResolutionScope(context, resolutionFacade)
}
@OptIn(FrontendInternals::class)
fun ResolutionFacade.getFileResolutionScope(file: KtFile): LexicalScope {
return frontendService<FileScopeProvider>().getFileResolutionScope(file)
}

View File

@@ -1,33 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.lazy
import org.jetbrains.kotlin.resolve.BindingTraceFilter
enum class BodyResolveMode(val bindingTraceFilter: BindingTraceFilter, val doControlFlowAnalysis: Boolean, val resolveAdditionals: Boolean = true) {
// All body statements are analyzed, diagnostics included
FULL(BindingTraceFilter.ACCEPT_ALL, doControlFlowAnalysis = true),
// Analyzes only dependent statements, including all declaration statements (difference from PARTIAL_WITH_CFA)
PARTIAL_FOR_COMPLETION(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = true),
// Analyzes only dependent statements, diagnostics included
PARTIAL_WITH_DIAGNOSTICS(BindingTraceFilter.ACCEPT_ALL, doControlFlowAnalysis = true),
// Analyzes only dependent statements, performs control flow analysis (mostly needed for isUsedAsExpression / AsStatement)
PARTIAL_WITH_CFA(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = true),
// Analyzes only dependent statements, including only used declaration statements, does not perform control flow analysis
PARTIAL(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = false),
// Resolve mode to resolve only the element itself without the additional elements (annotation resolve would not lead to function resolve or default parameters)
PARTIAL_NO_ADDITIONAL(BindingTraceFilter.NO_DIAGNOSTICS, doControlFlowAnalysis = false, resolveAdditionals = false)
;
fun doesNotLessThan(other: BodyResolveMode): Boolean {
return this <= other && this.bindingTraceFilter.includesEverythingIn(other.bindingTraceFilter)
}
}

View File

@@ -1,623 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.lazy
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiRecursiveElementVisitor
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.StatementFilter
import org.jetbrains.kotlin.util.isProbablyNothing
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.swap
import java.util.*
//TODO: do resolve anonymous object's body
class PartialBodyResolveFilter(
elementsToResolve: Collection<KtElement>,
private val declaration: KtDeclaration,
forCompletion: Boolean
) : StatementFilter() {
private val statementMarks = StatementMarks()
private val globalProbablyNothingCallableNames = ProbablyNothingCallableNames.getInstance(declaration.project)
private val globalProbablyContractedCallableNames = ProbablyContractedCallableNames.getInstance(declaration.project)
private val contextNothingFunctionNames = HashSet<String>()
private val contextNothingVariableNames = HashSet<String>()
override val filter: ((KtExpression) -> Boolean)? = { statementMarks.statementMark(it) != MarkLevel.NONE }
val allStatementsToResolve: Collection<KtExpression>
get() = statementMarks.allMarkedStatements()
init {
elementsToResolve.forEach { assert(declaration.isAncestor(it)) }
assert(!KtPsiUtil.isLocal(declaration)) { "Should never be invoked on local declaration otherwise we may miss some local declarations with type Nothing" }
declaration.forEachDescendantOfType<KtCallableDeclaration> { declaration ->
if (declaration.typeReference.containsProbablyNothing()) {
val name = declaration.name
if (name != null) {
if (declaration is KtNamedFunction) {
contextNothingFunctionNames.add(name)
} else {
contextNothingVariableNames.add(name)
}
}
}
}
elementsToResolve.forEach {
statementMarks.mark(it, if (forCompletion) MarkLevel.NEED_COMPLETION else MarkLevel.NEED_REFERENCE_RESOLVE)
}
declaration.forTopLevelBlocksInside { processBlock(it) }
}
//TODO: do..while is special case
private fun processBlock(block: KtBlockExpression): NameFilter {
if (isValueNeeded(block)) {
block.lastStatement()?.let { statementMarks.mark(it, MarkLevel.NEED_REFERENCE_RESOLVE) }
}
val nameFilter = NameFilter()
val startStatement = statementMarks.lastMarkedStatement(block, MarkLevel.NEED_REFERENCE_RESOLVE) ?: return nameFilter
for (statement in startStatement.siblings(forward = false)) {
if (statement !is KtExpression) continue
if (statement is KtNamedDeclaration) {
val name = statement.getName()
if (name != null && nameFilter(name)) {
statementMarks.mark(statement, MarkLevel.NEED_REFERENCE_RESOLVE)
}
} else if (statement is KtDestructuringDeclaration) {
if (statement.entries.any {
val name = it.name
name != null && nameFilter(name)
}) {
statementMarks.mark(statement, MarkLevel.NEED_REFERENCE_RESOLVE)
}
}
fun updateNameFilter() {
when (statementMarks.statementMark(statement)) {
MarkLevel.NONE, MarkLevel.TAKE -> {
}
MarkLevel.NEED_REFERENCE_RESOLVE -> nameFilter.addUsedNames(statement)
MarkLevel.NEED_COMPLETION -> nameFilter.addAllNames()
}
}
updateNameFilter()
if (!nameFilter.isEmpty) {
val smartCastPlaces = potentialSmartCastPlaces(statement, { it.affectsNames(nameFilter) })
if (!smartCastPlaces.isEmpty()) {
//TODO: do we really need correct resolve for ALL smart cast places?
smartCastPlaces.values
.flatten()
.forEach { statementMarks.mark(it, MarkLevel.NEED_REFERENCE_RESOLVE) }
updateNameFilter()
}
}
val level = statementMarks.statementMark(statement)
if (level > MarkLevel.TAKE) { // otherwise there are no statements inside that need processBlock which only works when reference resolve needed
statement.forTopLevelBlocksInside { nestedBlock ->
val childFilter = processBlock(nestedBlock)
nameFilter.addNamesFromFilter(childFilter)
}
}
}
return nameFilter
}
/**
* Finds places within the given statement that may affect smart-casts after it.
* That is, such places whose containing statements must be left in code to keep the smart-casts.
* Returns map from smart-cast expression names (variable name or qualified variable name) to places.
*/
private fun potentialSmartCastPlaces(
statement: KtExpression,
filter: (SmartCastName) -> Boolean = { true }
): Map<SmartCastName, List<KtExpression>> {
val map = HashMap<SmartCastName, ArrayList<KtExpression>>(0)
fun addPlace(name: SmartCastName, place: KtExpression) {
map.getOrPut(name, { ArrayList(1) }).add(place)
}
fun addPlaces(name: SmartCastName, places: Collection<KtExpression>) {
if (places.isNotEmpty()) {
map.getOrPut(name, { ArrayList(places.size) }).addAll(places)
}
}
fun addIfCanBeSmartCast(expression: KtExpression) {
val name = expression.smartCastExpressionName() ?: return
if (filter(name)) {
addPlace(name, expression)
}
}
statement.accept(object : ControlFlowVisitor() {
override fun visitPostfixExpression(expression: KtPostfixExpression) {
expression.acceptChildren(this)
if (expression.operationToken == KtTokens.EXCLEXCL) {
addIfCanBeSmartCast(expression.baseExpression ?: return)
}
}
override fun visitCallExpression(expression: KtCallExpression) {
super.visitCallExpression(expression)
val nameReference = expression.calleeExpression as? KtNameReferenceExpression ?: return
if (!globalProbablyContractedCallableNames.isProbablyContractedCallableName(nameReference.getReferencedName())) return
val mentionedSmartCastName = expression.findMentionedName(filter)
if (mentionedSmartCastName != null) {
addPlace(mentionedSmartCastName, expression)
}
}
override fun visitBinaryWithTypeRHSExpression(expression: KtBinaryExpressionWithTypeRHS) {
expression.acceptChildren(this)
if (expression.operationReference.getReferencedNameElementType() == KtTokens.AS_KEYWORD) {
addIfCanBeSmartCast(expression.left)
}
}
override fun visitBinaryExpression(expression: KtBinaryExpression) {
expression.acceptChildren(this)
if (expression.operationToken == KtTokens.ELVIS) {
val left = expression.left
val right = expression.right
if (left != null && right != null) {
val smartCastName = left.smartCastExpressionName()
if (smartCastName != null && filter(smartCastName)) {
val exits = collectAlwaysExitPoints(right)
addPlaces(smartCastName, exits)
}
}
}
}
override fun visitIfExpression(expression: KtIfExpression) {
val condition = expression.condition
val thenBranch = expression.then
val elseBranch = expression.`else`
val (thenSmartCastNames, elseSmartCastNames) = possiblySmartCastInCondition(condition)
fun processBranchExits(smartCastNames: Collection<SmartCastName>, branch: KtExpression?) {
if (branch == null) return
val filteredNames = smartCastNames.filter(filter)
if (filteredNames.isNotEmpty()) {
val exits = collectAlwaysExitPoints(branch)
if (exits.isNotEmpty()) {
for (name in filteredNames) {
addPlaces(name, exits)
}
}
}
}
processBranchExits(thenSmartCastNames, elseBranch)
processBranchExits(elseSmartCastNames, thenBranch)
condition?.accept(this)
if (thenBranch != null && elseBranch != null) {
val thenCasts = potentialSmartCastPlaces(thenBranch, filter)
if (thenCasts.isNotEmpty()) {
val elseCasts = potentialSmartCastPlaces(elseBranch) { filter(it) && thenCasts.containsKey(it) }
if (elseCasts.isNotEmpty()) {
for ((name, places) in thenCasts) {
if (elseCasts.containsKey(name)) { // need filtering by cast names in else-branch
addPlaces(name, places)
}
}
for ((name, places) in elseCasts) { // already filtered by cast names in then-branch
addPlaces(name, places)
}
}
}
}
}
override fun visitForExpression(expression: KtForExpression) {
// analyze only the loop-range expression, do not enter the loop body
expression.loopRange?.accept(this)
}
override fun visitWhileExpression(expression: KtWhileExpression) {
val condition = expression.condition
// we need to enter the body only for "while(true)"
if (condition.isTrueConstant()) {
expression.acceptChildren(this)
} else {
condition?.accept(this)
}
}
//TODO: when
})
return map
}
private fun KtExpression.findMentionedName(filter: (SmartCastName) -> Boolean): SmartCastName? {
var foundMentionedName: SmartCastName? = null
val visitor = object : PsiRecursiveElementVisitor() {
override fun visitElement(element: PsiElement) {
if (foundMentionedName != null) return
if (element !is KtSimpleNameExpression) super.visitElement(element)
if (element !is KtExpression) return
element.smartCastExpressionName()?.takeIf(filter)?.let { foundMentionedName = it }
}
}
accept(visitor)
return foundMentionedName
}
/**
* Returns names of expressions that would possibly be smart cast
* in then (first component) and else (second component)
* branches of an if-statement with such condition
*/
private fun possiblySmartCastInCondition(condition: KtExpression?): Pair<Set<SmartCastName>, Set<SmartCastName>> {
val emptyResult = Pair(setOf<SmartCastName>(), setOf<SmartCastName>())
when (condition) {
is KtBinaryExpression -> {
val operation = condition.operationToken
val left = condition.left ?: return emptyResult
val right = condition.right ?: return emptyResult
fun smartCastInEq(): Pair<Set<SmartCastName>, Set<SmartCastName>> = when {
left.isNullLiteral() -> {
Pair(setOf(), right.smartCastExpressionName().singletonOrEmptySet())
}
right.isNullLiteral() -> {
Pair(setOf(), left.smartCastExpressionName().singletonOrEmptySet())
}
else -> {
val leftName = left.smartCastExpressionName()
val rightName = right.smartCastExpressionName()
val names = listOfNotNull(leftName, rightName).toSet()
Pair(names, setOf())
}
}
when (operation) {
KtTokens.EQEQ, KtTokens.EQEQEQ -> return smartCastInEq()
KtTokens.EXCLEQ, KtTokens.EXCLEQEQEQ -> return smartCastInEq().swap()
KtTokens.ANDAND -> {
val casts1 = possiblySmartCastInCondition(left)
val casts2 = possiblySmartCastInCondition(right)
return Pair(casts1.first.union(casts2.first), casts1.second.intersect(casts2.second))
}
KtTokens.OROR -> {
val casts1 = possiblySmartCastInCondition(left)
val casts2 = possiblySmartCastInCondition(right)
return Pair(casts1.first.intersect(casts2.first), casts1.second.union(casts2.second))
}
}
}
is KtIsExpression -> {
val cast = condition.leftHandSide.smartCastExpressionName().singletonOrEmptySet()
return if (condition.isNegated) Pair(setOf(), cast) else Pair(cast, setOf())
}
is KtPrefixExpression -> {
if (condition.operationToken == KtTokens.EXCL) {
val operand = condition.baseExpression ?: return emptyResult
return possiblySmartCastInCondition(operand).swap()
}
}
is KtParenthesizedExpression -> {
val operand = condition.expression ?: return emptyResult
return possiblySmartCastInCondition(operand)
}
}
return emptyResult
}
/**
* If it's possible that the given statement never passes the execution to the next statement (that is, always exits somewhere)
* then this function returns a collection of all places in code that are necessary to be kept to preserve this behaviour.
*/
private fun collectAlwaysExitPoints(statement: KtExpression?): Collection<KtExpression> {
val result = ArrayList<KtExpression>()
statement?.accept(object : ControlFlowVisitor() {
var insideLoopLevel: Int = 0
override fun visitReturnExpression(expression: KtReturnExpression) {
result.add(expression)
}
override fun visitThrowExpression(expression: KtThrowExpression) {
result.add(expression)
}
override fun visitIfExpression(expression: KtIfExpression) {
expression.condition?.accept(this)
val thenBranch = expression.then
val elseBranch = expression.`else`
if (thenBranch != null && elseBranch != null) { // if we have only one branch it makes no sense to search exits in it
val thenExits = collectAlwaysExitPoints(thenBranch)
if (thenExits.isNotEmpty()) {
val elseExits = collectAlwaysExitPoints(elseBranch)
if (elseExits.isNotEmpty()) {
result.addAll(thenExits)
result.addAll(elseExits)
}
}
}
}
override fun visitForExpression(loop: KtForExpression) {
loop.loopRange?.accept(this)
// do not make sense to search exits inside for as not necessary enter it at all
}
override fun visitWhileExpression(loop: KtWhileExpression) {
val condition = loop.condition ?: return
if (condition.isTrueConstant()) {
insideLoopLevel++
loop.body?.accept(this)
insideLoopLevel--
} else {
// do not make sense to search exits inside while-loop as not necessary enter it at all
condition.accept(this)
}
}
override fun visitDoWhileExpression(loop: KtDoWhileExpression) {
loop.condition?.accept(this)
insideLoopLevel++
loop.body?.accept(this)
insideLoopLevel--
}
override fun visitBreakExpression(expression: KtBreakExpression) {
if (insideLoopLevel == 0 || expression.getLabelName() != null) {
result.add(expression)
}
}
override fun visitContinueExpression(expression: KtContinueExpression) {
if (insideLoopLevel == 0 || expression.getLabelName() != null) {
result.add(expression)
}
}
override fun visitCallExpression(expression: KtCallExpression) {
val name = (expression.calleeExpression as? KtSimpleNameExpression)?.getReferencedName()
if (name != null && (name in globalProbablyNothingCallableNames.functionNames() || name in contextNothingFunctionNames)) {
result.add(expression)
}
super.visitCallExpression(expression)
}
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
val name = expression.getReferencedName()
if (name in globalProbablyNothingCallableNames.propertyNames() || name in contextNothingVariableNames) {
result.add(expression)
}
}
override fun visitBinaryExpression(expression: KtBinaryExpression) {
if (expression.operationToken == KtTokens.ELVIS) {
// do not search exits after "?:"
expression.left?.accept(this)
} else {
super.visitBinaryExpression(expression)
}
}
})
return result
}
/**
* Recursively visits code but does not enter constructs that may not affect smart casts/control flow
*/
private abstract class ControlFlowVisitor : KtVisitorVoid() {
override fun visitKtElement(element: KtElement) {
if (element.noControlFlowInside()) return
element.acceptChildren(this)
}
private fun KtElement.noControlFlowInside() = this is KtFunction || this is KtClass || this is KtClassBody
}
private data class SmartCastName(
private val receiverName: SmartCastName?,
private val selectorName: String? /* null means "this" (and receiverName should be null */
) {
init {
if (selectorName == null) {
assert(receiverName == null) { "selectorName is allowed to be null only when receiverName is also null (which means 'this')" }
}
}
override fun toString(): String = if (receiverName != null) "$receiverName.$selectorName" else selectorName ?: "this"
fun affectsNames(nameFilter: (String) -> Boolean): Boolean {
if (selectorName == null) return true
if (!nameFilter(selectorName)) return false
return receiverName == null || receiverName.affectsNames(nameFilter)
}
}
private fun KtExpression.smartCastExpressionName(): SmartCastName? {
return when (this) {
is KtSimpleNameExpression -> SmartCastName(null, this.getReferencedName())
is KtQualifiedExpression -> {
val selector = selectorExpression as? KtSimpleNameExpression ?: return null
val selectorName = selector.getReferencedName()
val receiver = receiverExpression
if (receiver is KtThisExpression) {
return SmartCastName(null, selectorName)
}
val receiverName = receiver.smartCastExpressionName() ?: return null
return SmartCastName(receiverName, selectorName)
}
is KtThisExpression -> SmartCastName(null, null)
else -> null
}
}
//TODO: declarations with special names (e.g. "get")
private class NameFilter : (String) -> Boolean {
private var names: MutableSet<String>? = HashSet()
override fun invoke(name: String) = names == null || name in names!!
val isEmpty: Boolean
get() = names?.isEmpty() ?: false
fun addUsedNames(statement: KtExpression) {
if (names != null) {
statement.forEachDescendantOfType<KtSimpleNameExpression>(canGoInside = { it !is KtBlockExpression }) {
names!!.add(it.getReferencedName())
}
}
}
fun addNamesFromFilter(filter: NameFilter) {
if (names == null) return
if (filter.names == null) {
names = null
} else {
names!!.addAll(filter.names!!)
}
}
fun addAllNames() {
names = null
}
}
private enum class MarkLevel {
NONE,
TAKE,
NEED_REFERENCE_RESOLVE,
NEED_COMPLETION
}
companion object {
fun findStatementToResolve(element: KtElement, declaration: KtDeclaration): KtExpression? {
return element.parentsWithSelf.takeWhile { it != declaration }.firstOrNull { it.isStatement() } as KtExpression?
}
private fun KtElement.forTopLevelBlocksInside(action: (KtBlockExpression) -> Unit) {
forEachDescendantOfType(canGoInside = { it !is KtBlockExpression }, action = action)
}
private fun KtExpression?.isNullLiteral() = this?.node?.elementType == KtNodeTypes.NULL
private fun KtExpression?.isTrueConstant() = this != null && node?.elementType == KtNodeTypes.BOOLEAN_CONSTANT && text == "true"
private fun <T : Any> T?.singletonOrEmptySet(): Set<T> = if (this != null) setOf(this) else setOf()
//TODO: review logic
private fun isValueNeeded(expression: KtExpression): Boolean = when (val parent = expression.parent) {
is KtBlockExpression -> expression == parent.lastStatement() && isValueNeeded(parent)
is KtContainerNode -> { //TODO - not quite correct
val pparent = parent.parent as? KtExpression
pparent != null && isValueNeeded(pparent)
}
is KtDeclarationWithBody -> {
if (expression == parent.bodyExpression)
!parent.hasBlockBody() && !parent.hasDeclaredReturnType()
else
true
}
is KtAnonymousInitializer -> false
else -> true
}
private fun KtBlockExpression.lastStatement(): KtExpression? =
lastChild?.siblings(forward = false)?.firstIsInstanceOrNull<KtExpression>()
private fun PsiElement.isStatement() = this is KtExpression && parent is KtBlockExpression
private fun KtTypeReference?.containsProbablyNothing() =
this?.typeElement?.anyDescendantOfType<KtUserType> { it.isProbablyNothing() } ?: false
}
private inner class StatementMarks {
private val statementMarks = HashMap<KtExpression, MarkLevel>()
private val blockLevels = HashMap<KtBlockExpression, MarkLevel>()
fun mark(element: PsiElement, level: MarkLevel) {
var e = element
while (e != declaration) {
if (e.isStatement()) {
markStatement(e as KtExpression, level)
}
e = e.parent!!
}
}
private fun markStatement(statement: KtExpression, level: MarkLevel) {
val currentLevel = statementMark(statement)
if (currentLevel < level) {
statementMarks[statement] = level
val block = statement.parent as KtBlockExpression
val currentBlockLevel = blockLevels[block] ?: MarkLevel.NONE
if (currentBlockLevel < level) {
blockLevels[block] = level
}
}
}
fun statementMark(statement: KtExpression): MarkLevel = statementMarks[statement] ?: MarkLevel.NONE
fun allMarkedStatements(): Collection<KtExpression> = statementMarks.keys
fun lastMarkedStatement(block: KtBlockExpression, minLevel: MarkLevel): KtExpression? {
val level = blockLevels[block] ?: MarkLevel.NONE
if (level < minLevel) return null // optimization
return block.lastChild.siblings(forward = false)
.filterIsInstance<KtExpression>()
.first { statementMark(it) >= minLevel }
}
}
}

View File

@@ -1,18 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.lazy
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
interface ProbablyContractedCallableNames {
fun isProbablyContractedCallableName(name: String): Boolean
companion object {
fun getInstance(project: Project): ProbablyContractedCallableNames =
ServiceManager.getService(project, ProbablyContractedCallableNames::class.java)!!
}
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve.lazy
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
interface ProbablyNothingCallableNames {
fun functionNames(): Collection<String>
fun propertyNames(): Collection<String>
companion object {
fun getInstance(project: Project) = ServiceManager.getService(project, ProbablyNothingCallableNames::class.java)!!
}
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.resolve.scopes
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.Printer
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
class ExplicitImportsScope(private val descriptors: Collection<DeclarationDescriptor>) : BaseImportingScope(null) {
override fun getContributedClassifier(name: Name, location: LookupLocation) =
descriptors.filter { it.name == name }.firstIsInstanceOrNull<ClassifierDescriptor>()
override fun getContributedPackage(name: Name) = descriptors.filter { it.name == name }.firstIsInstanceOrNull<PackageViewDescriptor>()
override fun getContributedVariables(name: Name, location: LookupLocation) =
descriptors.filter { it.name == name }.filterIsInstance<VariableDescriptor>()
override fun getContributedFunctions(name: Name, location: LookupLocation) =
descriptors.filter { it.name == name }.filterIsInstance<FunctionDescriptor>()
override fun getContributedDescriptors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean,
changeNamesForAliased: Boolean
) = descriptors
override fun computeImportedNames() = descriptors.mapTo(hashSetOf()) { it.name }
override fun printStructure(p: Printer) {
p.println(this::class.java.name)
}
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.util
import com.google.common.collect.HashMultimap
import com.google.common.collect.Multimap
import com.intellij.openapi.util.Key
import com.intellij.psi.stubs.PsiFileStub
import com.intellij.psi.stubs.StubElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.KtUserType
fun KtUserType.aliasImportMap(): Multimap<String, String> {
// we need to access containing file via stub because getPsi() may return null when indexing and getContainingFile() will crash
val file = stub?.getContainingFileStub()?.psi ?: return HashMultimap.create()
return (file as KtFile).aliasImportMap()
}
fun KtFile.aliasImportMap(): Multimap<String, String> {
val cached = getUserData(ALIAS_IMPORT_DATA_KEY)
val modificationStamp = modificationStamp
if (cached != null && modificationStamp == cached.fileModificationStamp) {
return cached.map
}
val data = CachedAliasImportData(buildAliasImportMap(), modificationStamp)
putUserData(ALIAS_IMPORT_DATA_KEY, data)
return data.map
}
private fun KtFile.buildAliasImportMap(): Multimap<String, String> {
val map = HashMultimap.create<String, String>()
val importList = importList ?: return map
for (import in importList.imports) {
val aliasName = import.aliasName ?: continue
val name = import.importPath?.fqName?.shortName()?.asString() ?: continue
map.put(aliasName, name)
}
return map
}
private class CachedAliasImportData(val map: Multimap<String, String>, val fileModificationStamp: Long)
private val ALIAS_IMPORT_DATA_KEY = Key<CachedAliasImportData>("ALIAS_IMPORT_MAP_KEY")
fun KtTypeReference?.isProbablyNothing(): Boolean {
val userType = this?.typeElement as? KtUserType ?: return false
return userType.isProbablyNothing()
}
//TODO: support type aliases
fun KtUserType?.isProbablyNothing(): Boolean {
if (this == null) return false
val referencedName = referencedName
return referencedName == "Nothing" || aliasImportMap()[referencedName].contains("Nothing")
}
private fun StubElement<*>.getContainingFileStub(): PsiFileStub<*> {
return if (this is PsiFileStub)
this
else
parentStub.getContainingFileStub()
}

View File

@@ -1,98 +0,0 @@
/*
* Copyright 2010-2019 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.util
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.resolve.OverridingUtil
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.CONFLICT
import org.jetbrains.kotlin.resolve.OverridingUtil.OverrideCompatibilityInfo.Result.OVERRIDABLE
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
import org.jetbrains.kotlin.types.checker.KotlinTypeCheckerImpl
import org.jetbrains.kotlin.types.typeUtil.equalTypesOrNulls
fun descriptorsEqualWithSubstitution(
descriptor1: DeclarationDescriptor?,
descriptor2: DeclarationDescriptor?,
checkOriginals: Boolean = true
): Boolean {
if (descriptor1 == descriptor2) return true
if (descriptor1 == null || descriptor2 == null) return false
if (checkOriginals && descriptor1.original != descriptor2.original) return false
if (descriptor1 !is CallableDescriptor) return true
descriptor2 as CallableDescriptor
val typeChecker = KotlinTypeCheckerImpl.withAxioms(object : KotlinTypeChecker.TypeConstructorEquality {
override fun equals(a: TypeConstructor, b: TypeConstructor): Boolean {
val typeParam1 = a.declarationDescriptor as? TypeParameterDescriptor
val typeParam2 = b.declarationDescriptor as? TypeParameterDescriptor
if (typeParam1 != null
&& typeParam2 != null
&& typeParam1.containingDeclaration == descriptor1
&& typeParam2.containingDeclaration == descriptor2
) {
return typeParam1.index == typeParam2.index
}
return a == b
}
})
if (!typeChecker.equalTypesOrNulls(descriptor1.returnType, descriptor2.returnType)) return false
val parameters1 = descriptor1.valueParameters
val parameters2 = descriptor2.valueParameters
if (parameters1.size != parameters2.size) return false
for ((param1, param2) in parameters1.zip(parameters2)) {
if (!typeChecker.equalTypes(param1.type, param2.type)) return false
}
return true
}
fun ClassDescriptor.findCallableMemberBySignature(
signature: CallableMemberDescriptor,
allowOverridabilityConflicts: Boolean = false
): CallableMemberDescriptor? {
val descriptorKind = if (signature is FunctionDescriptor) DescriptorKindFilter.FUNCTIONS else DescriptorKindFilter.VARIABLES
return defaultType.memberScope
.getContributedDescriptors(descriptorKind)
.filterIsInstance<CallableMemberDescriptor>()
.firstOrNull {
if (it.containingDeclaration != this) return@firstOrNull false
val overridability = OverridingUtil.DEFAULT.isOverridableBy(it as CallableDescriptor, signature, null).result
overridability == OVERRIDABLE || (allowOverridabilityConflicts && overridability == CONFLICT)
}
}
fun TypeConstructor.supertypesWithAny(): Collection<KotlinType> {
val supertypes = supertypes
val noSuperClass = supertypes.map { it.constructor.declarationDescriptor as? ClassDescriptor }.all {
it == null || it.kind == ClassKind.INTERFACE
}
return if (noSuperClass) supertypes + builtIns.anyType else supertypes
}
val ClassifierDescriptorWithTypeParameters.constructors: Collection<ConstructorDescriptor>
get() = when (this) {
is TypeAliasDescriptor -> this.constructors
is ClassDescriptor -> this.constructors
else -> emptyList()
}
val ClassifierDescriptorWithTypeParameters.kind: ClassKind?
get() = when (this) {
is TypeAliasDescriptor -> classDescriptor?.kind
is ClassDescriptor -> kind
else -> null
}
val DeclarationDescriptor.isJavaDescriptor
get() = this is JavaClassDescriptor || this is JavaCallableMemberDescriptor

View File

@@ -1,49 +0,0 @@
/*
* Copyright 2010-2019 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.types.substitutions
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure
import java.util.*
fun getTypeSubstitution(baseType: KotlinType, derivedType: KotlinType): LinkedHashMap<TypeConstructor, TypeProjection>? {
val substitutedType = TypeCheckingProcedure.findCorrespondingSupertype(derivedType, baseType) ?: return null
val substitution = LinkedHashMap<TypeConstructor, TypeProjection>(substitutedType.arguments.size)
for ((param, arg) in baseType.constructor.parameters.zip(substitutedType.arguments)) {
substitution[param.typeConstructor] = arg
}
return substitution
}
fun getCallableSubstitution(
baseCallable: CallableDescriptor,
derivedCallable: CallableDescriptor
): MutableMap<TypeConstructor, TypeProjection>? {
val baseClass = baseCallable.containingDeclaration as? ClassDescriptor ?: return null
val derivedClass = derivedCallable.containingDeclaration as? ClassDescriptor ?: return null
val substitution = getTypeSubstitution(baseClass.defaultType, derivedClass.defaultType) ?: return null
for ((baseParam, derivedParam) in baseCallable.typeParameters.zip(derivedCallable.typeParameters)) {
substitution[baseParam.typeConstructor] = TypeProjectionImpl(derivedParam.defaultType)
}
return substitution
}
fun getCallableSubstitutor(
baseCallable: CallableDescriptor,
derivedCallable: CallableDescriptor
): TypeSubstitutor? {
return getCallableSubstitution(baseCallable, derivedCallable)?.let { TypeSubstitutor.create(it) }
}
fun getTypeSubstitutor(baseType: KotlinType, derivedType: KotlinType): TypeSubstitutor? {
return getTypeSubstitution(baseType, derivedType)?.let { TypeSubstitutor.create(it) }
}

View File

@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="backend" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="light-classes" />
<orderEntry type="module" module-name="eval4j" />
<orderEntry type="module-library">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/../../ideaSDK/core/annotations.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="library" name="guava" level="project" />
<orderEntry type="module" module-name="js.frontend" />
<orderEntry type="module" module-name="js.serializer" />
<orderEntry type="library" name="trove4j" level="project" />
<orderEntry type="module" module-name="ide-common" exported="" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="idea-core" />
<orderEntry type="module" module-name="idea-jps-common" />
<orderEntry type="module" module-name="cli-common" />
<orderEntry type="module" module-name="descriptors" />
<orderEntry type="library" exported="" name="idea-full" level="project" />
<orderEntry type="library" name="uast-java" level="project" />
<orderEntry type="module" module-name="frontend.script" />
</component>
</module>

View File

@@ -1,95 +0,0 @@
found.space=found:\u0020
html.0.has.no.corresponding.expected.declaration.1.html={0} has no corresponding expected declaration{1}
html.0.is.not.abstract.and.does.not.implement.abstract.base.class.member.br.1.html={0} is not abstract and does not implement abstract base class member<br/>{1}
html.0.is.not.abstract.and.does.not.implement.abstract.member.br.1.html={0} is not abstract and does not implement abstract member<br/>{1}
html.0.method.may.be.missing.none.of.the.following.functions.will.be.called.ul.1.ul.html=''{0}'' method may be missing. None of the following functions will be called: <ul>{1}</ul>
html.candidate.resolution.will.be.changed.soon.please.use.fully.qualified.name.to.invoke.the.following.closer.candidate.explicitly.ul.0.ul.html=Candidate resolution will be changed soon, please use fully qualified name to invoke the following closer candidate explicitly: <ul>{0}</ul>
html.expected.0.has.no.actual.declaration.in.module.1.2.html=Expected {0} has no actual declaration in module {1}{2}
html.accidental.override.0.html=Accidental override: {0}
html.method.contains.from.concurrenthashmap.may.have.unexpected.semantics.it.calls.containsvalue.instead.of.containskey.br.use.explicit.form.of.the.call.to.containskey.containsvalue.contains.or.cast.the.value.to.kotlin.collections.map.instead.br.see.https.youtrack.jetbrains.com.issue.kt.18053.for.more.details.html=Method ''contains'' from ConcurrentHashMap may have unexpected semantics: it calls ''containsValue'' instead of ''containsKey''.<br/>Use explicit form of the call to ''containsKey''/''containsValue''/''contains'' or cast the value to kotlin.collections.Map instead.<br/>See https://youtrack.jetbrains.com/issue/KT-18053 for more details
html.javascript.0.html=JavaScript: {0}
html.platform.declaration.clash.0.html=Platform declaration clash: {0}
html.internal.error.occurred.while.analyzing.this.expression.br.table.cellspacing.0.cellpadding.0.tr.td.strong.please.use.the.strong.td.td.img.src.0.td.td.strong.icon.in.the.bottom.right.corner.to.report.this.error.strong.td.tr.table.br.pre.0.pre.html=Internal Error occurred while analyzing this expression <br/><table cellspacing="0" cellpadding="0"><tr><td>(<strong>Please use the "</strong></td><td><img src="{0}"/></td><td><strong>" icon in the bottom-right corner to report this error</strong>):</td></tr></table><br/><pre>{0}</pre>
html.property.delegate.must.have.a.0.method.none.of.the.following.functions.are.suitable.ul.1.ul.html=Property delegate must have a ''{0}'' method. None of the following functions are suitable. <ul>{1}</ul>
html.overload.resolution.ambiguity.on.method.0.all.these.functions.match.ul.1.ul.html=Overload resolution ambiguity on method ''{0}''. All these functions match. <ul>{1}</ul>
html.unresolved.reference.br.none.of.the.following.candidates.is.applicable.because.of.receiver.type.mismatch.ul.0.ul.html=Unresolved reference. <br/> None of the following candidates is applicable because of receiver type mismatch: <ul>{0}</ul>
html.cannot.choose.among.the.following.candidates.without.completing.type.inference.ul.0.ul.html=Cannot choose among the following candidates without completing type inference: <ul>{0}</ul>
html.none.of.the.following.functions.can.be.called.with.the.arguments.supplied.ul.0.ul.html=None of the following functions can be called with the arguments supplied. <ul>{0}</ul>
html.overload.resolution.ambiguity.all.these.functions.match.ul.0.ul.html=Overload resolution ambiguity. All these functions match. <ul>{0}</ul>
html.function.return.type.mismatch.table.tr.td.expected.td.td.1.td.tr.tr.td.found.td.td.2.td.tr.table.html=Function return type mismatch.<table><tr><td>Expected:</td><td>{1}</td></tr><tr><td>Found:</td><td>{2}</td></tr></table>
html.0.must.override.1.br.because.it.inherits.many.implementations.of.it.html={0} must override {1}<br />because it inherits many implementations of it
html.types.of.inherited.var.properties.do.not.match.br.0.br.1.html=Types of inherited var-properties do not match:<br/>{0},<br/>{1}
html.types.of.inherited.properties.are.incompatible.br.0.br.1.html=Types of inherited properties are incompatible:<br/>{0},<br/>{1}
html.actual.class.0.has.no.corresponding.members.for.expected.class.members.1.html=Actual class ''{0}'' has no corresponding members for expected class members:{1}
html.val.property.cannot.override.var.property.br.1.html=Val-property cannot override var-property<br />{1}
html.var.property.type.is.0.which.is.not.a.type.of.overridden.br.1.html=Var-property type is {0}, which is not a type of overridden<br/>{1}
required.space=required:\u0020
type.inference.failed.expected.type.mismatch=Type inference failed. Expected type mismatch:\u0020
html.setter.parameter.type.must.be.equal.to.the.type.of.the.property.table.tr.td.expected.td.td.0.td.tr.tr.td.found.td.td.1.td.tr.table.html=Setter parameter type must be equal to the type of the property.<table><tr><td>Expected:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table>
html.property.type.is.0.which.is.not.a.subtype.type.of.overridden.br.1.html=Property type is {0}, which is not a subtype type of overridden<br/>{1}
html.return.types.of.inherited.members.are.incompatible.br.0.br.1.html=Return types of inherited members are incompatible:<br/>{0},<br/>{1}
html.return.type.is.0.which.is.not.a.subtype.of.overridden.br.1.html=Return type is ''{0}'', which is not a subtype of overridden<br/>{1}
html.loop.parameter.type.mismatch.table.tr.td.iterated.values.td.td.0.td.tr.tr.td.parameter.td.td.1.td.tr.table.html=Loop parameter type mismatch.<table><tr><td>Iterated values:</td><td>{0}</td></tr><tr><td>Parameter:</td><td>{1}</td></tr></table>
html.type.argument.is.not.within.its.bounds.table.tr.td.expected.td.td.0.td.tr.tr.td.found.td.td.1.td.tr.table.html=Type argument is not within its bounds.<table><tr><td>Expected:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table>
html.method.iterator.is.ambiguous.for.this.expression.ul.0.ul.html=Method ''iterator()'' is ambiguous for this expression.<ul>{0}</ul>
html.getter.return.type.must.be.equal.to.the.type.of.the.property.table.tr.td.expected.td.td.0.td.tr.tr.td.found.td.td.1.td.tr.table.html=Getter return type must be equal to the type of the property.<table><tr><td>Expected:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table>
html.type.inference.failed.0.html=Type inference failed: {0}
html.assignment.operators.ambiguity.all.these.functions.match.ul.0.ul.table.html=Assignment operators ambiguity. All these functions match.<ul>{0}</ul></table>
html.type.mismatch.table.tr.td.required.td.td.0.td.tr.tr.td.found.td.td.1.td.tr.table.br.projected.type.2.restricts.use.of.br.3.html=Type mismatch.<table><tr><td>Required:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table><br />\nProjected type {2} restricts use of <br />\n{3}\n
html.type.mismatch.table.tr.td.required.td.td.0.td.tr.tr.td.found.td.td.1.td.tr.table.html=Type mismatch.<table><tr><td>Required:</td><td>{0}</td></tr><tr><td>Found:</td><td>{1}</td></tr></table>
intention.suppress.family=Suppress Warnings
intention.suppress.text=Suppress ''{0}'' for {1} {2}
intention.calculating.text=Quick fix is being calculated ...
special.module.for.files.not.under.source.root=<special module for files not under source root>
sdk.0=<sdk {0}>
sources.for.library.0=<sources for library {0}>
library.0=<library {0}>
source.for.script.dependencies=<Source for script dependencies>
script.dependencies=<Script dependencies>
script.0.1=<script {0} {1}>
module.name.0.test={0} (test)
platform.module.0.including.1=<Platform module {0} including {1}>
the.following.declarations.have.the.same.jvm.signature.code.0.1.code.br.ul.2.ul=The following declarations have the same JVM signature (<code>{0}{1}</code>):<br/>\n<ul>\n{2}</ul>
declaration.kind.object=object
declaration.kind.companion.object=companion object
declaration.kind.initializer=initializer
declaration.kind.statement=statement
declaration.kind.file=file
declaration.name.0.of.1={0} of {1}
declaration.kind.secondary.constructor.of=secondary constructor of
declaration.kind.enum.entry=enum entry
declaration.kind.type.parameter=type parameter
declaration.kind.class=class
declaration.kind.interface=interface
declaration.kind.fun=fun
declaration.kind.parameter=parameter
type.parameters.where=where
cannot.be.inferred=cannot be inferred
i.for.i.br.0=<i> for </i><br/>{0}
defined.in=defined in
root.package=root package
automatically.declared.based.on.the.expected.type=Automatically declared based on the expected type
0.smart.cast.to.1={0} smart cast to {1}
unknown.receiver=Unknown receiver
implicit.receiver=Implicit receiver
extension.implicit.receiver=Extension implicit receiver
always.null=Always null
value.captured.in.a.closure=Value captured in a closure
wrapped.into.a.reference.object.to.be.modified.when.captured.in.a.closure=Wrapped into a reference object to be modified when captured in a closure
smart.cast.to.0.for.1.call=Smart cast to {0} (for {1} call)
smart.cast.to.0=Smart cast to {0}
replace.overloaded.operator.with.function.call=Replace overloaded operator with function call
class.initializer=<class initializer>
object.0=object{0}
show.non.public=Show non-public
show.properties=Show properties
klib.metadata.short=Klib Metadata
function.arguments=arguments:\u0020
function.receiver.0=receiver: {0}
kotlin.built.in.declarations=Kotlin built-in declarations
kotlin.javascript.meta.file=Kotlin JavaScript meta file
framework.name.kotlin.sdk=Kotlin SDK

View File

@@ -1,139 +0,0 @@
/*
* Copyright 2010-2018 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.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.PathUtil
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
import org.jetbrains.kotlin.analyzer.common.CommonResolverForModuleFactory
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
import org.jetbrains.kotlin.idea.klib.AbstractKlibLibraryInfo
import org.jetbrains.kotlin.idea.klib.createKlibPackageFragmentProvider
import org.jetbrains.kotlin.idea.klib.isKlibLibraryRootForPlatform
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
import org.jetbrains.kotlin.library.metadata.NullFlexibleTypeDeserializer
import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
import org.jetbrains.kotlin.serialization.konan.impl.KlibMetadataModuleDescriptorFactoryImpl
import org.jetbrains.kotlin.storage.StorageManager
class CommonPlatformKindResolution : IdePlatformKindResolution {
override fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean {
return virtualFile.extension == MetadataPackageFragment.METADATA_FILE_EXTENSION ||
virtualFile.isKlibLibraryRootForPlatform(CommonPlatforms.defaultCommonPlatform)
}
override val libraryKind: PersistentLibraryKind<*>?
get() = CommonLibraryKind
override val kind get() = CommonIdePlatformKind
override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey =
BuiltInsCacheKey.DefaultBuiltInsKey
override fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?,
stdlibDependency: LibraryInfo?,
): KotlinBuiltIns {
return DefaultBuiltIns.Instance
}
override fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> {
val klibFiles = library.getFiles(OrderRootType.CLASSES).filter {
it.isKlibLibraryRootForPlatform(CommonPlatforms.defaultCommonPlatform)
}
return if (klibFiles.isNotEmpty()) {
klibFiles.mapNotNull {
val path = PathUtil.getLocalPath(it) ?: return@mapNotNull null
CommonKlibLibraryInfo(project, library, path)
}
} else {
// No klib files <=> old metadata-library <=> create usual LibraryInfo
listOf(CommonMetadataLibraryInfo(project, library))
}
}
override fun createKlibPackageFragmentProvider(
moduleInfo: ModuleInfo,
storageManager: StorageManager,
languageVersionSettings: LanguageVersionSettings,
moduleDescriptor: ModuleDescriptor
): PackageFragmentProvider? {
return (moduleInfo as? CommonKlibLibraryInfo)
?.resolvedKotlinLibrary
?.createKlibPackageFragmentProvider(
storageManager = storageManager,
metadataModuleDescriptorFactory = metadataModuleDescriptorFactory,
languageVersionSettings = languageVersionSettings,
moduleDescriptor = moduleDescriptor,
lookupTracker = LookupTracker.DO_NOTHING
)
}
override fun createResolverForModuleFactory(
settings: PlatformAnalysisParameters,
environment: TargetEnvironment,
platform: TargetPlatform
): ResolverForModuleFactory {
return CommonResolverForModuleFactory(
settings as CommonAnalysisParameters,
environment,
platform,
shouldCheckExpectActual = true
)
}
companion object {
private val metadataFactories = KlibMetadataFactories({ DefaultBuiltIns.Instance }, NullFlexibleTypeDeserializer)
private val metadataModuleDescriptorFactory = KlibMetadataModuleDescriptorFactoryImpl(
metadataFactories.DefaultDescriptorFactory,
metadataFactories.DefaultPackageFragmentsFactory,
metadataFactories.flexibleTypeDeserializer,
metadataFactories.platformDependentTypeTransformer
)
}
}
class CommonKlibLibraryInfo(
project: Project,
library: Library,
libraryRoot: String
) : AbstractKlibLibraryInfo(project, library, libraryRoot) {
override val platform: TargetPlatform
get() = CommonPlatforms.defaultCommonPlatform
}
class CommonMetadataLibraryInfo(project: Project, library: Library) : LibraryInfo(project, library) {
override val platform: TargetPlatform
get() = CommonPlatforms.defaultCommonPlatform
}

View File

@@ -1,270 +0,0 @@
/*
* Copyright 2010-2020 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:Suppress("Duplicates")
package org.jetbrains.kotlin.caches.resolve
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.containers.addIfNotNull
import org.jetbrains.kotlin.analyzer.*
import org.jetbrains.kotlin.analyzer.common.CommonAnalysisParameters
import org.jetbrains.kotlin.analyzer.common.configureCommonSpecificComponents
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltInsPackageFragmentProvider
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.*
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.frontend.di.configureModule
import org.jetbrains.kotlin.frontend.di.configureStandardResolveComponents
import org.jetbrains.kotlin.frontend.java.di.configureJavaSpecificComponents
import org.jetbrains.kotlin.frontend.java.di.initializeJavaSpecificComponents
import org.jetbrains.kotlin.idea.compiler.IdeSealedClassInheritorsProvider
import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolver
import org.jetbrains.kotlin.load.java.lazy.ModuleClassResolverImpl
import org.jetbrains.kotlin.load.kotlin.PackagePartProvider
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinderFactory
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.platform.*
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.js.isJs
import org.jetbrains.kotlin.platform.jvm.JvmPlatform
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.platform.konan.NativePlatform
import org.jetbrains.kotlin.platform.konan.NativePlatforms
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.checkers.ExperimentalMarkerDeclarationAnnotationChecker
import org.jetbrains.kotlin.resolve.jvm.JavaDescriptorResolver
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactory
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragmentProvider
import org.jetbrains.kotlin.serialization.deserialization.MetadataPartProvider
import org.jetbrains.kotlin.storage.StorageManager
class CompositeResolverForModuleFactory(
private val commonAnalysisParameters: CommonAnalysisParameters,
private val jvmAnalysisParameters: JvmPlatformParameters,
private val targetPlatform: TargetPlatform,
private val compilerServices: CompositeAnalyzerServices
) : ResolverForModuleFactory() {
override fun <M : ModuleInfo> createResolverForModule(
moduleDescriptor: ModuleDescriptorImpl,
moduleContext: ModuleContext,
moduleContent: ModuleContent<M>,
resolverForProject: ResolverForProject<M>,
languageVersionSettings: LanguageVersionSettings,
sealedInheritorsProvider: SealedClassInheritorsProvider
): ResolverForModule {
val (moduleInfo, syntheticFiles, moduleContentScope) = moduleContent
val project = moduleContext.project
val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
project, moduleContext.storageManager, syntheticFiles,
moduleContentScope,
moduleInfo
)
val metadataPartProvider = commonAnalysisParameters.metadataPartProviderFactory(moduleContent)
val trace = CodeAnalyzerInitializer.getInstance(project).createTrace()
val moduleClassResolver = ModuleClassResolverImpl { javaClass ->
val referencedClassModule = jvmAnalysisParameters.moduleByJavaClass(javaClass)
// We don't have full control over idea resolve api so we allow for a situation which should not happen in Kotlin.
// For example, type in a java library can reference a class declared in a source root (is valid but rare case)
// Providing a fallback strategy in this case can hide future problems, so we should at least log to be able to diagnose those
@Suppress("UNCHECKED_CAST")
val resolverForReferencedModule = referencedClassModule?.let { resolverForProject.tryGetResolverForModule(it as M) }
val resolverForModule = resolverForReferencedModule?.takeIf {
referencedClassModule.platform.has<JvmPlatform>()
} ?: run {
// in case referenced class lies outside of our resolver, resolve the class as if it is inside our module
// this leads to java class being resolved several times
resolverForProject.resolverForModule(moduleInfo)
}
resolverForModule.componentProvider.get<JavaDescriptorResolver>()
}
val packagePartProvider = jvmAnalysisParameters.packagePartProviderFactory(moduleContent)
val container = createContainerForCompositePlatform(
moduleContext, moduleContentScope, languageVersionSettings, targetPlatform,
compilerServices, trace, declarationProviderFactory, metadataPartProvider,
moduleClassResolver, packagePartProvider
)
val packageFragmentProviders = sequence {
yield(container.get<ResolveSession>().packageFragmentProvider)
yieldAll(getCommonProvidersIfAny(moduleInfo, moduleContext, moduleDescriptor, container)) // todo: module context
yieldAll(getJsProvidersIfAny(moduleInfo, moduleContext, moduleDescriptor, container))
yieldAll(getJvmProvidersIfAny(container))
yieldAll(getNativeProvidersIfAny(moduleInfo, container))
}.toList()
return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container)
}
private fun getCommonProvidersIfAny(
moduleInfo: ModuleInfo,
moduleContext: ModuleContext,
moduleDescriptor: ModuleDescriptor,
container: StorageComponentContainer
): List<PackageFragmentProvider> {
if (!targetPlatform.isCommon()) return emptyList()
val metadataProvider = container.get<MetadataPackageFragmentProvider>()
val klibMetadataProvider = CommonPlatforms.defaultCommonPlatform.idePlatformKind.resolution.createKlibPackageFragmentProvider(
moduleInfo,
moduleContext.storageManager,
container.get<LanguageVersionSettings>(),
moduleDescriptor
)
return listOfNotNull(metadataProvider, klibMetadataProvider)
}
@OptIn(ExperimentalStdlibApi::class)
private fun getJvmProvidersIfAny(container: StorageComponentContainer): List<PackageFragmentProvider> =
buildList {
if (targetPlatform.has<JvmPlatform>()) add(container.get<JavaDescriptorResolver>().packageFragmentProvider)
// Use JVM built-ins only for completely-JVM modules
addIfNotNull(container.tryGetService(JvmBuiltInsPackageFragmentProvider::class.java))
}
private fun getNativeProvidersIfAny(moduleInfo: ModuleInfo, container: StorageComponentContainer): List<PackageFragmentProvider> {
if (!targetPlatform.has<NativePlatform>()) return emptyList()
return listOfNotNull(
NativePlatforms.unspecifiedNativePlatform.idePlatformKind.resolution.createKlibPackageFragmentProvider(
moduleInfo,
container.get<StorageManager>(),
container.get<LanguageVersionSettings>(),
container.get<ModuleDescriptor>()
)
)
}
private fun getJsProvidersIfAny(
moduleInfo: ModuleInfo,
moduleContext: ModuleContext,
moduleDescriptor: ModuleDescriptorImpl,
container: StorageComponentContainer
): List<PackageFragmentProvider> {
if (moduleInfo !is LibraryModuleInfo || !moduleInfo.platform.isJs()) return emptyList()
return createPackageFragmentProvider(moduleInfo, container, moduleContext, moduleDescriptor)
}
fun createContainerForCompositePlatform(
moduleContext: ModuleContext,
moduleContentScope: GlobalSearchScope,
languageVersionSettings: LanguageVersionSettings,
targetPlatform: TargetPlatform,
analyzerServices: CompositeAnalyzerServices,
trace: BindingTrace,
declarationProviderFactory: DeclarationProviderFactory,
metadataPartProvider: MetadataPartProvider,
// Guaranteed to be non-null for modules with JVM
moduleClassResolver: ModuleClassResolver?,
packagePartProvider: PackagePartProvider?
): StorageComponentContainer = composeContainer("CompositePlatform") {
// Shared by all PlatformConfigurators
configureDefaultCheckers()
// Specific for each PlatformConfigurator
for (configurator in analyzerServices.services.map { it.platformConfigurator as PlatformConfiguratorBase }) {
configurator.configureExtensionsAndCheckers(this)
}
// Called by all normal containers set-ups
configureModule(moduleContext, targetPlatform, analyzerServices, trace, languageVersionSettings, IdeSealedClassInheritorsProvider)
configureStandardResolveComponents()
useInstance(moduleContentScope)
useInstance(declarationProviderFactory)
// Probably, should be in StandardResolveComponents, but
useInstance(VirtualFileFinderFactory.getInstance(moduleContext.project).create(moduleContentScope))
useInstance(packagePartProvider!!)
// JVM-specific
if (targetPlatform.has<JvmPlatform>()) {
configureJavaSpecificComponents(
moduleContext, moduleClassResolver!!,
languageVersionSettings,
configureJavaClassFinder = null,
javaClassTracker = null,
useBuiltInsProvider = IdeBuiltInsLoadingState.isFromDependenciesForJvm && targetPlatform.isJvm() // use JVM BuiltIns only for completely JVM modules
)
}
// Common-specific
if (targetPlatform.isCommon()) {
configureCommonSpecificComponents()
}
IdeaEnvironment.configure(this)
}.apply {
if (targetPlatform.has<JvmPlatform>()) {
initializeJavaSpecificComponents(trace)
}
}
}
class CompositeAnalyzerServices(val services: List<PlatformDependentAnalyzerServices>) : PlatformDependentAnalyzerServices() {
override val platformConfigurator: PlatformConfigurator = CompositePlatformConfigurator(services.map { it.platformConfigurator })
override fun computePlatformSpecificDefaultImports(storageManager: StorageManager, result: MutableList<ImportPath>) {
val intersectionOfDefaultImports = services.map { service ->
mutableListOf<ImportPath>()
.apply { service.computePlatformSpecificDefaultImports(storageManager, this) }
.toSet()
}.safeIntersect()
result.addAll(intersectionOfDefaultImports)
}
override val defaultLowPriorityImports: List<ImportPath> = services.map { it.defaultLowPriorityImports.toSet() }.safeIntersect()
override val excludedImports: List<FqName> = services.map { it.excludedImports.toSet() }.safeUnion()
private fun <T> List<Set<T>>.safeUnion(): List<T> =
if (isEmpty()) emptyList() else reduce { first, second -> first.union(second) }.toList()
private fun <T> List<Set<T>>.safeIntersect(): List<T> =
if (isEmpty()) emptyList() else reduce { first, second -> first.intersect(second) }.toList()
}
class CompositePlatformConfigurator(private val componentConfigurators: List<PlatformConfigurator>) : PlatformConfigurator {
override val platformSpecificContainer: StorageComponentContainer
get() = composeContainer(this::class.java.simpleName) {
configureDefaultCheckers()
for (configurator in componentConfigurators) {
(configurator as PlatformConfiguratorBase).configureExtensionsAndCheckers(this)
}
}
override fun configureModuleComponents(container: StorageComponentContainer, languageVersionSettings: LanguageVersionSettings) {
componentConfigurators.forEach { it.configureModuleComponents(container, languageVersionSettings) }
}
override fun configureModuleDependentCheckers(container: StorageComponentContainer) {
// We (ab)use the fact that currently, platforms don't use that method, so the only injected compnent will be
// ExperimentalMarkerDeclarationAnnotationChecker.
// Unfortunately, it is declared in base class, so repeating call to 'configureModuleDependentCheckers' will lead
// to multiple registrrations.
container.useImpl<ExperimentalMarkerDeclarationAnnotationChecker>()
}
}

View File

@@ -1,99 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.storage.StorageManager
interface IdePlatformKindResolution {
val kind: IdePlatformKind<*>
fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey
fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?,
stdlibDependency: LibraryInfo?
): KotlinBuiltIns
fun createResolverForModuleFactory(
settings: PlatformAnalysisParameters,
environment: TargetEnvironment,
platform: TargetPlatform
): ResolverForModuleFactory
fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean
fun createKlibPackageFragmentProvider(
moduleInfo: ModuleInfo,
storageManager: StorageManager,
languageVersionSettings: LanguageVersionSettings,
moduleDescriptor: ModuleDescriptor
): PackageFragmentProvider? = null
val libraryKind: PersistentLibraryKind<*>?
fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo>
companion object : ApplicationExtensionDescriptor<IdePlatformKindResolution>(
"org.jetbrains.kotlin.idePlatformKindResolution", IdePlatformKindResolution::class.java
) {
private val CACHED_RESOLUTION_SUPPORT by lazy {
val allPlatformKinds = IdePlatformKind.ALL_KINDS
val groupedResolution = getInstances().groupBy { it.kind }.mapValues { it.value.single() }
for (kind in allPlatformKinds) {
if (kind !in groupedResolution) {
throw IllegalStateException(
"Resolution support for the platform '$kind' is missing. " +
"Implement 'IdePlatformKindResolution' for it."
)
}
}
groupedResolution
}
fun getResolution(kind: IdePlatformKind<*>): IdePlatformKindResolution {
return CACHED_RESOLUTION_SUPPORT[kind] ?: error("Unknown platform $this")
}
}
}
val IdePlatformKind<*>.resolution: IdePlatformKindResolution
get() = IdePlatformKindResolution.getResolution(this)

View File

@@ -1,127 +0,0 @@
/*
* Copyright 2010-2020 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.caches.resolve
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.PathUtil
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
import org.jetbrains.kotlin.idea.klib.AbstractKlibLibraryInfo
import org.jetbrains.kotlin.idea.klib.createKlibPackageFragmentProvider
import org.jetbrains.kotlin.idea.klib.isKlibLibraryRootForPlatform
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind
import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer
import org.jetbrains.kotlin.serialization.konan.impl.KlibMetadataModuleDescriptorFactoryImpl
import org.jetbrains.kotlin.storage.StorageManager
class JsPlatformKindResolution : IdePlatformKindResolution {
override fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean {
return virtualFile.extension == "js"
|| virtualFile.extension == "kjsm"
|| virtualFile.isKlibLibraryRootForPlatform(JsPlatforms.defaultJsPlatform)
}
override val libraryKind: PersistentLibraryKind<*>?
get() = JSLibraryKind
override val kind get() = JsIdePlatformKind
override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey {
return BuiltInsCacheKey.DefaultBuiltInsKey
}
override fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?,
stdlibDependency: LibraryInfo?,
): KotlinBuiltIns {
return DefaultBuiltIns.Instance
}
override fun createResolverForModuleFactory(
settings: PlatformAnalysisParameters,
environment: TargetEnvironment,
platform: TargetPlatform
): ResolverForModuleFactory = JsResolverForModuleFactory(environment)
override fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> {
val klibFiles = library.getFiles(OrderRootType.CLASSES).filter {
it.isKlibLibraryRootForPlatform(JsPlatforms.defaultJsPlatform)
}
return if (klibFiles.isNotEmpty()) {
klibFiles.mapNotNull {
// TODO report error?
val path = PathUtil.getLocalPath(it) ?: return@mapNotNull null
JsKlibLibraryInfo(project, library, path)
}
} else {
listOf(JsMetadataLibraryInfo(project, library))
}
}
override fun createKlibPackageFragmentProvider(
moduleInfo: ModuleInfo,
storageManager: StorageManager,
languageVersionSettings: LanguageVersionSettings,
moduleDescriptor: ModuleDescriptor
): PackageFragmentProvider? {
return (moduleInfo as? JsKlibLibraryInfo)
?.resolvedKotlinLibrary
?.createKlibPackageFragmentProvider(
storageManager = storageManager,
metadataModuleDescriptorFactory = metadataModuleDescriptorFactory,
languageVersionSettings = languageVersionSettings,
moduleDescriptor = moduleDescriptor,
lookupTracker = LookupTracker.DO_NOTHING
)
}
companion object {
private val metadataFactories = KlibMetadataFactories({ DefaultBuiltIns.Instance }, DynamicTypeDeserializer)
private val metadataModuleDescriptorFactory = KlibMetadataModuleDescriptorFactoryImpl(
metadataFactories.DefaultDescriptorFactory,
metadataFactories.DefaultPackageFragmentsFactory,
metadataFactories.flexibleTypeDeserializer,
metadataFactories.platformDependentTypeTransformer
)
}
}
class JsKlibLibraryInfo(project: Project, library: Library, libraryRoot: String) : AbstractKlibLibraryInfo(project, library, libraryRoot) {
override val platform: TargetPlatform
get() = JsPlatforms.defaultJsPlatform
}
class JsMetadataLibraryInfo(project: Project, library: Library) : LibraryInfo(project, library) {
override val platform: TargetPlatform
get() = JsPlatforms.defaultJsPlatform
}

View File

@@ -1,114 +0,0 @@
/*
* Copyright 2010-2020 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.caches.resolve
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.analyzer.*
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.StorageComponentContainer
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.frontend.di.createContainerForLazyResolve
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
import org.jetbrains.kotlin.platform.idePlatformKind
import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.resolve.BindingTraceContext
import org.jetbrains.kotlin.resolve.SealedClassInheritorsProvider
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
import org.jetbrains.kotlin.serialization.js.KotlinJavascriptSerializationUtil
import org.jetbrains.kotlin.serialization.js.createKotlinJavascriptPackageFragmentProvider
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
import java.io.File
private val LOG = Logger.getInstance(JsResolverForModuleFactory::class.java)
class JsResolverForModuleFactory(
private val targetEnvironment: TargetEnvironment
) : ResolverForModuleFactory() {
override fun <M : ModuleInfo> createResolverForModule(
moduleDescriptor: ModuleDescriptorImpl,
moduleContext: ModuleContext,
moduleContent: ModuleContent<M>,
resolverForProject: ResolverForProject<M>,
languageVersionSettings: LanguageVersionSettings,
sealedInheritorsProvider: SealedClassInheritorsProvider
): ResolverForModule {
val (moduleInfo, syntheticFiles, moduleContentScope) = moduleContent
val project = moduleContext.project
val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
project,
moduleContext.storageManager,
syntheticFiles,
moduleContentScope,
moduleInfo
)
val container = createContainerForLazyResolve(
moduleContext,
declarationProviderFactory,
BindingTraceContext(/* allowSliceRewrite = */ true),
moduleDescriptor.platform!!,
JsPlatformAnalyzerServices,
targetEnvironment,
languageVersionSettings
)
var packageFragmentProvider = container.get<ResolveSession>().packageFragmentProvider
val libraryProviders = createPackageFragmentProvider(moduleInfo, container, moduleContext, moduleDescriptor)
if (libraryProviders.isNotEmpty()) {
packageFragmentProvider = CompositePackageFragmentProvider(listOf(packageFragmentProvider) + libraryProviders)
}
return ResolverForModule(packageFragmentProvider, container)
}
}
internal fun <M : ModuleInfo> createPackageFragmentProvider(
moduleInfo: M,
container: StorageComponentContainer,
moduleContext: ModuleContext,
moduleDescriptor: ModuleDescriptorImpl
): List<PackageFragmentProvider> = when (moduleInfo) {
is JsKlibLibraryInfo -> {
listOfNotNull(
JsPlatforms.defaultJsPlatform.idePlatformKind.resolution.createKlibPackageFragmentProvider(
moduleInfo,
moduleContext.storageManager,
container.get<LanguageVersionSettings>(),
moduleDescriptor
)
)
}
is LibraryModuleInfo -> {
moduleInfo.getLibraryRoots()
.flatMap {
if (File(it).exists()) {
KotlinJavascriptMetadataUtils.loadMetadata(it)
} else {
// TODO can/should we warn a user about a problem in a library root? If so how?
LOG.error("Library $it not found")
emptyList()
}
}
.filter { it.version.isCompatible() }
.map { metadata ->
val (header, packageFragmentProtos) =
KotlinJavascriptSerializationUtil.readModuleAsProto(metadata.body, metadata.version)
createKotlinJavascriptPackageFragmentProvider(
moduleContext.storageManager, moduleDescriptor, header, packageFragmentProtos, metadata.version,
container.get(), LookupTracker.DO_NOTHING
)
}
}
else -> emptyList()
}

View File

@@ -1,138 +0,0 @@
/*
* Copyright 2010-2018 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.caches.resolve
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.PersistentLibraryKind
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.analyzer.PlatformAnalysisParameters
import org.jetbrains.kotlin.analyzer.ResolverForModuleFactory
import org.jetbrains.kotlin.analyzer.ResolverForProject
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.jvm.JvmBuiltIns
import org.jetbrains.kotlin.context.ProjectContext
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
import org.jetbrains.kotlin.idea.configuration.IdeBuiltInsLoadingState
import org.jetbrains.kotlin.idea.caches.resolve.supportsAdditionalBuiltInsMembers
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.resolve.TargetEnvironment
import org.jetbrains.kotlin.resolve.jvm.JvmPlatformParameters
import org.jetbrains.kotlin.resolve.jvm.JvmResolverForModuleFactory
private val LOG = Logger.getInstance(JvmPlatformKindResolution::class.java)
class JvmPlatformKindResolution : IdePlatformKindResolution {
override fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean {
return false // TODO: No library kind for JVM
}
override fun createResolverForModuleFactory(
settings: PlatformAnalysisParameters,
environment: TargetEnvironment,
platform: TargetPlatform
): ResolverForModuleFactory {
return JvmResolverForModuleFactory(settings as JvmPlatformParameters, environment, platform)
}
override val libraryKind: PersistentLibraryKind<*>?
get() = null
override fun createLibraryInfo(project: Project, library: Library): List<LibraryInfo> =
listOf(JvmLibraryInfo(project, library))
override val kind get() = JvmIdePlatformKind
override fun getKeyForBuiltIns(moduleInfo: ModuleInfo, sdkInfo: SdkInfo?, stdlibInfo: LibraryInfo?): BuiltInsCacheKey {
if (IdeBuiltInsLoadingState.isFromClassLoader && stdlibInfo != null) {
LOG.error("Standard library ${stdlibInfo.displayedName} provided for built-ins, but loading from dependencies is disabled")
}
return if (sdkInfo != null)
CacheKeyByBuiltInsDependencies(sdkInfo.sdk, stdlibInfo)
else BuiltInsCacheKey.DefaultBuiltInsKey
}
override fun createBuiltIns(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo?,
stdlibDependency: LibraryInfo?,
): KotlinBuiltIns {
return when {
sdkDependency == null -> DefaultBuiltIns.Instance
stdlibDependency == null || moduleInfo is SdkInfo ->
createBuiltInsFromClassLoader(moduleInfo, projectContext, resolverForProject, sdkDependency)
else -> createBuiltinsFromModuleDependencies(moduleInfo, projectContext, resolverForProject, sdkDependency, stdlibDependency)
}
}
private fun createBuiltInsFromClassLoader(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo,
): JvmBuiltIns {
return JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_CLASS_LOADER).apply {
setPostponedSettingsComputation {
// SDK should be present, otherwise we wouldn't have created JvmBuiltIns in createBuiltIns
val sdkDescriptor = resolverForProject.descriptorForModule(sdkDependency)
val isAdditionalBuiltInsFeaturesSupported =
moduleInfo.supportsAdditionalBuiltInsMembers(projectContext.project)
JvmBuiltIns.Settings(sdkDescriptor, isAdditionalBuiltInsFeaturesSupported)
}
}
}
private fun createBuiltinsFromModuleDependencies(
moduleInfo: IdeaModuleInfo,
projectContext: ProjectContext,
resolverForProject: ResolverForProject<IdeaModuleInfo>,
sdkDependency: SdkInfo,
stdlibDependency: LibraryInfo,
): JvmBuiltIns {
if (IdeBuiltInsLoadingState.isFromClassLoader) {
LOG.error("Incorrect attempt to create built-ins from module dependencies")
}
return JvmBuiltIns(projectContext.storageManager, JvmBuiltIns.Kind.FROM_DEPENDENCIES).apply {
setPostponedBuiltinsModuleComputation {
val stdlibDescriptor = resolverForProject.descriptorForModule(stdlibDependency)
@Suppress("unchecked_cast")
stdlibDescriptor as ModuleDescriptorImpl
}
setPostponedSettingsComputation {
val sdkDescriptor = resolverForProject.descriptorForModule(sdkDependency)
val isAdditionalBuiltInsFeaturesSupported =
moduleInfo.supportsAdditionalBuiltInsMembers(projectContext.project)
JvmBuiltIns.Settings(sdkDescriptor, isAdditionalBuiltInsFeaturesSupported)
}
}
}
data class CacheKeyByBuiltInsDependencies(val sdk: Sdk, val stdlib: LibraryInfo?) : BuiltInsCacheKey
}
class JvmLibraryInfo(project: Project, library: Library) : LibraryInfo(project, library) {
override val platform: TargetPlatform
get() = JvmPlatforms.defaultJvmPlatform
}

View File

@@ -1,155 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Iconable;
import com.intellij.psi.PsiElement;
import com.intellij.ui.RowIcon;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.kotlin.psi.KtElement;
import javax.swing.*;
public final class KotlinDescriptorIconProvider {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.kotlin.idea.KotlinDescriptorIconProvider");
private KotlinDescriptorIconProvider() {
}
@Nullable
public static Icon getIcon(@NotNull DeclarationDescriptor descriptor, @Nullable PsiElement declaration, @Iconable.IconFlags int flags) {
if (declaration != null && !(declaration instanceof KtElement)) {
return declaration.getIcon(flags);
}
Icon result = getBaseIcon(descriptor);
if ((flags & Iconable.ICON_FLAG_VISIBILITY) > 0) {
RowIcon rowIcon = new RowIcon(2);
rowIcon.setIcon(result, 0);
rowIcon.setIcon(getVisibilityIcon(descriptor), 1);
result = rowIcon;
}
return result;
}
private static Icon getVisibilityIcon(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof DeclarationDescriptorWithVisibility) {
DeclarationDescriptorWithVisibility descriptorWithVisibility = (DeclarationDescriptorWithVisibility) descriptor;
DescriptorVisibility visibility = descriptorWithVisibility.getVisibility().normalize();
if (visibility == DescriptorVisibilities.PUBLIC) {
return PlatformIcons.PUBLIC_ICON;
}
if (visibility == DescriptorVisibilities.PROTECTED) {
return PlatformIcons.PROTECTED_ICON;
}
if (DescriptorVisibilities.isPrivate(visibility)) {
return PlatformIcons.PRIVATE_ICON;
}
if (visibility == DescriptorVisibilities.INTERNAL) {
return PlatformIcons.PACKAGE_LOCAL_ICON;
}
}
return null;
}
private static Modality getModalitySafe(@NotNull MemberDescriptor descriptor) {
try {
return descriptor.getModality();
}
catch (InvalidModuleException ex) {
return Modality.FINAL;
}
}
private static Icon getBaseIcon(@NotNull DeclarationDescriptor descriptor) {
if (descriptor instanceof PackageFragmentDescriptor || descriptor instanceof PackageViewDescriptor) {
return PlatformIcons.PACKAGE_ICON;
}
if (descriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) descriptor;
if (functionDescriptor.getExtensionReceiverParameter() != null) {
return Modality.ABSTRACT == getModalitySafe(functionDescriptor)
? KotlinIcons.ABSTRACT_EXTENSION_FUNCTION
: KotlinIcons.EXTENSION_FUNCTION;
}
if (descriptor.getContainingDeclaration() instanceof ClassDescriptor) {
return Modality.ABSTRACT == getModalitySafe(functionDescriptor)
? PlatformIcons.ABSTRACT_METHOD_ICON
: PlatformIcons.METHOD_ICON;
}
else {
return KotlinIcons.FUNCTION;
}
}
if (descriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
switch (classDescriptor.getKind()) {
case INTERFACE:
return KotlinIcons.INTERFACE;
case ENUM_CLASS:
return KotlinIcons.ENUM;
case ENUM_ENTRY:
return KotlinIcons.ENUM;
case ANNOTATION_CLASS:
return KotlinIcons.ANNOTATION;
case OBJECT:
return KotlinIcons.OBJECT;
case CLASS:
return Modality.ABSTRACT == getModalitySafe(classDescriptor) ?
KotlinIcons.ABSTRACT_CLASS :
KotlinIcons.CLASS;
default:
LOG.warn("No icon for descriptor: " + descriptor);
return null;
}
}
if (descriptor instanceof ValueParameterDescriptor) {
return KotlinIcons.PARAMETER;
}
if (descriptor instanceof LocalVariableDescriptor) {
return ((VariableDescriptor) descriptor).isVar() ? KotlinIcons.VAR : KotlinIcons.VAL;
}
if (descriptor instanceof PropertyDescriptor) {
return ((VariableDescriptor) descriptor).isVar() ? KotlinIcons.FIELD_VAR : KotlinIcons.FIELD_VAL;
}
if (descriptor instanceof TypeParameterDescriptor) {
return PlatformIcons.CLASS_ICON;
}
if (descriptor instanceof TypeAliasDescriptor) {
return KotlinIcons.TYPE_ALIAS;
}
LOG.warn("No icon for descriptor: " + descriptor);
return null;
}
}

View File

@@ -1,14 +0,0 @@
/*
* Copyright 2010-2019 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.idea
import org.jetbrains.kotlin.idea.util.hasMatchingExpected
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.psiUtil.hasActualModifier
class KotlinIconProvider : KotlinIconProviderBase() {
override fun KtDeclaration.isMatchingExpected() = hasActualModifier() && hasMatchingExpected()
}

View File

@@ -1,84 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.util.IconLoader;
import com.intellij.util.PlatformIcons;
import javax.swing.*;
public interface KotlinIcons {
Icon SMALL_LOGO = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin.svg");
Icon SMALL_LOGO_13 = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin13.svg");
Icon CLASS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/classKotlin.svg");
Icon ABSTRACT_CLASS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/abstractClassKotlin.svg");
Icon ENUM = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/enumKotlin.svg");
Icon FILE = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_file.svg");
Icon SCRIPT = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_script.svg");
Icon GRADLE_SCRIPT = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_gradle_script.svg");
Icon OBJECT = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/objectKotlin.svg");
Icon INTERFACE = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/interfaceKotlin.svg");
Icon ANNOTATION = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/annotationKotlin.svg");
Icon FUNCTION = AllIcons.Nodes.Function;
Icon EXTENSION_FUNCTION = PlatformIcons.FUNCTION_ICON;
Icon ABSTRACT_EXTENSION_FUNCTION = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/abstract_extension_function.svg");
Icon LAMBDA = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/lambda.svg");
Icon VAR = PlatformIcons.VARIABLE_ICON;
Icon VAL = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/value.svg");
Icon PARAMETER = PlatformIcons.PARAMETER_ICON;
Icon FIELD_VAL = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/field_value.svg");
Icon FIELD_VAR = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/field_variable.svg");
Icon CLASS_INITIALIZER = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/classInitializerKotlin.svg");
Icon TYPE_ALIAS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/typeAlias.svg");
Icon DSL_MARKER_ANNOTATION = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/dslMarkerAnnotation.svg");
Icon SUSPEND_CALL = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/suspendCall.svg");
Icon ACTUAL = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/actual.svg");
Icon EXPECT = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/expect.svg");
Icon LAUNCH = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_launch_configuration.svg");
Icon LOAD_SCRIPT_CONFIGURATION = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/loadScriptConfiguration.svg");
Icon JS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_js.svg");
Icon MPP = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_multiplatform_project.svg");
Icon NATIVE = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/kotlin_native.svg");
interface Wizard {
Icon JVM = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/jvm.svg");
Icon JS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/js.svg");
Icon CONSOLE = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/console.svg");
Icon MULTIPLATFORM = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/multiplatform.svg");
Icon MULTIPLATFORM_LIBRARY = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/multiplatformLibrary.svg");
Icon MULTIPLATFORM_MOBILE = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/multiplatformMobile.svg");
Icon MULTIPLATFORM_MOBILE_LIBRARY = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/multiplatformMobileLibrary.svg");
Icon NATIVE = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/native.svg");
Icon WEB = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/ppWeb.svg");
Icon ANDROID = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/android.svg");
Icon IOS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/ios.svg");
Icon LINUX = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/linux.svg");
Icon MAC_OS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/macOS.svg");
Icon WINDOWS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/windows.svg");
Icon NODE_JS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/nodejs.svg");
Icon REACT_JS = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/react.svg");
Icon COMPOSE = IconLoader.getIcon("/org/jetbrains/kotlin/idea/icons/wizard/compose.svg");
}
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright 2010-2020 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.idea
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.PropertyKey
import org.jetbrains.kotlin.util.AbstractKotlinBundle
@NonNls
private const val BUNDLE = "messages.KotlinIdeaAnalysisBundle"
object KotlinIdeaAnalysisBundle : AbstractKotlinBundle(BUNDLE) {
@JvmStatic
fun message(@NonNls @PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String = getMessage(key, *params)
@JvmStatic
fun htmlMessage(@NonNls @PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): String =
getMessage(key, *params).withHtml()
@JvmStatic
fun lazyMessage(@PropertyKey(resourceBundle = BUNDLE) key: String, vararg params: Any): () -> String = { getMessage(key, *params) }
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright 2010-2019 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.idea
import com.intellij.ide.plugins.IdeaPluginDescriptor
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.extensions.PluginId
import java.io.File
object KotlinPluginUtil {
private class KotlinPluginInfo(val id: PluginId, val version: String, val path: File) {
constructor(plugin: IdeaPluginDescriptor) : this(plugin.pluginId, plugin.version, plugin.path)
}
private val KNOWN_KOTLIN_PLUGIN_IDS = listOf(
"org.jetbrains.kotlin",
"org.jetbrains.kotlin.native.clion",
"org.jetbrains.kotlin.native.appcode"
)
private val KOTLIN_PLUGIN_INFO: KotlinPluginInfo by lazy {
val plugin = PluginManagerCore.getPlugins().firstOrNull { it.pluginId.idString in KNOWN_KOTLIN_PLUGIN_IDS }
?: error("Kotlin plugin not found: " + PluginManagerCore.getPlugins().contentToString())
KotlinPluginInfo(plugin)
}
val KOTLIN_PLUGIN_ID: PluginId
get() = KOTLIN_PLUGIN_INFO.id
private const val PATCHED_PLUGIN_VERSION_KEY = "kotlin.plugin.version"
private val PATCHED_PLUGIN_VERSION: String? = System.getProperty(PATCHED_PLUGIN_VERSION_KEY, null)
@JvmStatic
fun getPluginVersion(): String {
if (PATCHED_PLUGIN_VERSION != null) {
assert(isPatched())
return PATCHED_PLUGIN_VERSION
}
@Suppress("DEPRECATION")
return getPluginVersionFromIdea()
}
@Deprecated("This method returns original plugin version. Please use getPluginVersion() instead.")
@JvmStatic
fun getPluginVersionFromIdea(): String {
return KOTLIN_PLUGIN_INFO.version
}
@JvmStatic
fun isPatched(): Boolean {
return PATCHED_PLUGIN_VERSION != null
}
@JvmStatic
fun isSnapshotVersion(): Boolean {
return "@snapshot@" == getPluginVersion()
}
fun isDevVersion(): Boolean {
return getPluginVersion().contains("-dev-")
}
fun getPluginPath(): File {
return KOTLIN_PLUGIN_INFO.path
}
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.api.fe10.impl
import org.jetbrains.kotlin.idea.api.ResolveAllowanceService
class ResolveAllowanceServiceFE10Impl: ResolveAllowanceService() {
override fun switchOnAllowingResolveInEdtInCurrentThread(): SwitchResult {
return SwitchResult.ALREADY_SWITCHED
}
override fun isResolveOnEdtInCurrentThreadAllowed(): Boolean = true
override fun switchOffAllowingResolveInEdtInCurrentThread() {}
override fun switchOnForbidResolveInCurrentThread(actionName: String): SwitchResult {
return SwitchResult.ALREADY_SWITCHED
}
override fun switchOffForbidResolveInCurrentThread() {
}
override fun getResolveInCurrentThreadForbiddenReason(): String? = null
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.caches
import com.intellij.openapi.vfs.VirtualFile
import java.io.DataInput
import java.io.DataOutput
data class CachedAttributeData<out T>(val value: T, val timeStamp: Long)
interface FileAttributeService {
fun register(id: String, version: Int, fixedSize: Boolean = true) {}
fun <T : Enum<T>> writeEnumAttribute(id: String, file: VirtualFile, value: T): CachedAttributeData<T> =
CachedAttributeData(value, timeStamp = file.timeStamp)
fun <T : Enum<T>> readEnumAttribute(id: String, file: VirtualFile, klass: Class<T>): CachedAttributeData<T>? = null
fun writeBooleanAttribute(id: String, file: VirtualFile, value: Boolean): CachedAttributeData<Boolean> =
CachedAttributeData(value, timeStamp = file.timeStamp)
fun readBooleanAttribute(id: String, file: VirtualFile): CachedAttributeData<Boolean>? = null
fun <T> write(file: VirtualFile, id: String, value: T, writeValueFun: (DataOutput, T) -> Unit): CachedAttributeData<T>
fun <T> read(file: VirtualFile, id: String, readValueFun: (DataInput) -> T): CachedAttributeData<T>?
}

View File

@@ -1,140 +0,0 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.caches
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.components.service
import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileWithId
import com.intellij.reference.SoftReference
import org.jetbrains.kotlin.load.kotlin.KotlinBinaryClassCache
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
import org.jetbrains.kotlin.name.ClassId
class IDEKotlinBinaryClassCache {
class KotlinBinaryClassHeaderData(
val classId: ClassId,
val kind: KotlinClassHeader.Kind,
val metadataVersion: JvmMetadataVersion,
val partNamesIfMultifileFacade: List<String>,
val packageName: String?
)
data class KotlinBinaryData(val isKotlinBinary: Boolean, val timestamp: Long, val headerData: KotlinBinaryClassHeaderData?)
/**
* Checks if this file is a compiled Kotlin class file (not necessarily ABI-compatible with the current plugin)
*/
fun isKotlinJvmCompiledFile(file: VirtualFile, fileContent: ByteArray? = null): Boolean {
if (file.extension != JavaClassFileType.INSTANCE!!.defaultExtension) {
return false
}
val cached = getKotlinBinaryFromCache(file)
if (cached != null) {
return cached.isKotlinBinary
}
return getKotlinBinaryClass(file, fileContent) != null
}
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
val cached = getKotlinBinaryFromCache(file)
if (cached != null && !cached.isKotlinBinary) {
return null
}
val kotlinBinaryClass = KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file, fileContent)?.toKotlinJvmBinaryClass()
val isKotlinBinaryClass = kotlinBinaryClass != null
if (file is VirtualFileWithId) {
attributeService.writeBooleanAttribute(KOTLIN_IS_COMPILED_FILE_ATTRIBUTE, file, isKotlinBinaryClass)
}
if (isKotlinBinaryClass) {
val headerInfo = createHeaderInfo(kotlinBinaryClass)
file.putUserData(KOTLIN_BINARY_DATA_KEY, SoftReference(KotlinBinaryData(isKotlinBinaryClass, file.timeStamp, headerInfo)))
}
return kotlinBinaryClass
}
fun getKotlinBinaryClassHeaderData(file: VirtualFile, fileContent: ByteArray? = null): KotlinBinaryClassHeaderData? {
val cached = getKotlinBinaryFromCache(file)
if (cached != null) {
if (!cached.isKotlinBinary) {
return null
}
if (cached.headerData != null) {
return cached.headerData
}
}
val kotlinBinaryClass = getKotlinBinaryClass(file, fileContent)
return createHeaderInfo(kotlinBinaryClass)
}
private val attributeService = ServiceManager.getService(FileAttributeService::class.java)
private fun createHeaderInfo(kotlinBinaryClass: KotlinJvmBinaryClass?): KotlinBinaryClassHeaderData? {
val classId = kotlinBinaryClass?.classId ?: return null
return kotlinBinaryClass.classHeader.toLightHeader(classId)
}
private fun KotlinClassHeader.toLightHeader(classId: ClassId) =
KotlinBinaryClassHeaderData(
classId, kind, metadataVersion, multifilePartNames, packageName
)
private val KOTLIN_IS_COMPILED_FILE_ATTRIBUTE: String = "kotlin-is-binary-compiled".apply {
ServiceManager.getService(FileAttributeService::class.java)?.register(this, 1)
}
private val KOTLIN_BINARY_DATA_KEY = Key.create<SoftReference<KotlinBinaryData>>(KOTLIN_IS_COMPILED_FILE_ATTRIBUTE)
private fun getKotlinBinaryFromCache(file: VirtualFile): KotlinBinaryData? {
val userData = file.getUserData(KOTLIN_BINARY_DATA_KEY)?.get()
if (userData != null && userData.timestamp == file.timeStamp) {
return userData
}
val isKotlinBinaryAttribute = if (file is VirtualFileWithId)
attributeService.readBooleanAttribute(KOTLIN_IS_COMPILED_FILE_ATTRIBUTE, file)
else
null
if (isKotlinBinaryAttribute != null) {
val isKotlinBinary = isKotlinBinaryAttribute.value
val kotlinBinaryData = KotlinBinaryData(isKotlinBinary, file.timeStamp, null)
if (isKotlinBinary) {
file.putUserData(KOTLIN_BINARY_DATA_KEY, SoftReference(kotlinBinaryData))
}
return kotlinBinaryData
}
return null
}
companion object {
fun getInstance(): IDEKotlinBinaryClassCache = service()
}
}

View File

@@ -1,348 +0,0 @@
/*
* Copyright 2010-2019 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.idea.caches
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMethod
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.PsiShortNamesCache
import com.intellij.psi.stubs.StubIndex
import com.intellij.util.ArrayUtil
import com.intellij.util.Processor
import com.intellij.util.Processors
import com.intellij.util.containers.ContainerUtil
import com.intellij.util.indexing.IdFilter
import gnu.trove.THashSet
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.defaultImplsChild
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.asJava.getAccessorLightMethods
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType
import org.jetbrains.kotlin.idea.stubindex.*
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.getPropertyNamesCandidatesByAccessorName
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
class KotlinShortNamesCache(private val project: Project) : PsiShortNamesCache() {
companion object {
private val LOG = Logger.getInstance(KotlinShortNamesCache::class.java)
}
//hacky way to avoid searches for Kotlin classes, when looking for Java (from Kotlin)
val disableSearch: ThreadLocal<Boolean> = object : ThreadLocal<Boolean>() {
override fun initialValue(): Boolean = false
}
//region Classes
override fun processAllClassNames(processor: Processor<in String>): Boolean {
if (disableSearch.get()) return true
return KotlinClassShortNameIndex.getInstance().processAllKeys(project, processor) &&
KotlinFileFacadeShortNameIndex.INSTANCE.processAllKeys(project, processor)
}
override fun processAllClassNames(processor: Processor<in String>, scope: GlobalSearchScope, filter: IdFilter?): Boolean {
if (disableSearch.get()) return true
return processAllClassNames(processor)
}
/**
* Return kotlin class names from project sources which should be visible from java.
*/
override fun getAllClassNames(): Array<String> {
if (disableSearch.get()) return ArrayUtil.EMPTY_STRING_ARRAY
return withArrayProcessor(ArrayUtil.EMPTY_STRING_ARRAY) { processor ->
processAllClassNames(processor)
}
}
override fun processClassesWithName(
name: String,
processor: Processor<in PsiClass>,
scope: GlobalSearchScope,
filter: IdFilter?
): Boolean {
if (disableSearch.get()) return true
val effectiveScope = kotlinDeclarationsVisibleFromJavaScope(scope)
val fqNameProcessor = Processor<FqName> { fqName: FqName? ->
if (fqName == null) return@Processor true
val isInterfaceDefaultImpl = name == JvmAbi.DEFAULT_IMPLS_CLASS_NAME && fqName.shortName().asString() != name
if (fqName.shortName().asString() != name && !isInterfaceDefaultImpl) {
LOG.error(
"A declaration obtained from index has non-matching name:" +
"\nin index: $name" +
"\ndeclared: ${fqName.shortName()}($fqName)"
)
return@Processor true
}
val fqNameToSearch = if (isInterfaceDefaultImpl) fqName.defaultImplsChild() else fqName
val psiClass = JavaElementFinder.getInstance(project).findClass(fqNameToSearch.asString(), effectiveScope)
?: return@Processor true
return@Processor processor.process(psiClass)
}
val allKtClassOrObjectsProcessed = StubIndex.getInstance().processElements(
KotlinClassShortNameIndex.getInstance().key,
name,
project,
effectiveScope,
filter,
KtClassOrObject::class.java
) { ktClassOrObject ->
fqNameProcessor.process(ktClassOrObject.fqName)
}
if (!allKtClassOrObjectsProcessed) {
return false
}
return StubIndex.getInstance().processElements(
KotlinFileFacadeShortNameIndex.getInstance().key,
name,
project,
effectiveScope,
filter,
KtFile::class.java
) { ktFile ->
fqNameProcessor.process(ktFile.javaFileFacadeFqName)
}
}
/**
* Return class names form kotlin sources in given scope which should be visible as Java classes.
*/
override fun getClassesByName(name: String, scope: GlobalSearchScope): Array<PsiClass> {
if (disableSearch.get()) return PsiClass.EMPTY_ARRAY
return withArrayProcessor(PsiClass.EMPTY_ARRAY) { processor ->
processClassesWithName(name, processor, scope, null)
}
}
private fun kotlinDeclarationsVisibleFromJavaScope(scope: GlobalSearchScope): GlobalSearchScope {
val noBuiltInsScope: GlobalSearchScope = object : GlobalSearchScope(project) {
override fun isSearchInModuleContent(aModule: Module) = true
override fun compare(file1: VirtualFile, file2: VirtualFile) = 0
override fun isSearchInLibraries() = true
override fun contains(file: VirtualFile) = file.fileType != KotlinBuiltInFileType
}
return KotlinSourceFilterScope.sourceAndClassFiles(scope, project).intersectWith(noBuiltInsScope)
}
//endregion
//region Methods
override fun processAllMethodNames(
processor: Processor<in String>,
scope: GlobalSearchScope,
filter: IdFilter?
): Boolean {
if (disableSearch.get()) return true
return processAllMethodNames(processor)
}
override fun getAllMethodNames(): Array<String> {
if (disableSearch.get()) ArrayUtil.EMPTY_STRING_ARRAY
return withArrayProcessor(ArrayUtil.EMPTY_STRING_ARRAY) { processor ->
processAllMethodNames(processor)
}
}
private fun processAllMethodNames(processor: Processor<in String>): Boolean {
if (disableSearch.get()) return true
if (!KotlinFunctionShortNameIndex.getInstance().processAllKeys(project, processor)) {
return false
}
return KotlinPropertyShortNameIndex.getInstance().processAllKeys(project) { name ->
return@processAllKeys processor.process(JvmAbi.setterName(name)) && processor.process(JvmAbi.getterName(name))
}
}
override fun processMethodsWithName(
name: String,
processor: Processor<in PsiMethod>,
scope: GlobalSearchScope,
filter: IdFilter?
): Boolean {
if (disableSearch.get()) return true
val allFunctionsProcessed = StubIndex.getInstance().processElements(
KotlinFunctionShortNameIndex.getInstance().key,
name,
project,
scope,
filter,
KtNamedFunction::class.java
) { ktNamedFunction ->
val methods = LightClassUtil.getLightClassMethodsByName(ktNamedFunction, name)
return@processElements methods.all { method ->
processor.process(method)
}
}
if (!allFunctionsProcessed) {
return false
}
for (propertyName in getPropertyNamesCandidatesByAccessorName(Name.identifier(name))) {
val allProcessed = StubIndex.getInstance().processElements(
KotlinPropertyShortNameIndex.getInstance().key,
propertyName.asString(),
project,
scope,
filter,
KtNamedDeclaration::class.java
) { ktNamedDeclaration ->
val methods: Sequence<PsiMethod> = ktNamedDeclaration.getAccessorLightMethods()
.asSequence()
.filter { it.name == name }
return@processElements methods.all { method ->
processor.process(method)
}
}
if (!allProcessed) {
return false
}
}
return true
}
override fun getMethodsByName(name: String, scope: GlobalSearchScope): Array<PsiMethod> {
if (disableSearch.get()) return PsiMethod.EMPTY_ARRAY
return withArrayProcessor(PsiMethod.EMPTY_ARRAY) { processor ->
processMethodsWithName(name, processor, scope, null)
}
}
override fun getMethodsByNameIfNotMoreThan(name: String, scope: GlobalSearchScope, maxCount: Int): Array<PsiMethod> {
if (disableSearch.get()) return PsiMethod.EMPTY_ARRAY
require(maxCount >= 0)
return withArrayProcessor(PsiMethod.EMPTY_ARRAY) { processor ->
processMethodsWithName(
name,
{ psiMethod ->
processor.size != maxCount && processor.process(psiMethod)
},
scope,
null
)
}
}
override fun processMethodsWithName(
name: String,
scope: GlobalSearchScope,
processor: Processor<in PsiMethod>
): Boolean {
if (disableSearch.get()) return true
return ContainerUtil.process(getMethodsByName(name, scope), processor)
}
//endregion
//region Fields
override fun processAllFieldNames(processor: Processor<in String>, scope: GlobalSearchScope, filter: IdFilter?): Boolean {
if (disableSearch.get()) return true
return processAllFieldNames(processor)
}
override fun getAllFieldNames(): Array<String> {
if (disableSearch.get()) return ArrayUtil.EMPTY_STRING_ARRAY
return withArrayProcessor(ArrayUtil.EMPTY_STRING_ARRAY) { processor ->
processAllFieldNames(processor)
}
}
private fun processAllFieldNames(processor: Processor<in String>): Boolean {
if (disableSearch.get()) return true
return KotlinPropertyShortNameIndex.getInstance().processAllKeys(project, processor)
}
override fun processFieldsWithName(
name: String,
processor: Processor<in PsiField>,
scope: GlobalSearchScope,
filter: IdFilter?
): Boolean {
if (disableSearch.get()) return true
return StubIndex.getInstance().processElements(
KotlinPropertyShortNameIndex.getInstance().key,
name,
project,
scope,
filter,
KtNamedDeclaration::class.java
) { ktNamedDeclaration ->
val field = LightClassUtil.getLightClassBackingField(ktNamedDeclaration)
?: return@processElements true
return@processElements processor.process(field)
}
}
override fun getFieldsByName(name: String, scope: GlobalSearchScope): Array<PsiField> {
if (disableSearch.get()) return PsiField.EMPTY_ARRAY
return withArrayProcessor(PsiField.EMPTY_ARRAY) { processor ->
processFieldsWithName(name, processor, scope, null)
}
}
override fun getFieldsByNameIfNotMoreThan(name: String, scope: GlobalSearchScope, maxCount: Int): Array<PsiField> {
if (disableSearch.get()) return PsiField.EMPTY_ARRAY
require(maxCount >= 0)
return withArrayProcessor(PsiField.EMPTY_ARRAY) { processor ->
processFieldsWithName(
name,
{ psiField ->
processor.size != maxCount && processor.process(psiField)
},
scope,
null
)
}
}
//endregion
private inline fun <T> withArrayProcessor(
result: Array<T>,
process: (CancelableArrayCollectProcessor<T>) -> Unit
): Array<T> {
return CancelableArrayCollectProcessor<T>().also { processor ->
process(processor)
}.toArray(result)
}
private class CancelableArrayCollectProcessor<T> : Processor<T> {
val troveSet = THashSet<T>()
private val processor = Processors.cancelableCollectProcessor<T>(troveSet)
override fun process(value: T): Boolean {
return processor.process(value)
}
val size: Int get() = troveSet.size
fun toArray(a: Array<T>): Array<T> = troveSet.toArray(a)
}
}

View File

@@ -1,418 +0,0 @@
/*
* Copyright 2000-2019 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.idea.caches
import com.intellij.ProjectTopics
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.module.Module
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.rootManager
import com.intellij.openapi.roots.ModuleRootEvent
import com.intellij.openapi.roots.ModuleRootListener
import com.intellij.openapi.startup.StartupActivity
import com.intellij.openapi.util.Key
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.openapi.vfs.newvfs.BulkFileListener
import com.intellij.openapi.vfs.newvfs.events.*
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.impl.PsiManagerEx
import com.intellij.psi.impl.PsiTreeChangeEventImpl
import com.intellij.psi.impl.PsiTreeChangePreprocessor
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService.Companion.DEBUG_LOG_ENABLE_PerModulePackageCache
import org.jetbrains.kotlin.idea.caches.PerModulePackageCacheService.Companion.FULL_DROP_THRESHOLD
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfoByVirtualFile
import org.jetbrains.kotlin.idea.caches.project.getNullableModuleInfo
import org.jetbrains.kotlin.idea.stubindex.PackageIndexUtil
import org.jetbrains.kotlin.idea.util.getSourceRoot
import org.jetbrains.kotlin.idea.util.sourceRoot
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPackageDirective
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
class KotlinPackageContentModificationListener : StartupActivity {
companion object {
val LOG = Logger.getInstance(this::class.java)
}
override fun runActivity(project: Project) {
val connection = project.messageBus.connect(project)
connection.subscribe(VirtualFileManager.VFS_CHANGES, object : BulkFileListener {
override fun before(events: MutableList<out VFileEvent>) = onEvents(events, false)
override fun after(events: List<VFileEvent>) = onEvents(events, true)
private fun isRelevant(event: VFileEvent): Boolean = when (event) {
is VFilePropertyChangeEvent -> false
is VFileCreateEvent -> true
is VFileMoveEvent -> true
is VFileDeleteEvent -> true
is VFileContentChangeEvent -> true
is VFileCopyEvent -> true
else -> {
LOG.warn("Unknown vfs event: ${event.javaClass}")
false
}
}
fun onEvents(events: List<VFileEvent>, isAfter: Boolean) {
val service = PerModulePackageCacheService.getInstance(project)
val fileManager = PsiManagerEx.getInstanceEx(project).fileManager
if (events.size >= FULL_DROP_THRESHOLD) {
service.onTooComplexChange()
} else {
events.asSequence()
.filter(::isRelevant)
.filter {
(it.isValid || it !is VFileCreateEvent) && it.file != null
}
.filter {
val vFile = it.file!!
vFile.isDirectory || vFile.fileType == KotlinFileType.INSTANCE
}
.filter {
// It expected that content change events will be duplicated with more precise PSI events and processed
// in KotlinPackageStatementPsiTreeChangePreprocessor, but events might have been missing if PSI view provider
// is absent.
if (it is VFileContentChangeEvent) {
isAfter && fileManager.findCachedViewProvider(it.file) == null
} else {
true
}
}
.filter {
when (val origin = it.requestor) {
is Project -> origin == project
is PsiManager -> origin.project == project
else -> true
}
}
.forEach { event -> service.notifyPackageChange(event) }
}
}
})
connection.subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener {
override fun rootsChanged(event: ModuleRootEvent) {
PerModulePackageCacheService.getInstance(project).onTooComplexChange()
}
})
}
}
class KotlinPackageStatementPsiTreeChangePreprocessor(private val project: Project) : PsiTreeChangePreprocessor {
override fun treeChanged(event: PsiTreeChangeEventImpl) {
val eFile = event.file ?: event.child as? PsiFile
if (eFile == null) {
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without file" }
}
val file = eFile as? KtFile ?: return
when (event.code) {
PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED,
PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED,
PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED,
PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED -> {
val child = event.child ?: run {
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without child" }
return
}
if (child.getParentOfType<KtPackageDirective>(false) != null)
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
}
PsiTreeChangeEventImpl.PsiEventType.CHILDREN_CHANGED -> {
val parent = event.parent ?: run {
LOG.debugIfEnabled(project, true) { "Got PsiEvent: $event without parent" }
return
}
val childrenOfType = parent.getChildrenOfType<KtPackageDirective>()
if (
(!event.isGenericChange && (childrenOfType.any() || parent is KtPackageDirective)) ||
(childrenOfType.any { it.name.isEmpty() } && parent is KtFile)
) {
ServiceManager.getService(project, PerModulePackageCacheService::class.java).notifyPackageChange(file)
}
}
else -> {
}
}
}
companion object {
val LOG = Logger.getInstance(this::class.java)
}
}
private typealias ImplicitPackageData = MutableMap<FqName, MutableList<VirtualFile>>
class ImplicitPackagePrefixCache(private val project: Project) {
private val implicitPackageCache = ConcurrentHashMap<VirtualFile, ImplicitPackageData>()
fun getPrefix(sourceRoot: VirtualFile): FqName {
val implicitPackageMap = implicitPackageCache.getOrPut(sourceRoot) { analyzeImplicitPackagePrefixes(sourceRoot) }
return implicitPackageMap.keys.singleOrNull() ?: FqName.ROOT
}
internal fun clear() {
implicitPackageCache.clear()
}
private fun analyzeImplicitPackagePrefixes(sourceRoot: VirtualFile): MutableMap<FqName, MutableList<VirtualFile>> {
val result = mutableMapOf<FqName, MutableList<VirtualFile>>()
val ktFiles = sourceRoot.children.filter { it.fileType == KotlinFileType.INSTANCE }
for (ktFile in ktFiles) {
result.addFile(ktFile)
}
return result
}
private fun ImplicitPackageData.addFile(ktFile: VirtualFile) {
synchronized(this) {
val psiFile = PsiManager.getInstance(project).findFile(ktFile) as? KtFile ?: return
addPsiFile(psiFile, ktFile)
}
}
private fun ImplicitPackageData.addPsiFile(
psiFile: KtFile,
ktFile: VirtualFile
) = getOrPut(psiFile.packageFqName) { mutableListOf() }.add(ktFile)
private fun ImplicitPackageData.removeFile(file: VirtualFile) {
synchronized(this) {
for ((key, value) in this) {
if (value.remove(file)) {
if (value.isEmpty()) remove(key)
break
}
}
}
}
private fun ImplicitPackageData.updateFile(file: KtFile) {
synchronized(this) {
removeFile(file.virtualFile)
addPsiFile(file, file.virtualFile)
}
}
internal fun update(event: VFileEvent) {
when (event) {
is VFileCreateEvent -> checkNewFileInSourceRoot(event.file)
is VFileDeleteEvent -> checkDeletedFileInSourceRoot(event.file)
is VFileCopyEvent -> {
val newParent = event.newParent
if (newParent.isValid) {
checkNewFileInSourceRoot(newParent.findChild(event.newChildName))
}
}
is VFileMoveEvent -> {
checkNewFileInSourceRoot(event.file)
if (event.oldParent.getSourceRoot(project) == event.oldParent) {
implicitPackageCache[event.oldParent]?.removeFile(event.file)
}
}
}
}
private fun checkNewFileInSourceRoot(file: VirtualFile?) {
if (file == null) return
if (file.getSourceRoot(project) == file.parent) {
implicitPackageCache[file.parent]?.addFile(file)
}
}
private fun checkDeletedFileInSourceRoot(file: VirtualFile?) {
val directory = file?.parent
if (directory == null || !directory.isValid) return
if (directory.getSourceRoot(project) == directory) {
implicitPackageCache[directory]?.removeFile(file)
}
}
internal fun update(ktFile: KtFile) {
val parent = ktFile.virtualFile?.parent ?: return
if (ktFile.sourceRoot == parent) {
implicitPackageCache[parent]?.updateFile(ktFile)
}
}
}
class PerModulePackageCacheService(private val project: Project) : Disposable {
/*
* Actually an WeakMap<Module, SoftMap<ModuleSourceInfo, SoftMap<FqName, Boolean>>>
*/
private val cache = ContainerUtil.createConcurrentWeakMap<Module, ConcurrentMap<ModuleSourceInfo, ConcurrentMap<FqName, Boolean>>>()
private val implicitPackagePrefixCache = ImplicitPackagePrefixCache(project)
private val pendingVFileChanges: MutableSet<VFileEvent> = mutableSetOf()
private val pendingKtFileChanges: MutableSet<KtFile> = mutableSetOf()
private val projectScope = GlobalSearchScope.projectScope(project)
internal fun onTooComplexChange() {
clear()
}
private fun clear() {
synchronized(this) {
pendingVFileChanges.clear()
pendingKtFileChanges.clear()
cache.clear()
implicitPackagePrefixCache.clear()
}
}
internal fun notifyPackageChange(file: VFileEvent): Unit = synchronized(this) {
pendingVFileChanges += file
}
internal fun notifyPackageChange(file: KtFile): Unit = synchronized(this) {
pendingKtFileChanges += file
}
private fun invalidateCacheForModuleSourceInfo(moduleSourceInfo: ModuleSourceInfo) {
LOG.debugIfEnabled(project) { "Invalidated cache for $moduleSourceInfo" }
val perSourceInfoData = cache[moduleSourceInfo.module] ?: return
val dataForSourceInfo = perSourceInfoData[moduleSourceInfo] ?: return
dataForSourceInfo.clear()
}
private fun checkPendingChanges() = synchronized(this) {
if (pendingVFileChanges.size + pendingKtFileChanges.size >= FULL_DROP_THRESHOLD) {
onTooComplexChange()
} else {
pendingVFileChanges.processPending { event ->
val vfile = event.file ?: return@processPending
// When VirtualFile !isValid (deleted for example), it impossible to use getModuleInfoByVirtualFile
// For directory we must check both is it in some sourceRoot, and is it contains some sourceRoot
if (vfile.isDirectory || !vfile.isValid) {
for ((module, data) in cache) {
val sourceRootUrls = module.rootManager.sourceRootUrls
if (sourceRootUrls.any { url ->
vfile.containedInOrContains(url)
}) {
LOG.debugIfEnabled(project) { "Invalidated cache for $module" }
data.clear()
}
}
} else {
val infoByVirtualFile = getModuleInfoByVirtualFile(project, vfile)
if (infoByVirtualFile == null || infoByVirtualFile !is ModuleSourceInfo) {
LOG.debugIfEnabled(project) { "Skip $vfile as it has mismatched ModuleInfo=$infoByVirtualFile" }
}
(infoByVirtualFile as? ModuleSourceInfo)?.let {
invalidateCacheForModuleSourceInfo(it)
}
}
implicitPackagePrefixCache.update(event)
}
pendingKtFileChanges.processPending { file ->
if (file.virtualFile != null && file.virtualFile !in projectScope) {
LOG.debugIfEnabled(project) {
"Skip $file without vFile, or not in scope: ${file.virtualFile?.let { it !in projectScope }}"
}
return@processPending
}
val nullableModuleInfo = file.getNullableModuleInfo()
(nullableModuleInfo as? ModuleSourceInfo)?.let { invalidateCacheForModuleSourceInfo(it) }
if (nullableModuleInfo == null || nullableModuleInfo !is ModuleSourceInfo) {
LOG.debugIfEnabled(project) { "Skip $file as it has mismatched ModuleInfo=$nullableModuleInfo" }
}
implicitPackagePrefixCache.update(file)
}
}
}
private inline fun <T> MutableCollection<T>.processPending(crossinline body: (T) -> Unit) {
this.removeIf { value ->
try {
body(value)
} catch (pce: ProcessCanceledException) {
throw pce
} catch (exc: Exception) {
// Log and proceed. Otherwise pending object processing won't be cleared and exception will be thrown forever.
LOG.error(exc)
}
return@removeIf true
}
}
private fun VirtualFile.containedInOrContains(root: String) =
(VfsUtilCore.isEqualOrAncestor(url, root)
|| isDirectory && VfsUtilCore.isEqualOrAncestor(root, url))
fun packageExists(packageFqName: FqName, moduleInfo: ModuleSourceInfo): Boolean {
val module = moduleInfo.module
checkPendingChanges()
val perSourceInfoCache = cache.getOrPut(module) {
ContainerUtil.createConcurrentSoftMap()
}
val cacheForCurrentModuleInfo = perSourceInfoCache.getOrPut(moduleInfo) {
ContainerUtil.createConcurrentSoftMap()
}
return cacheForCurrentModuleInfo.getOrPut(packageFqName) {
val packageExists = PackageIndexUtil.packageExists(packageFqName, moduleInfo.contentScope(), project)
LOG.debugIfEnabled(project) { "Computed cache value for $packageFqName in $moduleInfo is $packageExists" }
packageExists
}
}
fun getImplicitPackagePrefix(sourceRoot: VirtualFile): FqName {
checkPendingChanges()
return implicitPackagePrefixCache.getPrefix(sourceRoot)
}
override fun dispose() {
clear()
}
companion object {
const val FULL_DROP_THRESHOLD = 1000
private val LOG = Logger.getInstance(this::class.java)
fun getInstance(project: Project): PerModulePackageCacheService =
ServiceManager.getService(project, PerModulePackageCacheService::class.java)
var Project.DEBUG_LOG_ENABLE_PerModulePackageCache: Boolean
by NotNullableUserDataProperty<Project, Boolean>(Key.create("debug.PerModulePackageCache"), false)
}
}
private fun Logger.debugIfEnabled(project: Project, withCurrentTrace: Boolean = false, message: () -> String) {
if (ApplicationManager.getApplication().isUnitTestMode && project.DEBUG_LOG_ENABLE_PerModulePackageCache) {
val msg = message()
if (withCurrentTrace) {
val e = Exception().apply { fillInStackTrace() }
this.debug(msg, e)
} else {
this.debug(msg)
}
}
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.caches.lightClasses
import com.intellij.ide.highlighter.JavaClassFileType
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.impl.compiled.ClsFileImpl
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl
import com.intellij.util.cls.ClsFormatException
import com.intellij.util.containers.ContainerUtil
import java.io.IOException
class ClsJavaStubByVirtualFileCache {
private class CachedJavaStub(val modificationStamp: Long, val javaFileStub: PsiJavaFileStubImpl)
private val cache = ContainerUtil.createConcurrentWeakKeySoftValueMap<VirtualFile, CachedJavaStub>()
fun get(classFile: VirtualFile): PsiJavaFileStubImpl? {
val cached = cache.get(classFile)
val fileModificationStamp = classFile.modificationStamp
if (cached != null && cached.modificationStamp == fileModificationStamp) {
return cached.javaFileStub
}
val stub = createStub(classFile) as PsiJavaFileStubImpl? ?: return null
cache.put(classFile, CachedJavaStub(fileModificationStamp, stub))
return stub
}
private fun createStub(file: VirtualFile): PsiJavaFileStub? {
if (file.fileType !== JavaClassFileType.INSTANCE) return null
try {
return ClsFileImpl.buildFileStub(file, file.contentsToByteArray(false))
} catch (e: ClsFormatException) {
LOG.error("Failed to build java cls class for " + file.canonicalPath!!, e)
} catch (e: IOException) {
LOG.error("Failed to build java cls class for " + file.canonicalPath!!, e)
}
return null
}
companion object {
private val LOG = Logger.getInstance(ClsJavaStubByVirtualFileCache::class.java)
fun getInstance(project: Project): ClsJavaStubByVirtualFileCache {
return ServiceManager.getService(project, ClsJavaStubByVirtualFileCache::class.java)
}
}
}

View File

@@ -1,469 +0,0 @@
/*
* Copyright 2010-2019 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.idea.caches.lightClasses
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.project.Project
import com.intellij.psi.search.EverythingGlobalScope
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StubIndex
import org.jetbrains.kotlin.asJava.builder.LightClassConstructionContext
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.container.useImpl
import org.jetbrains.kotlin.container.useInstance
import org.jetbrains.kotlin.context.ModuleContext
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.CompositePackageFragmentProvider
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.frontend.di.configureModule
import org.jetbrains.kotlin.idea.FrontendInternals
import org.jetbrains.kotlin.idea.caches.lightClasses.IDELightClassConstructionContext.Mode.EXACT
import org.jetbrains.kotlin.idea.caches.lightClasses.IDELightClassConstructionContext.Mode.LIGHT
import org.jetbrains.kotlin.idea.caches.lightClasses.annotations.KOTLINX_SERIALIZABLE_FQ_NAME
import org.jetbrains.kotlin.idea.caches.lightClasses.annotations.KOTLINX_SERIALIZER_FQ_NAME
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider
import org.jetbrains.kotlin.idea.project.IdeaEnvironment
import org.jetbrains.kotlin.idea.project.ResolveElementCache
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.stubindex.KotlinOverridableInternalMembersShortNameIndex
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import org.jetbrains.kotlin.resolve.*
import org.jetbrains.kotlin.resolve.calls.CallResolver
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
import org.jetbrains.kotlin.resolve.calls.context.CheckArgumentTypesMode
import org.jetbrains.kotlin.resolve.calls.context.ContextDependency
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.util.CallMaker
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.resolve.lazy.FileScopeProviderImpl
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
import org.jetbrains.kotlin.resolve.lazy.ResolveSession
import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory
import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.WrappedTypeFactory
import org.jetbrains.kotlin.utils.sure
class IDELightClassConstructionContext(
bindingContext: BindingContext,
module: ModuleDescriptor,
languageVersionSettings: LanguageVersionSettings,
jvmTarget: JvmTarget,
val mode: Mode
) : LightClassConstructionContext(bindingContext, module, languageVersionSettings, jvmTarget) {
enum class Mode {
LIGHT,
EXACT
}
override fun toString() = "${this.javaClass.simpleName}:$mode"
}
internal object IDELightClassContexts {
private val LOG = Logger.getInstance(this::class.java)
fun contextForNonLocalClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
val resolutionFacade = classOrObject.getResolutionFacade()
val bindingContext = if (classOrObject is KtClass && classOrObject.isAnnotation()) {
// need to make sure default values for parameters are resolved
// because java resolve depends on whether there is a default value for an annotation attribute
@OptIn(FrontendInternals::class)
resolutionFacade.getFrontendService(ResolveElementCache::class.java)
.resolvePrimaryConstructorParametersDefaultValues(classOrObject)
} else {
resolutionFacade.analyze(classOrObject)
}
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject).sure {
"Class descriptor was not found for ${classOrObject.getElementTextWithContext()}"
}
ForceResolveUtil.forceResolveAllContents(classDescriptor)
return IDELightClassConstructionContext(
bindingContext,
resolutionFacade.moduleDescriptor,
classOrObject.languageVersionSettings,
resolutionFacade.jvmTarget,
EXACT
)
}
fun contextForLocalClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext {
val resolutionFacade = classOrObject.getResolutionFacade()
val bindingContext = resolutionFacade.analyze(classOrObject)
val descriptor = bindingContext.get(BindingContext.CLASS, classOrObject)
if (descriptor == null) {
LOG.warn("No class descriptor in context for class: " + classOrObject.getElementTextWithContext())
return IDELightClassConstructionContext(
bindingContext,
resolutionFacade.moduleDescriptor,
classOrObject.languageVersionSettings,
resolutionFacade.jvmTarget,
EXACT
)
}
ForceResolveUtil.forceResolveAllContents(descriptor)
return IDELightClassConstructionContext(
bindingContext,
resolutionFacade.moduleDescriptor,
classOrObject.languageVersionSettings,
resolutionFacade.jvmTarget,
EXACT
)
}
fun contextForFacade(files: List<KtFile>): LightClassConstructionContext {
val resolutionFacade = files.first().getResolutionFacade()
@OptIn(FrontendInternals::class)
val resolveSession = resolutionFacade.getFrontendService(ResolveSession::class.java)
forceResolvePackageDeclarations(files, resolveSession)
return IDELightClassConstructionContext(
resolveSession.bindingContext,
resolveSession.moduleDescriptor,
files.first().languageVersionSettings,
resolutionFacade.jvmTarget,
EXACT
)
}
fun contextForScript(script: KtScript): LightClassConstructionContext {
val resolutionFacade = script.getResolutionFacade()
val bindingContext = resolutionFacade.analyze(script)
val descriptor = bindingContext[BindingContext.SCRIPT, script]
if (descriptor == null) {
LOG.warn("No script descriptor in context for script: " + script.getElementTextWithContext())
return IDELightClassConstructionContext(
bindingContext,
resolutionFacade.moduleDescriptor,
script.languageVersionSettings,
resolutionFacade.jvmTarget,
EXACT
)
}
ForceResolveUtil.forceResolveAllContents(descriptor)
return IDELightClassConstructionContext(
bindingContext, resolutionFacade.moduleDescriptor, script.languageVersionSettings, resolutionFacade.jvmTarget,
EXACT
)
}
fun lightContextForClassOrObject(classOrObject: KtClassOrObject): LightClassConstructionContext? {
if (!isDummyResolveApplicable(classOrObject)) return null
val resolutionFacade = classOrObject.getResolutionFacade()
val resolveSession = setupAdHocResolve(
classOrObject.project,
resolutionFacade.moduleDescriptor,
listOf(classOrObject.containingKtFile)
)
val descriptor = resolveSession.resolveToDescriptor(classOrObject) as? ClassDescriptor ?: return null
if (!isDummyResolveApplicableByDescriptor(descriptor)) return null
ForceResolveUtil.forceResolveAllContents(descriptor)
return IDELightClassConstructionContext(
resolveSession.bindingContext,
resolveSession.moduleDescriptor,
classOrObject.languageVersionSettings,
resolutionFacade.jvmTarget,
LIGHT
)
}
fun lightContextForFacade(files: List<KtFile>): LightClassConstructionContext {
val representativeFile = files.first()
val resolutionFacade = representativeFile.getResolutionFacade()
val resolveSession = setupAdHocResolve(representativeFile.project, resolutionFacade.moduleDescriptor, files)
forceResolvePackageDeclarations(files, resolveSession)
return IDELightClassConstructionContext(
resolveSession.bindingContext,
resolveSession.moduleDescriptor,
files.first().languageVersionSettings,
resolutionFacade.jvmTarget,
LIGHT
)
}
@OptIn(FrontendInternals::class)
private val ResolutionFacade.jvmTarget: JvmTarget
get() = getFrontendService(JvmTarget::class.java)
private fun isDummyResolveApplicable(classOrObject: KtClassOrObject): Boolean {
if (classOrObject.hasModifier(KtTokens.INLINE_KEYWORD)) return false
if (classOrObject.hasLightClassMatchingErrors) return false
if (hasDelegatedSupertypes(classOrObject)) return false
if (isDataClassWithGeneratedMembersOverridden(classOrObject)) return false
if (isDataClassWhichExtendsOtherClass(classOrObject)) return false
if (hasMembersOverridingInternalMembers(classOrObject)) return false
if (hasSerializationLikeAnnotations(classOrObject)) return false
if (hasJvmSyntheticMembers(classOrObject)) return false
return classOrObject.declarations.filterIsInstance<KtClassOrObject>().all { isDummyResolveApplicable(it) }
}
private fun hasSerializationLikeAnnotations(classOrObject: KtClassOrObject) =
classOrObject.annotationEntries.any { isSerializableOrSerializerShortName(it.shortName) }
private fun isDummyResolveApplicableByDescriptor(classDescriptor: ClassDescriptor): Boolean {
if (classDescriptor.annotations.any { isSerializableOrSerializerFqName(it.fqName) }) return false
return classDescriptor
.unsubstitutedInnerClassesScope
.getContributedDescriptors()
.filterIsInstance<ClassDescriptor>()
.all(::isDummyResolveApplicableByDescriptor)
}
private fun isSerializableOrSerializerShortName(shortName: Name?) =
shortName == KOTLINX_SERIALIZABLE_FQ_NAME.shortName() || shortName == KOTLINX_SERIALIZER_FQ_NAME.shortName()
private fun isSerializableOrSerializerFqName(fqName: FqName?) =
fqName == KOTLINX_SERIALIZABLE_FQ_NAME || fqName == KOTLINX_SERIALIZER_FQ_NAME
private fun hasJvmSyntheticMembers(classOrObject: KtClassOrObject) =
classOrObject.declarations.filterIsInstance<KtFunction>().any { isJvmSynthetic(it) }
private fun isJvmSynthetic(fn: KtFunction) =
fn.annotationEntries.any { it.shortName == JVM_SYNTHETIC_ANNOTATION_FQ_NAME.shortName() }
private fun hasDelegatedSupertypes(classOrObject: KtClassOrObject) =
classOrObject.superTypeListEntries.any { it is KtDelegatedSuperTypeEntry }
private fun isDataClassWithGeneratedMembersOverridden(classOrObject: KtClassOrObject): Boolean {
return classOrObject.hasModifier(KtTokens.DATA_KEYWORD) &&
classOrObject.declarations.filterIsInstance<KtFunction>().any {
isGeneratedForDataClass(it.nameAsSafeName)
}
}
private fun isGeneratedForDataClass(name: Name): Boolean {
return name == FunctionsFromAny.EQUALS_METHOD_NAME ||
// known failure is related to equals override, checking for other methods 'just in case'
name == DataClassDescriptorResolver.COPY_METHOD_NAME ||
name == FunctionsFromAny.HASH_CODE_METHOD_NAME ||
name == FunctionsFromAny.TO_STRING_METHOD_NAME ||
DataClassDescriptorResolver.isComponentLike(name)
}
private fun isDataClassWhichExtendsOtherClass(classOrObject: KtClassOrObject): Boolean {
return classOrObject.hasModifier(KtTokens.DATA_KEYWORD) &&
classOrObject.superTypeListEntries.isNotEmpty()
}
private fun hasMembersOverridingInternalMembers(classOrObject: KtClassOrObject): Boolean {
return classOrObject.declarations.filterIsInstance<KtCallableDeclaration>().any {
possiblyOverridesInternalMember(it)
}
}
private fun possiblyOverridesInternalMember(declaration: KtCallableDeclaration): Boolean {
if (!declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return false
return declaration.name?.let { anyInternalMembersWithThisName(it, declaration.project) } ?: false
}
private fun anyInternalMembersWithThisName(name: String, project: Project): Boolean {
var result = false
StubIndex.getInstance().processElements(
KotlinOverridableInternalMembersShortNameIndex.Instance.key, name, project,
EverythingGlobalScope(project), KtCallableDeclaration::class.java
) {
result = true
false // stop processing at first matching result
}
return result
}
fun forceResolvePackageDeclarations(files: Collection<KtFile>, session: ResolveSession) {
for (file in files) {
if (file.isScript()) continue
val packageFqName = file.packageFqName
// make sure we create a package descriptor
val packageDescriptor = session.moduleDescriptor.getPackage(packageFqName)
if (packageDescriptor.isEmpty()) {
LOG.warn("No descriptor found for package " + packageFqName + " in file " + file.name + "\n" + file.text)
session.forceResolveAll()
continue
}
for (declaration in file.declarations) {
when (declaration) {
is KtFunction -> {
val name = declaration.nameAsSafeName
val functions = packageDescriptor.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_IDE)
for (descriptor in functions) {
ForceResolveUtil.forceResolveAllContents(descriptor)
}
}
is KtProperty -> {
val name = declaration.nameAsSafeName
val properties = packageDescriptor.memberScope.getContributedVariables(name, NoLookupLocation.FROM_IDE)
for (descriptor in properties) {
ForceResolveUtil.forceResolveAllContents(descriptor)
}
}
is KtClassOrObject, is KtTypeAlias, is KtDestructuringDeclaration -> {
// Do nothing: we are not interested in classes or type aliases,
// and all destructuring declarations are erroneous at top level
}
else -> LOG.error("Unsupported declaration kind: " + declaration + " in file " + file.name + "\n" + file.text)
}
}
ForceResolveUtil.forceResolveAllContents(session.getFileAnnotations(file))
}
}
private fun setupAdHocResolve(project: Project, realWorldModule: ModuleDescriptor, files: List<KtFile>): ResolveSession {
val trace = BindingTraceContext()
val sm = LockBasedStorageManager.NO_LOCKS
val moduleDescriptor =
ModuleDescriptorImpl(realWorldModule.name, sm, realWorldModule.builtIns, stableName = realWorldModule.stableName)
moduleDescriptor.setDependencies(moduleDescriptor, moduleDescriptor.builtIns.builtInsModule)
val moduleInfo = files.first().getModuleInfo()
val container = createContainer("LightClassStub", JvmPlatformAnalyzerServices) {
val jvmTarget = IDELanguageSettingsProvider.getTargetPlatform(moduleInfo, project) as? JvmTarget ?: JvmTarget.DEFAULT
configureModule(
ModuleContext(moduleDescriptor, project, "ad hoc resolve"), JvmPlatforms.jvmPlatformByTargetVersion(jvmTarget),
JvmPlatformAnalyzerServices, trace,
IDELanguageSettingsProvider.getLanguageVersionSettings(moduleInfo, project)
)
useInstance(GlobalSearchScope.EMPTY_SCOPE)
useInstance(LookupTracker.DO_NOTHING)
useInstance(ExpectActualTracker.DoNothing)
useImpl<FileScopeProviderImpl>()
useInstance(FileBasedDeclarationProviderFactory(sm, files))
useInstance(CodegenAffectingAnnotations(realWorldModule))
useImpl<AdHocAnnotationResolver>()
useInstance(object : WrappedTypeFactory(sm) {
override fun createDeferredType(trace: BindingTrace, computation: () -> KotlinType) = errorType()
override fun createRecursionIntolerantDeferredType(trace: BindingTrace, computation: () -> KotlinType) = errorType()
private fun errorType() = ErrorUtils.createErrorType("Error type in ad hoc resolve for lighter classes")
})
IdeaEnvironment.configure(this)
useImpl<ResolveSession>()
}
val resolveSession = container.get<ResolveSession>()
moduleDescriptor.initialize(CompositePackageFragmentProvider(listOf(resolveSession.packageFragmentProvider)))
return resolveSession
}
class CodegenAffectingAnnotations(private val realModule: ModuleDescriptor) {
fun get(name: String): ClassDescriptor? {
val annotationFqName = annotationsThatAffectCodegen.firstOrNull { it.shortName().asString() == name } ?: return null
return realModule.getPackage(annotationFqName.parent()).memberScope
.getContributedClassifier(annotationFqName.shortName(), NoLookupLocation.FROM_IDE) as? ClassDescriptor
}
// see JvmPlatformAnnotations.kt, JvmFlagAnnotations.kt, also PsiModifier.MODIFIERS
private val annotationsThatAffectCodegen = listOf(
"JvmField", "JvmOverloads", "JvmName", "JvmStatic",
"Synchronized", "Transient", "Volatile", "Strictfp"
).map { FqName("kotlin.jvm").child(Name.identifier(it)) } +
FqName("kotlin.PublishedApi") +
FqName("kotlin.Deprecated") +
FqName("kotlin.internal.InlineOnly") +
FqName("kotlinx.android.parcel.Parcelize") +
KOTLINX_SERIALIZABLE_FQ_NAME +
KOTLINX_SERIALIZER_FQ_NAME
}
class AdHocAnnotationResolver(
private val codegenAffectingAnnotations: CodegenAffectingAnnotations,
private val callResolver: CallResolver,
private val languageVersionSettings: LanguageVersionSettings,
private val dataFlowValueFactory: DataFlowValueFactory, constantExpressionEvaluator: ConstantExpressionEvaluator,
storageManager: StorageManager
) : AnnotationResolverImpl(callResolver, constantExpressionEvaluator, storageManager) {
override fun resolveAnnotationType(scope: LexicalScope, entryElement: KtAnnotationEntry, trace: BindingTrace): KotlinType {
return annotationClassByEntry(entryElement)?.defaultType ?: super.resolveAnnotationType(scope, entryElement, trace)
}
private fun annotationClassByEntry(entryElement: KtAnnotationEntry): ClassDescriptor? {
val annotationTypeReferencePsi = entryElement.calleeExpression?.constructorReferenceExpression ?: return null
val referencedName = annotationTypeReferencePsi.getReferencedName()
return codegenAffectingAnnotations.get(referencedName)
}
override fun resolveAnnotationCall(
annotationEntry: KtAnnotationEntry,
scope: LexicalScope,
trace: BindingTrace
): OverloadResolutionResults<FunctionDescriptor> {
val annotationConstructor = annotationClassByEntry(annotationEntry)?.constructors?.singleOrNull()
?: return super.resolveAnnotationCall(annotationEntry, scope, trace)
@Suppress("UNCHECKED_CAST")
return callResolver.resolveConstructorCall(
BasicCallResolutionContext.create(
trace, scope, CallMaker.makeCall(null, null, annotationEntry), TypeUtils.NO_EXPECTED_TYPE,
DataFlowInfoFactory.EMPTY, ContextDependency.INDEPENDENT, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
true, languageVersionSettings,
dataFlowValueFactory
),
annotationEntry.calleeExpression!!.constructorReferenceExpression!!,
annotationConstructor.returnType
) as OverloadResolutionResults<FunctionDescriptor>
}
}
}

View File

@@ -1,72 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.caches.lightClasses
import com.intellij.psi.CommonClassNames
import com.intellij.psi.PsiClass
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult
import org.jetbrains.kotlin.asJava.ImpreciseResolveResult.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.LightClassInheritanceHelper
import org.jetbrains.kotlin.asJava.classes.defaultJavaAncestorQualifiedName
import org.jetbrains.kotlin.idea.caches.resolve.util.isInDumbMode
import org.jetbrains.kotlin.idea.search.PsiBasedClassResolver
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtSuperTypeCallEntry
import org.jetbrains.kotlin.psi.KtSuperTypeListEntry
class IdeLightClassInheritanceHelper : LightClassInheritanceHelper {
override fun isInheritor(
lightClass: KtLightClass,
baseClass: PsiClass,
checkDeep: Boolean
): ImpreciseResolveResult {
if (baseClass.project.isInDumbMode()) return NO_MATCH
if (lightClass.manager.areElementsEquivalent(baseClass, lightClass)) return NO_MATCH
val classOrObject = lightClass.kotlinOrigin ?: return UNSURE
if (checkDeep && baseClass.qualifiedName == CommonClassNames.JAVA_LANG_OBJECT) {
return MATCH
}
val entries = classOrObject.superTypeListEntries
val hasSuperClass = entries.any { it is KtSuperTypeCallEntry }
if (baseClass.qualifiedName == classOrObject.defaultJavaAncestorQualifiedName() && (!hasSuperClass || checkDeep)) {
return MATCH
}
val amongEntries = isAmongEntries(baseClass, entries)
return when {
!checkDeep -> amongEntries
amongEntries == MATCH -> MATCH
else -> UNSURE
}
}
private fun isAmongEntries(baseClass: PsiClass, entries: List<KtSuperTypeListEntry>): ImpreciseResolveResult {
val psiBasedResolver = PsiBasedClassResolver.getInstance(baseClass)
entries@ for (entry in entries) {
val reference: KtSimpleNameExpression = entry.typeAsUserType?.referenceExpression ?: continue@entries
when (psiBasedResolver.canBeTargetReference(reference)) {
MATCH -> return MATCH
NO_MATCH -> continue@entries
UNSURE -> return UNSURE
}
}
return NO_MATCH
}
}

View File

@@ -1,190 +0,0 @@
/*
* Copyright 2000-2019 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.idea.caches.lightClasses
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import org.jetbrains.kotlin.asJava.LightClassBuilder
import org.jetbrains.kotlin.asJava.builder.*
import org.jetbrains.kotlin.asJava.classes.KtLightClass
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.asJava.elements.KtLightField
import org.jetbrains.kotlin.asJava.elements.KtLightFieldImpl
import org.jetbrains.kotlin.asJava.elements.KtLightMethod
import org.jetbrains.kotlin.asJava.elements.KtLightMethodImpl
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
import org.jetbrains.kotlin.psi.debugText.getDebugText
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.storage.StorageManager
typealias ExactLightClassContextProvider = () -> LightClassConstructionContext
typealias DummyLightClassContextProvider = (() -> LightClassConstructionContext?)?
typealias DiagnosticsHolderProvider = () -> LazyLightClassDataHolder.DiagnosticsHolder
sealed class LazyLightClassDataHolder(
private val builder: LightClassBuilder,
private val exactContextProvider: ExactLightClassContextProvider,
dummyContextProvider: DummyLightClassContextProvider,
private val diagnosticsHolderProvider: DiagnosticsHolderProvider
) : LightClassDataHolder {
class DiagnosticsHolder(storageManager: StorageManager) {
private val cache = storageManager.createCacheWithNotNullValues<LazyLightClassDataHolder, Diagnostics>()
fun getOrCompute(lazyLightClassDataHolder: LazyLightClassDataHolder, diagnostics: () -> Diagnostics) =
cache.computeIfAbsent(lazyLightClassDataHolder, diagnostics)
}
private val _builderExactContextProvider: LightClassBuilderResult by lazyPub { builder(exactContextProvider()) }
private val exactResultLazyValue = lazyPub { _builderExactContextProvider.stub }
private val lazyInexactStub by lazyPub {
dummyContextProvider?.let { provider -> provider()?.let { context -> builder.invoke(context).stub } }
}
private val inexactStub: PsiJavaFileStub?
get() = if (exactResultLazyValue.isInitialized()) null else lazyInexactStub
override val javaFileStub by exactResultLazyValue
override val extraDiagnostics: Diagnostics
get() = diagnosticsHolderProvider().getOrCompute(this) {
// Force lazy diagnostics computation because otherwise a lot of memory is retained by computation.
// NB: Laziness here is not crucial anyway since somebody already has requested diagnostics and we hope one will use them
_builderExactContextProvider.diagnostics.takeUnless { it.isEmpty() } ?: Diagnostics.EMPTY
}
// for facade or defaultImpls
override fun findData(findDelegate: (PsiJavaFileStub) -> PsiClass): LightClassData =
LazyLightClassData { stub ->
findDelegate(stub)
}
class ForClass(
builder: LightClassBuilder,
exactContextProvider: ExactLightClassContextProvider,
dummyContextProvider: DummyLightClassContextProvider,
diagnosticsHolderProvider: DiagnosticsHolderProvider
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider, diagnosticsHolderProvider),
LightClassDataHolder.ForClass {
override fun findDataForClassOrObject(classOrObject: KtClassOrObject): LightClassData =
LazyLightClassData { stub ->
stub.findDelegate(classOrObject)
}
}
class ForFacade(
builder: LightClassBuilder,
exactContextProvider: ExactLightClassContextProvider,
dummyContextProvider: DummyLightClassContextProvider,
diagnosticsHolderProvider: DiagnosticsHolderProvider
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider, diagnosticsHolderProvider),
LightClassDataHolder.ForFacade
class ForScript(
builder: LightClassBuilder,
exactContextProvider: ExactLightClassContextProvider,
dummyContextProvider: DummyLightClassContextProvider,
diagnosticsHolderProvider: DiagnosticsHolderProvider
) : LazyLightClassDataHolder(builder, exactContextProvider, dummyContextProvider, diagnosticsHolderProvider),
LightClassDataHolder.ForScript
private inner class LazyLightClassData(
findDelegate: (PsiJavaFileStub) -> PsiClass
) : LightClassData {
override val clsDelegate: PsiClass by lazyPub { findDelegate(javaFileStub) }
private val dummyDelegate: PsiClass? by lazyPub { inexactStub?.let(findDelegate) }
override fun getOwnFields(containingClass: KtLightClass): List<KtLightField> {
if (dummyDelegate == null) return KtLightFieldImpl.fromClsFields(clsDelegate, containingClass)
return dummyDelegate!!.fields.map { dummyField ->
val fieldOrigin = KtLightFieldImpl.getOrigin(dummyField)
val fieldName = dummyField.name
KtLightFieldImpl.lazy(dummyField, fieldOrigin, containingClass) {
val findFieldByName = clsDelegate.findFieldByName(fieldName, false)
findFieldByName.checkMatches(dummyField, containingClass) ?:
// fallback in case of non-matched (like synthetic) fields
//
// it costs some performance and has to happen in rare and odd cases
KtLightFieldImpl.create(
KtLightFieldImpl.getOrigin(dummyField), dummyField, containingClass
)
}
}
}
override fun getOwnMethods(containingClass: KtLightClass): List<KtLightMethod> {
if (dummyDelegate == null) return KtLightMethodImpl.fromClsMethods(clsDelegate, containingClass)
return dummyDelegate!!.methods.map { dummyMethod ->
val methodOrigin = KtLightMethodImpl.getOrigin(dummyMethod)
KtLightMethodImpl.lazy(dummyMethod, containingClass, methodOrigin) {
val dummyIndex = dummyMethod.memberIndex!!
val byMemberIndex: (PsiMethod) -> Boolean = { it.memberIndex == dummyIndex }
/* Searching all methods may be necessary in some cases where we failed to rollback optimization:
Overriding internal member that was final
Resulting light member is not consistent in this case, so this should happen only for erroneous code
*/
val findMethodsByName = clsDelegate.findMethodsByName(dummyMethod.name, false)
val candidateDelegateMethod = findMethodsByName.firstOrNull(byMemberIndex)
?: clsDelegate.methods.firstOrNull(byMemberIndex)
candidateDelegateMethod.checkMatches(dummyMethod, containingClass) ?:
// fallback if unable to find method for a dummy method (e.g. synthetic methods marked explicit or implicit) are
// not visible as own methods.
//
// it costs some performance and has to happen in rare and odd cases
KtLightMethodImpl.create(dummyMethod, KtLightMethodImpl.getOrigin(dummyMethod), containingClass)
}
}
}
}
private fun <T : PsiMember> T?.checkMatches(dummyMember: T, containingClass: KtLightClass): T? {
if (this == null) {
logMismatch("Couldn't match ${dummyMember.debugName}", containingClass)
return null
}
val parameterCountMatches = (this as? PsiMethod)?.parameterList?.parametersCount ?: 0 ==
(dummyMember as? PsiMethod)?.parameterList?.parametersCount ?: 0
if (this.memberIndex != dummyMember.memberIndex || !parameterCountMatches) {
logMismatch("Wrongly matched ${dummyMember.debugName} to ${this.debugName}", containingClass)
return null
}
return this
}
companion object {
private val LOG = Logger.getInstance(LazyLightClassDataHolder::class.java)
private fun logMismatch(message: String, containingClass: KtLightClass) {
containingClass.kotlinOrigin?.hasLightClassMatchingErrors = true
LOG.warn("$message, class.kt: ${(containingClass.kotlinOrigin)?.getDebugText()}")
}
}
}
private val PsiMember.debugName
get() = "${this::class.java
.simpleName}:${this.name} ${this.memberIndex}" + if (this is PsiMethod) " (with ${parameterList.parametersCount} parameters)" else ""
var KtClassOrObject.hasLightClassMatchingErrors: Boolean by NotNullableUserDataProperty(Key.create("LIGHT_CLASS_MATCHING_ERRORS"), false)

View File

@@ -1,286 +0,0 @@
/*
* Copyright 2010-2020 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.idea.caches.lightClasses
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
import com.intellij.psi.impl.compiled.SignatureParsing
import com.intellij.util.cls.ClsFormatException
import org.jetbrains.kotlin.asJava.builder.LightMemberOrigin
import org.jetbrains.kotlin.asJava.classes.lazyPub
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile
import org.jetbrains.kotlin.idea.decompiler.textBuilder.DecompiledTextIndexer
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.kotlin.MemberSignature
import org.jetbrains.kotlin.metadata.deserialization.getExtensionOrNull
import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDeclarationContainer
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.resolve.jvm.annotations.findJvmOverloadsAnnotation
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassConstructorDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
import org.jetbrains.kotlin.type.MapPsiToAsmDesc
import java.text.CharacterIterator
import java.text.StringCharacterIterator
interface LightMemberOriginForCompiledElement<T : PsiMember> : LightMemberOrigin {
val member: T
override val originKind: JvmDeclarationOriginKind
get() = JvmDeclarationOriginKind.OTHER
override fun isEquivalentTo(other: PsiElement?): Boolean {
return when (other) {
is KtDeclaration -> originalElement?.isEquivalentTo(other) ?: false
is PsiMember -> member.isEquivalentTo(other)
else -> false
}
}
override fun isValid(): Boolean = member.isValid
}
data class LightMemberOriginForCompiledField(val psiField: PsiField, val file: KtClsFile) : LightMemberOriginForCompiledElement<PsiField> {
override val member: PsiField
get() = psiField
override fun copy(): LightMemberOrigin {
return LightMemberOriginForCompiledField(psiField.copy() as PsiField, file)
}
override fun isEquivalentTo(other: LightMemberOrigin?): Boolean {
if (other !is LightMemberOriginForCompiledField) return false
return psiField.isEquivalentTo(other.psiField)
}
override val originalElement: KtDeclaration? by lazyPub {
val desc = MapPsiToAsmDesc.typeDesc(psiField.type)
val signature = MemberSignature.fromFieldNameAndDesc(psiField.name, desc)
findDeclarationInCompiledFile(file, psiField, signature)
}
}
data class LightMemberOriginForCompiledMethod(val psiMethod: PsiMethod, val file: KtClsFile) :
LightMemberOriginForCompiledElement<PsiMethod> {
override val member: PsiMethod
get() = psiMethod
override fun isEquivalentTo(other: LightMemberOrigin?): Boolean {
if (other !is LightMemberOriginForCompiledMethod) return false
return psiMethod.isEquivalentTo(other.psiMethod)
}
override fun copy(): LightMemberOrigin {
return LightMemberOriginForCompiledMethod(psiMethod.copy() as PsiMethod, file)
}
override val originalElement: KtDeclaration? by lazyPub {
val desc = MapPsiToAsmDesc.methodDesc(psiMethod)
val name = if (psiMethod.isConstructor) "<init>" else psiMethod.name
val signature = MemberSignature.fromMethodNameAndDesc(name, desc)
findDeclarationInCompiledFile(file, psiMethod, signature)
}
}
internal fun findDeclarationInCompiledFile(file: KtClsFile, member: PsiMember, signature: MemberSignature): KtDeclaration? {
val relativeClassName = member.relativeClassName()
val key = ClassNameAndSignature(relativeClassName, signature)
val memberName = member.name
if (memberName != null && !file.isContentsLoaded && file.hasDeclarationWithKey(ByJvmSignatureIndexer, key)) {
val container: KtDeclarationContainer? = if (relativeClassName.isEmpty())
file
else {
val topClassOrObject = file.declarations.singleOrNull() as? KtClassOrObject
relativeClassName.fold(topClassOrObject) { classOrObject, name ->
classOrObject?.declarations?.singleOrNull { it.name == name.asString() } as? KtClassOrObject
}
}
val declaration = container?.declarations?.singleOrNull {
it.name == memberName
}
if (declaration != null) {
return declaration
}
}
return file.getDeclaration(ByJvmSignatureIndexer, key)
}
// this is convenient data structure for this purpose and is not supposed to be used outside this file
// every member is represented by its jvm signature and relative class name (which is easy to obtain from descriptors or cls psi)
// relative class name is a path containing inner/nested class names from top level class to the class containing this member (excluding top level class name)
// Examples: for top level function or function in a top level class relativeClassName is empty
// For: class TopLevel { class A { class B { fun f() } } }
// relativeClassName for function 'f' will be [A, B]
private data class ClassNameAndSignature(val relativeClassName: List<Name>, val memberSignature: MemberSignature)
private fun PsiMember.relativeClassName(): List<Name> {
return generateSequence(this.containingClass) { it.containingClass }.toList().dropLast(1).reversed().map { Name.identifier(it.name!!) }
}
private fun ClassDescriptor.relativeClassName(): List<Name> {
return classId!!.relativeClassName.pathSegments().drop(1)
}
private fun excludeParametersFromDescriptor(descriptor: String, omittedParameters: List<Int>): String? {
fun tryParseParametersAndReturnType(): Pair<List<String>, String>? {
val iterator = StringCharacterIterator(descriptor)
fun parseTypeString(): String? {
val begin = iterator.index
try {
SignatureParsing.parseTypeString(iterator) { it }
} catch (e: ClsFormatException) {
return null
}
val end = iterator.index
return descriptor.substring(begin, end)
}
if (iterator.current() != '(') return null
iterator.next()
if (iterator.current() == ')') {
iterator.next()
val returnType = parseTypeString() ?: return null
return emptyList<String>() to returnType
}
val parameterTypes = mutableListOf<String>()
while (iterator.current() != ')' && iterator.current() != CharacterIterator.DONE) {
parameterTypes += parseTypeString() ?: return null
}
if (iterator.current() != ')') return null
iterator.next()
val returnType = parseTypeString() ?: return null
return parameterTypes to returnType
}
val (parameterTypes, returnType) = tryParseParametersAndReturnType() ?: return null
val parametersList = parameterTypes
.filterIndexed { index, _ -> index !in omittedParameters }
.joinToString("")
return "($parametersList)$returnType"
}
private fun ClassDescriptor.desc(): String = "L" + JvmClassName.byClassId(classId!!).internalName + ";"
private object ByJvmSignatureIndexer : DecompiledTextIndexer<ClassNameAndSignature> {
override fun indexDescriptor(descriptor: DeclarationDescriptor): Collection<ClassNameAndSignature> {
val signatures = arrayListOf<ClassNameAndSignature>()
fun save(id: List<Name>, signature: MemberSignature) {
signatures.add(ClassNameAndSignature(id, signature))
}
fun ClassDescriptor.apply() {
when (kind) {
ClassKind.ENUM_ENTRY -> {
val enumClass = containingDeclaration as ClassDescriptor
val signature = MemberSignature.fromFieldNameAndDesc(name.asString(), enumClass.desc())
save(enumClass.relativeClassName(), signature)
}
ClassKind.OBJECT -> {
val instanceFieldSignature = MemberSignature.fromFieldNameAndDesc(JvmAbi.INSTANCE_FIELD, desc())
save(relativeClassName(), instanceFieldSignature)
if (isCompanionObject) {
val signature = MemberSignature.fromFieldNameAndDesc(name.asString(), desc())
save((containingDeclaration as? ClassDescriptor)?.relativeClassName().orEmpty(), signature)
}
}
else -> {
}
}
}
fun DeserializedClassConstructorDescriptor.apply() {
JvmProtoBufUtil.getJvmConstructorSignature(proto, nameResolver, typeTable)?.let {
val id = (containingDeclaration as? ClassDescriptor)?.relativeClassName().orEmpty()
val signature = MemberSignature.fromJvmMemberSignature(it)
save(id, signature)
}
}
fun DeserializedSimpleFunctionDescriptor.apply() {
JvmProtoBufUtil.getJvmMethodSignature(proto, nameResolver, typeTable)?.let {
val id = (containingDeclaration as? ClassDescriptor)?.relativeClassName().orEmpty()
val signature = MemberSignature.fromJvmMemberSignature(it)
save(id, signature)
if (findJvmOverloadsAnnotation() == null) return
val extensionShift = if (isExtension) 1 else 0
val omittedList = mutableListOf<Int>()
valueParameters.asReversed().forEach { parameter ->
if (parameter.hasDefaultValue()) {
omittedList.add(parameter.index + extensionShift)
val newDescriptor = excludeParametersFromDescriptor(it.desc, omittedList)
if (newDescriptor != null) {
val overloadedSignature = MemberSignature.fromMethodNameAndDesc(it.name, newDescriptor)
save(id, overloadedSignature)
}
}
}
}
}
fun DeserializedPropertyDescriptor.apply() {
val className = (containingDeclaration as? ClassDescriptor)?.relativeClassName().orEmpty()
val signature = proto.getExtensionOrNull(JvmProtoBuf.propertySignature)
if (signature != null) {
val fieldSignature = JvmProtoBufUtil.getJvmFieldSignature(proto, nameResolver, typeTable)
if (fieldSignature != null) {
save(className, MemberSignature.fromJvmMemberSignature(fieldSignature))
}
if (signature.hasGetter()) {
save(className, MemberSignature.fromMethod(nameResolver, signature.getter))
}
if (signature.hasSetter()) {
save(className, MemberSignature.fromMethod(nameResolver, signature.setter))
}
}
}
when (descriptor) {
is ClassDescriptor -> descriptor.apply()
is DeserializedClassConstructorDescriptor -> descriptor.apply()
is DeserializedSimpleFunctionDescriptor -> descriptor.apply()
is DeserializedPropertyDescriptor -> descriptor.apply()
}
return signatures
}
}
// expose with different type
val BySignatureIndexer: DecompiledTextIndexer<*> = ByJvmSignatureIndexer

Some files were not shown because too many files have changed in this diff Show More