mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-31 15:51:59 +00:00
Compare commits
3 Commits
rr/mb/tp
...
push/pdn_b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef461d4a3a | ||
|
|
eaf870bfd4 | ||
|
|
e8982765c8 |
40
ChangeLog.md
40
ChangeLog.md
@@ -1,45 +1,5 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 1.4.32
|
||||
|
||||
### IDE
|
||||
|
||||
- [`KT-43824`](https://youtrack.jetbrains.com/issue/KT-43824) KtLightClassForSourceDeclaration#isInheritor works in a different way than java implementation
|
||||
- [`KT-45287`](https://youtrack.jetbrains.com/issue/KT-45287) LightClasses: `KtLightSimpleModifierList` is no more a parent of `KtLightAnnotationForSourceEntry`
|
||||
- [`KT-45291`](https://youtrack.jetbrains.com/issue/KT-45291) LightClasses: can't get annotations for constructor val-parameter
|
||||
- [`KT-45417`](https://youtrack.jetbrains.com/issue/KT-45417) ULC leakage of primitive type annotations
|
||||
|
||||
### Tools. CLI
|
||||
|
||||
- [`KT-44758`](https://youtrack.jetbrains.com/issue/KT-44758) kotlin-compiler-embeddable dependency includes unshaded `fastutil` package
|
||||
- [`KT-45007`](https://youtrack.jetbrains.com/issue/KT-45007) Concurrent Kotlin script compilation/execution results in NullPointerException in KeyedExtensionCollector.getPoint()
|
||||
|
||||
## 1.4.31
|
||||
|
||||
### Compiler
|
||||
|
||||
- [`KT-39776`](https://youtrack.jetbrains.com/issue/KT-39776) 2020.3+: Unresolved reference to Kotlin stdlib function
|
||||
|
||||
### IDE. Gradle Integration
|
||||
|
||||
- [`KT-44845`](https://youtrack.jetbrains.com/issue/KT-44845) After update to Kotlin 1.4.30 all external dependencies is unresolved in IDE with kotlin.mpp.enableGranularSourceSetsMetadata=true
|
||||
|
||||
### IDE. Gradle. Script
|
||||
|
||||
- [`KTIJ-11137`](https://youtrack.jetbrains.com/issue/KTIJ-1137) build.gradle.kts: Fatal error during save/load standalone scripts settings
|
||||
- [`KTIJ-898`](https://youtrack.jetbrains.com/issue/KTIJ-898) Unable to import with Kotlin DSL buildscript - NullPointerException in KotlinDslScriptModelProcessorKt.toListOfScriptModels
|
||||
|
||||
### IDE. Multiplatform
|
||||
|
||||
- [`KTIJ-1200`](https://youtrack.jetbrains.com/issue/KTIJ-1200) KotlinIconProviderKt.addExpectActualMarker takes up to 180+ seconds
|
||||
|
||||
### IDE
|
||||
|
||||
#### Fixes
|
||||
|
||||
- [`KT-44697`](https://youtrack.jetbrains.com/issue/KT-44697) New JVM IR backend notification - narrow its triggering to Kotlin projects
|
||||
- [`KT-44523`](https://youtrack.jetbrains.com/issue/KT-44523) IDE notification for trying new JVM backend
|
||||
- [`KTIJ-696`](https://youtrack.jetbrains.com/issue/KTIJ-696) Freeze during startup of IDEA with intellij project with Kotlin (211-1.4.10-release-IJ1440)
|
||||
|
||||
## 1.4.30
|
||||
|
||||
|
||||
@@ -14,11 +14,8 @@ buildscript {
|
||||
|
||||
if (cacheRedirectorEnabled) {
|
||||
maven("https://cache-redirector.jetbrains.com/plugins.gradle.org/m2")
|
||||
maven("https://cache-redirector.jetbrains.com/repo.maven.apache.org/maven2")
|
||||
|
||||
} else {
|
||||
maven("https://plugins.gradle.org/m2")
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +27,7 @@ buildscript {
|
||||
dependencies {
|
||||
bootstrapCompilerClasspath(kotlin("compiler-embeddable", bootstrapKotlinVersion))
|
||||
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.27")
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.26")
|
||||
classpath(kotlin("gradle-plugin", bootstrapKotlinVersion))
|
||||
classpath(kotlin("serialization", bootstrapKotlinVersion))
|
||||
classpath("org.jetbrains.dokka:dokka-gradle-plugin:0.9.17")
|
||||
@@ -336,9 +333,7 @@ extra["tasksWithWarnings"] = listOf(
|
||||
":kotlin-stdlib-jdk7:compileTestKotlin",
|
||||
":kotlin-stdlib-jdk8:compileTestKotlin",
|
||||
":plugins:uast-kotlin:compileKotlin",
|
||||
":plugins:uast-kotlin:compileTestKotlin",
|
||||
":plugins:uast-kotlin-fir:compileKotlin",
|
||||
":plugins:uast-kotlin-fir:compileTestKotlin"
|
||||
":plugins:uast-kotlin:compileTestKotlin"
|
||||
)
|
||||
|
||||
val tasksWithWarnings: List<String> by extra
|
||||
@@ -383,7 +378,7 @@ apply {
|
||||
}
|
||||
|
||||
apply {
|
||||
if (extra["isDeployStagingRepoGenerationRequired"] as? Boolean == true) {
|
||||
if (extra["isSonatypeRelease"] as? Boolean == true) {
|
||||
logger.info("Applying configuration for sonatype release")
|
||||
from("libraries/prepareSonatypeStaging.gradle")
|
||||
}
|
||||
@@ -849,11 +844,11 @@ tasks {
|
||||
":idea:idea-fir:test",
|
||||
":idea:idea-frontend-api:test",
|
||||
":idea:idea-frontend-fir:test",
|
||||
":idea:idea-frontend-fir:idea-fir-low-level-api:test",
|
||||
":plugins:uast-kotlin-fir:test"
|
||||
":idea:idea-frontend-fir:idea-fir-low-level-api:test"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
register("android-ide-tests") {
|
||||
dependsOn("dist")
|
||||
dependsOn(
|
||||
@@ -899,6 +894,7 @@ tasks {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
register("kaptIdeTest") {
|
||||
dependsOn(":kotlin-annotation-processing:test")
|
||||
dependsOn(":kotlin-annotation-processing-base:test")
|
||||
@@ -966,7 +962,6 @@ tasks {
|
||||
":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",
|
||||
":prepare:ide-plugin-dependencies:lombok-compiler-plugin-for-ide:publish",
|
||||
":kotlin-script-runtime:publish",
|
||||
":kotlin-script-util:publish",
|
||||
":kotlin-scripting-common:publish",
|
||||
|
||||
@@ -22,7 +22,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.27")
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.26")
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.bootstrapKotlinVersion}")
|
||||
classpath("org.jetbrains.kotlin:kotlin-sam-with-receiver:${project.bootstrapKotlinVersion}")
|
||||
}
|
||||
@@ -144,7 +144,7 @@ java {
|
||||
dependencies {
|
||||
implementation(kotlin("stdlib", embeddedKotlinVersion))
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${project.bootstrapKotlinVersion}")
|
||||
implementation("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.27")
|
||||
implementation("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.26")
|
||||
implementation("com.gradle.publish:plugin-publish-plugin:0.14.0")
|
||||
|
||||
implementation("net.rubygrapefruit:native-platform:${property("versions.native-platform")}")
|
||||
|
||||
@@ -18,10 +18,9 @@ buildscript {
|
||||
} else {
|
||||
maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/kotlin-dependencies" }
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.27")
|
||||
classpath("org.jetbrains.kotlin:kotlin-build-gradle-plugin:0.0.26")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -229,6 +229,23 @@ fun Project.publish(moduleMetadata: Boolean = false, configure: MavenPublication
|
||||
publication.configure()
|
||||
}
|
||||
|
||||
fun Project.publishWithLegacyMavenPlugin(body: Upload.() -> Unit = {}): Upload {
|
||||
apply<plugins.PublishedKotlinModule>()
|
||||
|
||||
if (artifactsRemovedDiagnosticFlag) {
|
||||
error("`publish()` should be called before removing artifacts typically done in `noDefaultJar()` or `runtimeJar()` call")
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
if (configurations.findByName("classes-dirs") != null)
|
||||
throw GradleException("classesDirsArtifact() is incompatible with publish(), see sources comments for details")
|
||||
}
|
||||
|
||||
return (tasks.getByName("uploadArchives") as Upload).apply {
|
||||
body()
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.idePluginDependency(block: () -> Unit) {
|
||||
val shouldActivate = rootProject.findProperty("publish.ide.plugin.dependencies")?.toString()?.toBoolean() == true
|
||||
if (shouldActivate) {
|
||||
|
||||
@@ -164,17 +164,7 @@ fun Project.configureDefaultPublishing() {
|
||||
private fun Project.configureSigning() {
|
||||
configure<SigningExtension> {
|
||||
sign(extensions.getByType<PublishingExtension>().publications) // all publications
|
||||
|
||||
val signKeyId = project.findProperty("signKeyId") as? String
|
||||
if (!signKeyId.isNullOrBlank()) {
|
||||
val signKeyPrivate = project.findProperty("signKeyPrivate") as? String
|
||||
?: error("Parameter `signKeyPrivate` not found")
|
||||
val signKeyPassphrase = project.findProperty("signKeyPassphrase") as? String
|
||||
?: error("Parameter `signKeyPassphrase` not found")
|
||||
useInMemoryPgpKeys(signKeyId, signKeyPrivate, signKeyPassphrase)
|
||||
} else {
|
||||
useGpgCmd()
|
||||
}
|
||||
useGpgCmd()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
173
buildSrc/src/main/kotlin/plugins/PublishedKotlinModule.kt
Normal file
173
buildSrc/src/main/kotlin/plugins/PublishedKotlinModule.kt
Normal file
@@ -0,0 +1,173 @@
|
||||
@file:Suppress("DEPRECATION")
|
||||
package plugins
|
||||
|
||||
import org.codehaus.groovy.runtime.InvokerHelper
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.artifacts.maven.Conf2ScopeMappingContainer
|
||||
import org.gradle.api.artifacts.maven.MavenDeployment
|
||||
import org.gradle.api.artifacts.maven.MavenResolver
|
||||
import org.gradle.api.plugins.MavenPluginConvention
|
||||
import org.gradle.api.plugins.MavenRepositoryHandlerConvention
|
||||
import org.gradle.api.publication.maven.internal.deployer.MavenRemoteRepository
|
||||
import org.gradle.api.tasks.Upload
|
||||
import org.gradle.kotlin.dsl.*
|
||||
import org.gradle.plugins.signing.Sign
|
||||
import org.gradle.plugins.signing.SigningExtension
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
/**
|
||||
* Configures a Kotlin module for publication.
|
||||
*/
|
||||
open class PublishedKotlinModule : Plugin<Project> {
|
||||
|
||||
private fun String.toBooleanOrNull() = listOf(true, false).firstOrNull { it.toString().equals(this, ignoreCase = true) }
|
||||
|
||||
override fun apply(project: Project) {
|
||||
|
||||
project.run {
|
||||
|
||||
plugins.apply("maven")
|
||||
|
||||
configurations.maybeCreate("publishedRuntime").apply {
|
||||
the<MavenPluginConvention>()
|
||||
.conf2ScopeMappings
|
||||
.addMapping(0, this, Conf2ScopeMappingContainer.RUNTIME)
|
||||
}
|
||||
|
||||
configurations.maybeCreate("publishedCompile").apply {
|
||||
the<MavenPluginConvention>()
|
||||
.conf2ScopeMappings
|
||||
.addMapping(0, this, Conf2ScopeMappingContainer.COMPILE)
|
||||
}
|
||||
|
||||
if (!project.hasProperty("prebuiltJar")) {
|
||||
plugins.apply("signing")
|
||||
|
||||
val signingRequired = project.findProperty("signingRequired")?.toString()?.toBooleanOrNull()
|
||||
?: project.property("isSonatypeRelease") as Boolean
|
||||
|
||||
configure<SigningExtension> {
|
||||
isRequired = signingRequired
|
||||
sign(configurations["archives"])
|
||||
useGpgCmd()
|
||||
}
|
||||
|
||||
tasks.named<Sign>("signArchives").configure {
|
||||
enabled = signingRequired
|
||||
}
|
||||
}
|
||||
|
||||
fun MavenResolver.configurePom() {
|
||||
pom.project {
|
||||
withGroovyBuilder {
|
||||
"licenses" {
|
||||
"license" {
|
||||
"name"("The Apache Software License, Version 2.0")
|
||||
"url"("http://www.apache.org/licenses/LICENSE-2.0.txt")
|
||||
"distribution"("repo")
|
||||
}
|
||||
}
|
||||
"name"("${project.group}:${project.name}")
|
||||
"packaging"("jar")
|
||||
// optionally artifactId can be defined here
|
||||
"description"(project.description)
|
||||
"url"("https://kotlinlang.org/")
|
||||
"licenses" {
|
||||
"license" {
|
||||
"name"("The Apache License, Version 2.0")
|
||||
"url"("http://www.apache.org/licenses/LICENSE-2.0.txt")
|
||||
}
|
||||
}
|
||||
"scm" {
|
||||
"url"("https://github.com/JetBrains/kotlin")
|
||||
"connection"("scm:git:https://github.com/JetBrains/kotlin.git")
|
||||
"developerConnection"("scm:git:https://github.com/JetBrains/kotlin.git")
|
||||
}
|
||||
"developers" {
|
||||
"developer" {
|
||||
"name"("Kotlin Team")
|
||||
setProperty("organization", "JetBrains")
|
||||
"organizationUrl"("https://www.jetbrains.com")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pom.whenConfigured {
|
||||
dependencies.removeIf {
|
||||
InvokerHelper.getMetaClass(it).getProperty(it, "scope") == "test"
|
||||
}
|
||||
|
||||
dependencies
|
||||
.find {
|
||||
InvokerHelper.getMetaClass(it).getProperty(it, "groupId") == "org.jetbrains.kotlin"
|
||||
&& InvokerHelper.getMetaClass(it).getProperty(it, "artifactId") == "kotlin-stdlib"
|
||||
}
|
||||
?.also {
|
||||
InvokerHelper.getMetaClass(it).setProperty(it, "exclusions", emptyList<Any>())
|
||||
logger.warn("WARNING! Removed exclusions from kotlin-stdlib dependency of ${this.artifactId} artifact's maven metadata, check kotlin-stdlib dependency of ${project.path} project")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.named<Upload>("uploadArchives").configure {
|
||||
|
||||
val preparePublication = project.rootProject.tasks.named("preparePublication").get()
|
||||
|
||||
dependsOn(preparePublication)
|
||||
|
||||
val username: String? by preparePublication.extra
|
||||
val password: String? by preparePublication.extra
|
||||
val repoUrl: String by preparePublication.extra
|
||||
|
||||
var repository by Delegates.notNull<MavenRemoteRepository>()
|
||||
|
||||
repositories {
|
||||
withConvention(MavenRepositoryHandlerConvention::class) {
|
||||
|
||||
mavenDeployer {
|
||||
withGroovyBuilder {
|
||||
"beforeDeployment" {
|
||||
val signing = project.the<SigningExtension>()
|
||||
if (signing.isRequired)
|
||||
signing.signPom(delegate as MavenDeployment)
|
||||
}
|
||||
|
||||
"repository"("url" to repoUrl)!!.also { repository = it as MavenRemoteRepository }.withGroovyBuilder {
|
||||
if (username != null && password != null) {
|
||||
"authentication"("userName" to username, "password" to password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurePom()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doFirst {
|
||||
repository.url = repoUrl
|
||||
}
|
||||
}
|
||||
|
||||
val install = if (tasks.names.contains("install")) tasks.getByName("install") as Upload
|
||||
else tasks.create("install", Upload::class.java)
|
||||
install.apply {
|
||||
configuration = project.configurations.getByName(Dependency.ARCHIVES_CONFIGURATION)
|
||||
description = "Installs the 'archives' artifacts into the local Maven repository."
|
||||
repositories {
|
||||
withConvention(MavenRepositoryHandlerConvention::class) {
|
||||
mavenInstaller {
|
||||
configurePom()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register("publish") {
|
||||
dependsOn(tasks.named("uploadArchives"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -354,8 +354,8 @@ class CodegenTestsOnAndroidGenerator private constructor(private val pathManager
|
||||
extractor.provideConfigurationKeys()
|
||||
extractor.configure(keyConfiguration, module.directives)
|
||||
}
|
||||
val kind = JvmEnvironmentConfigurator.extractConfigurationKind(module.directives)
|
||||
val jdkKind = JvmEnvironmentConfigurator.extractJdkKind(module.directives)
|
||||
val kind = configuratorForFlags.extractConfigurationKind(module.directives)
|
||||
val jdkKind = configuratorForFlags.extractJdkKind(module.directives)
|
||||
|
||||
keyConfiguration.languageVersionSettings = module.languageVersionSettings
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ interface TypeMappingContext<Writer : JvmDescriptorTypeWriter<Type>> {
|
||||
val typeContext: TypeSystemCommonBackendContextForTypeMapping
|
||||
|
||||
fun getClassInternalName(typeConstructor: TypeConstructorMarker): String
|
||||
fun getScriptInternalName(typeConstructor: TypeConstructorMarker): String
|
||||
fun Writer.writeGenericType(type: SimpleTypeMarker, asmType: Type, mode: TypeMappingMode)
|
||||
}
|
||||
|
||||
@@ -118,7 +117,9 @@ object AbstractTypeMapper {
|
||||
}
|
||||
|
||||
typeConstructor.isScript() -> {
|
||||
return Type.getObjectType(context.getScriptInternalName(typeConstructor))
|
||||
val asmType = AsmTypes.JAVA_CLASS_TYPE
|
||||
with(context) { sw?.writeGenericType(type, asmType, mode) }
|
||||
return asmType
|
||||
}
|
||||
|
||||
typeConstructor.isTypeParameter() -> {
|
||||
|
||||
@@ -265,23 +265,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
);
|
||||
}
|
||||
|
||||
private static void addReifiedParametersFromSignature(@NotNull MemberCodegen<?> member, @NotNull ClassDescriptor descriptor) {
|
||||
private static void addReifiedParametersFromSignature(@NotNull MemberCodegen member, @NotNull ClassDescriptor descriptor) {
|
||||
for (KotlinType type : descriptor.getTypeConstructor().getSupertypes()) {
|
||||
processTypeArguments(member, type);
|
||||
}
|
||||
}
|
||||
|
||||
private static void processTypeArguments(@NotNull MemberCodegen<?> member, KotlinType type) {
|
||||
for (TypeProjection supertypeArgument : type.getArguments()) {
|
||||
if (supertypeArgument.isStarProjection()) continue;
|
||||
|
||||
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(supertypeArgument.getType());
|
||||
if (parameterDescriptor != null) {
|
||||
if (parameterDescriptor.isReified()) {
|
||||
for (TypeProjection supertypeArgument : type.getArguments()) {
|
||||
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(supertypeArgument.getType());
|
||||
if (parameterDescriptor != null && parameterDescriptor.isReified()) {
|
||||
member.getReifiedTypeParametersUsages().addUsedReifiedParameter(parameterDescriptor.getName().asString());
|
||||
}
|
||||
} else {
|
||||
processTypeArguments(member, supertypeArgument.getType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,7 +650,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
|
||||
val livenessFrames = analyzeLiveness(methodNode)
|
||||
|
||||
// References shall be cleaned up after unspill (during spill in next suspension point) to prevent memory leaks,
|
||||
// References shall be cleaned up after uspill (during spill in next suspension point) to prevent memory leaks,
|
||||
val referencesToSpillBySuspensionPointIndex = arrayListOf<List<ReferenceToSpill>>()
|
||||
// while primitives shall not
|
||||
val primitivesToSpillBySuspensionPointIndex = arrayListOf<List<PrimitiveToSpill>>()
|
||||
@@ -759,35 +759,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
referencesToCleanBySuspensionPointIndex += currentSpilledReferencesCount to predSpilledReferencesCount
|
||||
}
|
||||
|
||||
// Calculate debug metadata mapping before modifying method node to make it easier to locate
|
||||
// locals alive across suspension points.
|
||||
|
||||
fun calculateSpilledVariableAndField(
|
||||
suspension: SuspensionPoint,
|
||||
slot: Int,
|
||||
spillableVariable: SpillableVariable?
|
||||
): SpilledVariableAndField? {
|
||||
if (spillableVariable == null) return null
|
||||
val name = localVariableName(methodNode, slot, suspension.suspensionCallBegin.index()) ?: return null
|
||||
return SpilledVariableAndField(spillableVariable.fieldName, name)
|
||||
}
|
||||
|
||||
val spilledToVariableMapping = arrayListOf<List<SpilledVariableAndField>>()
|
||||
for (suspensionPointIndex in suspensionPoints.indices) {
|
||||
val suspension = suspensionPoints[suspensionPointIndex]
|
||||
|
||||
val spilledToVariable = arrayListOf<SpilledVariableAndField>()
|
||||
|
||||
referencesToSpillBySuspensionPointIndex[suspensionPointIndex].mapNotNullTo(spilledToVariable) { (slot, spillableVariable) ->
|
||||
calculateSpilledVariableAndField(suspension, slot, spillableVariable)
|
||||
}
|
||||
primitivesToSpillBySuspensionPointIndex[suspensionPointIndex].mapNotNullTo(spilledToVariable) { (slot, spillableVariable) ->
|
||||
calculateSpilledVariableAndField(suspension, slot, spillableVariable)
|
||||
}
|
||||
|
||||
spilledToVariableMapping += spilledToVariable
|
||||
}
|
||||
|
||||
// Mutate method node
|
||||
|
||||
fun generateSpillAndUnspill(suspension: SuspensionPoint, slot: Int, spillableVariable: SpillableVariable?) {
|
||||
@@ -801,22 +772,6 @@ class CoroutineTransformerMethodVisitor(
|
||||
return
|
||||
}
|
||||
|
||||
// Find and remove the local variable node, if any, in the local variable table corresponding to the slot that is spilled.
|
||||
var local: LocalVariableNode? = null
|
||||
val localRestart = LabelNode().linkWithLabel()
|
||||
val iterator = methodNode.localVariables.listIterator()
|
||||
while (iterator.hasNext()) {
|
||||
val node = iterator.next()
|
||||
if (node.index == slot &&
|
||||
methodNode.instructions.indexOf(node.start) <= methodNode.instructions.indexOf(suspension.suspensionCallBegin) &&
|
||||
methodNode.instructions.indexOf(node.end) > methodNode.instructions.indexOf(suspension.tryCatchBlockEndLabelAfterSuspensionCall)
|
||||
) {
|
||||
local = node
|
||||
iterator.remove()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
with(instructions) {
|
||||
// store variable before suspension call
|
||||
insertBefore(suspension.suspensionCallBegin, withInstructionAdapter {
|
||||
@@ -840,31 +795,8 @@ class CoroutineTransformerMethodVisitor(
|
||||
)
|
||||
StackValue.coerce(spillableVariable.normalizedType, spillableVariable.type, this)
|
||||
store(slot, spillableVariable.type)
|
||||
if (local != null) {
|
||||
visitLabel(localRestart.label)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Split the local variable range for the local so that it is visible until the next state label, but is
|
||||
// not visible until it has been unspilled from the continuation on the reentry path.
|
||||
if (local != null) {
|
||||
val previousEnd = local.end
|
||||
local.end = suspension.stateLabel
|
||||
// Add the local back, but end it at the next state label.
|
||||
methodNode.localVariables.add(local)
|
||||
// Add a new entry that starts after the local variable is restored from the continuation.
|
||||
methodNode.localVariables.add(
|
||||
LocalVariableNode(
|
||||
local.name,
|
||||
local.desc,
|
||||
local.signature,
|
||||
localRestart,
|
||||
previousEnd,
|
||||
local.index
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun cleanUpField(suspension: SuspensionPoint, fieldIndex: Int) {
|
||||
@@ -907,6 +839,33 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate debug metadata mapping
|
||||
|
||||
fun calculateSpilledVariableAndField(
|
||||
suspension: SuspensionPoint,
|
||||
slot: Int,
|
||||
spillableVariable: SpillableVariable?
|
||||
): SpilledVariableAndField? {
|
||||
if (spillableVariable == null) return null
|
||||
val name = localVariableName(methodNode, slot, suspension.suspensionCallEnd.next.index()) ?: return null
|
||||
return SpilledVariableAndField(spillableVariable.fieldName, name)
|
||||
}
|
||||
|
||||
val spilledToVariableMapping = arrayListOf<List<SpilledVariableAndField>>()
|
||||
for (suspensionPointIndex in suspensionPoints.indices) {
|
||||
val suspension = suspensionPoints[suspensionPointIndex]
|
||||
|
||||
val spilledToVariable = arrayListOf<SpilledVariableAndField>()
|
||||
|
||||
referencesToSpillBySuspensionPointIndex[suspensionPointIndex].mapNotNullTo(spilledToVariable) { (slot, spillableVariable) ->
|
||||
calculateSpilledVariableAndField(suspension, slot, spillableVariable)
|
||||
}
|
||||
primitivesToSpillBySuspensionPointIndex[suspensionPointIndex].mapNotNullTo(spilledToVariable) { (slot, spillableVariable) ->
|
||||
calculateSpilledVariableAndField(suspension, slot, spillableVariable)
|
||||
}
|
||||
|
||||
spilledToVariableMapping += spilledToVariable
|
||||
}
|
||||
return spilledToVariableMapping
|
||||
}
|
||||
|
||||
@@ -942,6 +901,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
suspendMarkerVarIndex: Int,
|
||||
suspendPointLineNumber: LineNumberNode?
|
||||
): LabelNode {
|
||||
val stateLabel = LabelNode().linkWithLabel()
|
||||
val continuationLabelAfterLoadedResult = LabelNode()
|
||||
val suspendElementLineNumber = lineNumber
|
||||
var nextLineNumberNode = nextDefinitelyHitLineNumber(suspension)
|
||||
@@ -969,7 +929,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
load(suspendMarkerVarIndex, AsmTypes.OBJECT_TYPE)
|
||||
areturn(AsmTypes.OBJECT_TYPE)
|
||||
// Mark place for continuation
|
||||
visitLabel(suspension.stateLabel.label)
|
||||
visitLabel(stateLabel.label)
|
||||
})
|
||||
|
||||
// After suspension point there is always three nodes: L1, NOP, L2
|
||||
@@ -1025,7 +985,7 @@ class CoroutineTransformerMethodVisitor(
|
||||
}
|
||||
}
|
||||
|
||||
return suspension.stateLabel
|
||||
return stateLabel
|
||||
}
|
||||
|
||||
// Find the next line number instruction that is defintely hit. That is, a line number
|
||||
@@ -1194,7 +1154,6 @@ internal class SuspensionPoint(
|
||||
) {
|
||||
lateinit var tryCatchBlocksContinuationLabel: LabelNode
|
||||
|
||||
val stateLabel = LabelNode().linkWithLabel()
|
||||
val unboxInlineClassInstructions: List<AbstractInsnNode> = findUnboxInlineClassInstructions()
|
||||
|
||||
private fun findUnboxInlineClassInstructions(): List<AbstractInsnNode> {
|
||||
|
||||
@@ -320,7 +320,8 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
|
||||
val splitBy = SimpleInterval(start.info as LabelNode, extension.finallyIntervalEnd)
|
||||
processor.tryBlocksMetaInfo.splitAndRemoveCurrentIntervals(splitBy, true)
|
||||
processor.localVarsMetaInfo.splitAndRemoveCurrentIntervals(splitBy, true);
|
||||
|
||||
//processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy);
|
||||
|
||||
mark.dropTo()
|
||||
}
|
||||
@@ -329,7 +330,8 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
}
|
||||
|
||||
processor.substituteTryBlockNodes(intoNode)
|
||||
processor.substituteLocalVarTable(intoNode);
|
||||
|
||||
//processor.substituteLocalVarTable(intoNode);
|
||||
}
|
||||
|
||||
protected abstract fun generateAssertFieldIfNeeded(info: RootInliningContext)
|
||||
|
||||
@@ -18,16 +18,12 @@ package org.jetbrains.kotlin.codegen.optimization.boxing
|
||||
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.coroutines.RELEASE_COROUTINES_VERSION_SETTINGS
|
||||
import org.jetbrains.kotlin.codegen.coroutines.coroutinesJvmInternalPackageFqName
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||
import org.jetbrains.kotlin.codegen.topLevelClassInternalName
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
@@ -178,7 +174,7 @@ fun AbstractInsnNode.isUnboxing(state: GenerationState) =
|
||||
isPrimitiveUnboxing() || isJavaLangClassUnboxing() || isInlineClassUnboxing(state)
|
||||
|
||||
fun AbstractInsnNode.isBoxing(state: GenerationState) =
|
||||
isPrimitiveBoxing() || isJavaLangClassBoxing() || isInlineClassBoxing(state) || isCoroutinePrimitiveBoxing()
|
||||
isPrimitiveBoxing() || isJavaLangClassBoxing() || isInlineClassBoxing(state)
|
||||
|
||||
fun AbstractInsnNode.isPrimitiveUnboxing() =
|
||||
isMethodInsnWith(Opcodes.INVOKEVIRTUAL) {
|
||||
@@ -215,19 +211,6 @@ fun AbstractInsnNode.isPrimitiveBoxing() =
|
||||
isBoxingMethodDescriptor()
|
||||
}
|
||||
|
||||
private val BOXING_CLASS_INTERNAL_NAME =
|
||||
RELEASE_COROUTINES_VERSION_SETTINGS.coroutinesJvmInternalPackageFqName().child(Name.identifier("Boxing")).topLevelClassInternalName()
|
||||
|
||||
private fun isJvmPrimitiveName(name: String) = JvmPrimitiveType.values().any { it.javaKeywordName == name }
|
||||
|
||||
fun AbstractInsnNode.isCoroutinePrimitiveBoxing(): Boolean {
|
||||
return isMethodInsnWith(Opcodes.INVOKESTATIC) {
|
||||
owner == BOXING_CLASS_INTERNAL_NAME &&
|
||||
name.startsWith("box") &&
|
||||
isJvmPrimitiveName(name.substring(3).lowercase())
|
||||
}
|
||||
}
|
||||
|
||||
private fun MethodInsnNode.isBoxingMethodDescriptor(): Boolean {
|
||||
val ownerType = Type.getObjectType(owner)
|
||||
return desc == Type.getMethodDescriptor(ownerType, AsmUtil.unboxType(ownerType))
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiJavaModule
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.impl.light.LightJavaModule
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.cli.common.config.ContentRoot
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
@@ -38,7 +37,6 @@ import org.jetbrains.kotlin.cli.jvm.modules.CliJavaModuleFinder
|
||||
import org.jetbrains.kotlin.cli.jvm.modules.JavaModuleGraph
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.isValidJavaFqName
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.KOTLIN_STDLIB_MODULE_NAME
|
||||
@@ -54,13 +52,10 @@ class ClasspathRootsResolver(
|
||||
private val contentRootToVirtualFile: (JvmContentRoot) -> VirtualFile?,
|
||||
private val javaModuleFinder: CliJavaModuleFinder,
|
||||
private val requireStdlibModule: Boolean,
|
||||
private val outputDirectory: VirtualFile?,
|
||||
private val javaFileManager: KotlinCliJavaFileManager
|
||||
private val outputDirectory: VirtualFile?
|
||||
) {
|
||||
val javaModuleGraph = JavaModuleGraph(javaModuleFinder)
|
||||
|
||||
private val searchScope = GlobalSearchScope.allScope(psiManager.project)
|
||||
|
||||
data class RootsAndModules(val roots: List<JavaRoot>, val modules: List<JavaModule>)
|
||||
|
||||
private data class RootWithPrefix(val root: VirtualFile, val packagePrefix: String?)
|
||||
@@ -165,7 +160,7 @@ class ClasspathRootsResolver(
|
||||
}
|
||||
|
||||
if (moduleInfoFile != null) {
|
||||
val moduleInfo = JavaModuleInfo.read(moduleInfoFile, javaFileManager, searchScope) ?: return null
|
||||
val moduleInfo = JavaModuleInfo.read(moduleInfoFile) ?: return null
|
||||
return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(root, isBinary = true)), moduleInfoFile)
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ class CliKotlinAsJavaSupport(
|
||||
return findFacadeFilesInPackage(packageFqName, scope)
|
||||
.groupBy { it.javaFileFacadeFqName }
|
||||
.mapNotNull { (facadeClassFqName, _) ->
|
||||
KtLightClassForFacadeImpl.createForFacade(psiManager, facadeClassFqName, scope)
|
||||
KtLightClassForFacade.createForFacade(psiManager, facadeClassFqName, scope)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ class CliKotlinAsJavaSupport(
|
||||
.orEmpty()
|
||||
|
||||
override fun getFacadeClasses(facadeFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
return listOfNotNull(KtLightClassForFacadeImpl.createForFacade(psiManager, facadeFqName, scope))
|
||||
return listOfNotNull(KtLightClassForFacade.createForFacade(psiManager, facadeFqName, scope))
|
||||
}
|
||||
|
||||
override fun getScriptClasses(scriptFqName: FqName, scope: GlobalSearchScope): Collection<PsiClass> {
|
||||
|
||||
@@ -35,10 +35,6 @@ class CliVirtualFileFinder(
|
||||
override fun findVirtualFileWithHeader(classId: ClassId): VirtualFile? =
|
||||
findBinaryClass(classId, classId.relativeClassName.asString().replace('.', '$') + ".class")
|
||||
|
||||
override fun findSourceOrBinaryVirtualFile(classId: ClassId) =
|
||||
findBinaryClass(classId, classId.relativeClassName.asString().replace('.', '$') + ".class")
|
||||
?: findSourceClass(classId, classId.relativeClassName.asString() + ".java")
|
||||
|
||||
override fun findMetadata(classId: ClassId): InputStream? {
|
||||
assert(!classId.isNestedClass) { "Nested classes are not supported here: $classId" }
|
||||
|
||||
@@ -65,11 +61,8 @@ class CliVirtualFileFinder(
|
||||
return findBinaryClass(classId, BuiltInSerializerProtocol.getBuiltInsFileName(packageFqName))?.inputStream
|
||||
}
|
||||
|
||||
private fun findClass(classId: ClassId, fileName: String, rootType: Set<JavaRoot.RootType>) =
|
||||
index.findClass(classId, acceptedRootTypes = rootType) { dir, _ ->
|
||||
private fun findBinaryClass(classId: ClassId, fileName: String): VirtualFile? =
|
||||
index.findClass(classId, acceptedRootTypes = JavaRoot.OnlyBinary) { dir, _ ->
|
||||
dir.findChild(fileName)?.takeIf(VirtualFile::isValid)
|
||||
}?.takeIf { it in scope }
|
||||
|
||||
private fun findBinaryClass(classId: ClassId, fileName: String) = findClass(classId, fileName, JavaRoot.OnlyBinary)
|
||||
private fun findSourceClass(classId: ClassId, fileName: String) = findClass(classId, fileName, JavaRoot.OnlySource)
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
|
||||
private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap()
|
||||
private val signatureParsingComponent = BinaryClassSignatureParser()
|
||||
|
||||
fun findClass(classId: ClassId, searchScope: GlobalSearchScope) = findClass(JavaClassFinder.Request(classId), searchScope)
|
||||
fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? = findClass(JavaClassFinder.Request(classId), searchScope)
|
||||
|
||||
override fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass? {
|
||||
val (classId, classFileContentFromRequest, outerClassFromRequest) = request
|
||||
|
||||
@@ -190,17 +190,11 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
sourceFiles.sortBy { it.virtualFile.path }
|
||||
|
||||
val javaFileManager = ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
|
||||
|
||||
val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME)
|
||||
val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL)
|
||||
val javaModuleFinder = CliJavaModuleFinder(
|
||||
jdkHome?.path?.let { path ->
|
||||
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
|
||||
},
|
||||
javaFileManager,
|
||||
project
|
||||
)
|
||||
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.path?.let { path ->
|
||||
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
|
||||
})
|
||||
|
||||
val outputDirectory =
|
||||
configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
|
||||
@@ -213,8 +207,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
this::contentRootToVirtualFile,
|
||||
javaModuleFinder,
|
||||
!configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE),
|
||||
outputDirectory?.let(this::findLocalFile),
|
||||
javaFileManager
|
||||
outputDirectory?.let(this::findLocalFile)
|
||||
)
|
||||
|
||||
val (initialRoots, javaModules) =
|
||||
@@ -238,7 +231,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
updateClasspathFromRootsIndex(this)
|
||||
}
|
||||
|
||||
javaFileManager.initialize(
|
||||
(ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl).initialize(
|
||||
rootsIndex,
|
||||
packagePartProviders,
|
||||
SingleJavaFileRootsIndex(singleJavaFileRoots),
|
||||
@@ -247,7 +240,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
project.registerService(
|
||||
JavaModuleResolver::class.java,
|
||||
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList(), project)
|
||||
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList())
|
||||
)
|
||||
|
||||
val finderFactory = CliVirtualFileFinderFactory(rootsIndex)
|
||||
|
||||
@@ -78,7 +78,10 @@ import org.jetbrains.kotlin.cli.jvm.modules.CoreJrtFileSystem
|
||||
import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension
|
||||
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.config.APPEND_JAVA_SOURCE_ROOTS_HANDLER_KEY
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.extensions.*
|
||||
import org.jetbrains.kotlin.extensions.internal.CandidateInterceptor
|
||||
import org.jetbrains.kotlin.extensions.internal.TypeResolutionInterceptor
|
||||
@@ -190,16 +193,11 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
sourceFiles.sortBy { it.virtualFile.path }
|
||||
|
||||
val javaFileManager = ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl
|
||||
|
||||
val jdkHome = configuration.get(JVMConfigurationKeys.JDK_HOME)
|
||||
val jrtFileSystem = VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.JRT_PROTOCOL)
|
||||
val javaModuleFinder = CliJavaModuleFinder(
|
||||
jdkHome?.path?.let { path ->
|
||||
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
|
||||
},
|
||||
javaFileManager
|
||||
)
|
||||
val javaModuleFinder = CliJavaModuleFinder(jdkHome?.path?.let { path ->
|
||||
jrtFileSystem?.findFileByPath(path + URLUtil.JAR_SEPARATOR)
|
||||
})
|
||||
|
||||
val outputDirectory =
|
||||
configuration.get(JVMConfigurationKeys.MODULES)?.singleOrNull()?.getOutputDirectory()
|
||||
@@ -212,8 +210,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
this::contentRootToVirtualFile,
|
||||
javaModuleFinder,
|
||||
!configuration.getBoolean(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE),
|
||||
outputDirectory?.let(this::findLocalFile),
|
||||
javaFileManager
|
||||
outputDirectory?.let(this::findLocalFile)
|
||||
)
|
||||
|
||||
val (initialRoots, javaModules) =
|
||||
@@ -237,7 +234,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
updateClasspathFromRootsIndex(this)
|
||||
}
|
||||
|
||||
javaFileManager.initialize(
|
||||
(ServiceManager.getService(project, CoreJavaFileManager::class.java) as KotlinCliJavaFileManagerImpl).initialize(
|
||||
rootsIndex,
|
||||
packagePartProviders,
|
||||
SingleJavaFileRootsIndex(singleJavaFileRoots),
|
||||
@@ -246,7 +243,7 @@ class KotlinCoreEnvironment private constructor(
|
||||
|
||||
project.registerService(
|
||||
JavaModuleResolver::class.java,
|
||||
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList(), project)
|
||||
CliJavaModuleResolver(classpathRootsResolver.javaModuleGraph, javaModules, javaModuleFinder.systemModules.toList())
|
||||
)
|
||||
|
||||
val finderFactory = CliVirtualFileFinderFactory(rootsIndex)
|
||||
|
||||
@@ -49,9 +49,6 @@ fun CompilerConfiguration.addJvmSdkRoots(files: List<File>) {
|
||||
val CompilerConfiguration.jvmClasspathRoots: List<File>
|
||||
get() = getList(CLIConfigurationKeys.CONTENT_ROOTS).filterIsInstance<JvmClasspathRoot>().map(JvmContentRoot::file)
|
||||
|
||||
val CompilerConfiguration.jvmModularRoots: List<File>
|
||||
get() = getList(CLIConfigurationKeys.CONTENT_ROOTS).filterIsInstance<JvmModulePathRoot>().map(JvmContentRoot::file)
|
||||
|
||||
@JvmOverloads
|
||||
fun CompilerConfiguration.addJavaSourceRoot(file: File, packagePrefix: String? = null) {
|
||||
add(CLIConfigurationKeys.CONTENT_ROOTS, JavaSourceRoot(file, packagePrefix))
|
||||
|
||||
@@ -45,7 +45,6 @@ data class JavaRoot(val file: VirtualFile, val type: RootType, val prefixFqName:
|
||||
|
||||
companion object RootTypes {
|
||||
val OnlyBinary: Set<RootType> = EnumSet.of(RootType.BINARY)
|
||||
val OnlySource: Set<RootType> = EnumSet.of(RootType.SOURCE)
|
||||
val SourceAndBinary: Set<RootType> = EnumSet.of(RootType.BINARY, RootType.SOURCE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,25 +16,16 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.jvm.modules
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiJavaModule
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinCliJavaFileManager
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleFinder
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
|
||||
|
||||
class CliJavaModuleFinder(
|
||||
jrtFileSystemRoot: VirtualFile?,
|
||||
private val javaFileManager: KotlinCliJavaFileManager,
|
||||
project: Project
|
||||
) : JavaModuleFinder {
|
||||
class CliJavaModuleFinder(jrtFileSystemRoot: VirtualFile?) : JavaModuleFinder {
|
||||
private val modulesRoot = jrtFileSystemRoot?.findChild("modules")
|
||||
private val userModules = linkedMapOf<String, JavaModule>()
|
||||
|
||||
private val allScope = GlobalSearchScope.allScope(project)
|
||||
|
||||
fun addUserModule(module: JavaModule) {
|
||||
userModules.putIfAbsent(module.name, module)
|
||||
}
|
||||
@@ -50,7 +41,7 @@ class CliJavaModuleFinder(
|
||||
|
||||
private fun findSystemModule(moduleRoot: VirtualFile): JavaModule.Explicit? {
|
||||
val file = moduleRoot.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE) ?: return null
|
||||
val moduleInfo = JavaModuleInfo.read(file, javaFileManager, allScope) ?: return null
|
||||
val moduleInfo = JavaModuleInfo.read(file) ?: return null
|
||||
return JavaModule.Explicit(moduleInfo, listOf(JavaModule.Root(moduleRoot, isBinary = true)), file)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,24 +18,18 @@ package org.jetbrains.kotlin.cli.jvm.modules
|
||||
|
||||
import com.intellij.ide.highlighter.JavaClassFileType
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VfsUtilCore
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
|
||||
import org.jetbrains.kotlin.load.kotlin.VirtualFileFinder
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModule
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class CliJavaModuleResolver(
|
||||
private val moduleGraph: JavaModuleGraph,
|
||||
private val userModules: List<JavaModule>,
|
||||
private val systemModules: List<JavaModule.Explicit>,
|
||||
private val project: Project
|
||||
private val systemModules: List<JavaModule.Explicit>
|
||||
) : JavaModuleResolver {
|
||||
init {
|
||||
assert(userModules.count(JavaModule::isSourceModule) <= 1) {
|
||||
@@ -43,14 +37,6 @@ class CliJavaModuleResolver(
|
||||
}
|
||||
}
|
||||
|
||||
private val virtualFileFinder by lazy { VirtualFileFinder.getInstance(project) }
|
||||
|
||||
override fun getAnnotationsForModuleOwnerOfClass(classId: ClassId): List<JavaAnnotation>? {
|
||||
val virtualFile = virtualFileFinder.findSourceOrBinaryVirtualFile(classId) ?: return null
|
||||
|
||||
return (findJavaModule(virtualFile) as? JavaModule.Explicit)?.moduleInfo?.annotations
|
||||
}
|
||||
|
||||
private val sourceModule: JavaModule? = userModules.firstOrNull(JavaModule::isSourceModule)
|
||||
|
||||
private fun findJavaModule(file: VirtualFile): JavaModule? {
|
||||
@@ -91,8 +77,4 @@ class CliJavaModuleResolver(
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val MODULE_ANNOTATIONS_CACHE_SIZE = 10000
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,11 +101,7 @@ object KotlinCompilerClient {
|
||||
fun CompileService.leaseImpl(): CompileServiceSession? {
|
||||
// the newJVMOptions could be checked here for additional parameters, if needed
|
||||
registerClient(clientAliveFlagFile.absolutePath)
|
||||
val javaExecutablePath = compilerId.javaExecutable?.absolutePath ?: "'user jvm'"
|
||||
reportingTargets.report(
|
||||
DaemonReportCategory.DEBUG,
|
||||
"connected to the daemon. Daemon is using following 'java' executable to run itself: $javaExecutablePath"
|
||||
)
|
||||
reportingTargets.report(DaemonReportCategory.DEBUG, "connected to the daemon")
|
||||
|
||||
if (!leaseSession) return CompileServiceSession(this, CompileService.NO_SESSION)
|
||||
|
||||
|
||||
@@ -2789,11 +2789,6 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("symbolsAndDescriptors.kt")
|
||||
public void testSymbolsAndDescriptors() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("transform.kt")
|
||||
public void testTransform() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/transform.kt");
|
||||
|
||||
@@ -10,7 +10,7 @@ FILE: A.kt
|
||||
}
|
||||
FILE: main.kt
|
||||
public final fun test_1(): R|kotlin/Unit| {
|
||||
lval a: <ERROR TYPE REF: Unresolved name: A> = <Unresolved name: A>#()
|
||||
lval a: R|ERROR CLASS: Unresolved name: A| = <Unresolved name: A>#()
|
||||
lval b: R|foo/A| = R|foo/A.A|()
|
||||
lval c: R|foo/A| = <Unresolved name: A>#()
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ FILE: cast.kt
|
||||
}
|
||||
|
||||
public get(): R|(kotlin/String) -> kotlin/Boolean|
|
||||
public final val hError: R|(ERROR CLASS: No type for parameter) -> kotlin/Boolean| = fun <anonymous>(_: <ERROR TYPE REF: No type for parameter>): R|kotlin/Boolean| <inline=Unknown> {
|
||||
public final val hError: R|(ERROR CLASS: No type for parameter) -> kotlin/Boolean| = fun <anonymous>(_: R|ERROR CLASS: No type for parameter|): R|kotlin/Boolean| <inline=Unknown> {
|
||||
^ Boolean(true)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,6 @@ interface B
|
||||
|
||||
fun test_2(x: Any?) {
|
||||
if (x is A && x is B) {
|
||||
<!USELESS_IS_CHECK!>x is A<!>
|
||||
x is A
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ FILE: instanceAccessBeforeSuperCall.kt
|
||||
}
|
||||
|
||||
public constructor(x: R|kotlin/Int|): R|C| {
|
||||
this<R|C|>(fun <anonymous>(): <ERROR TYPE REF: Cannot access ''<this>'' before superclass constructor has been called> <inline=Unknown> {
|
||||
this<R|C|>(fun <anonymous>(): R|ERROR CLASS: Cannot access ''<this>'' before superclass constructor has been called| <inline=Unknown> {
|
||||
lval a: R|kotlin/Int| = Int(10)
|
||||
^ this@R|/C|
|
||||
}
|
||||
@@ -63,8 +63,8 @@ FILE: instanceAccessBeforeSuperCall.kt
|
||||
}
|
||||
public final fun test(f: R|F|): R|kotlin/Unit| {
|
||||
}
|
||||
public final val a: <ERROR TYPE REF: 'this' is not defined in this context> = this#
|
||||
public get(): <ERROR TYPE REF: 'this' is not defined in this context>
|
||||
public final val a: R|ERROR CLASS: 'this' is not defined in this context| = this#
|
||||
public get(): R|ERROR CLASS: 'this' is not defined in this context|
|
||||
public final class F : R|kotlin/Any| {
|
||||
public constructor(a: R|kotlin/Int|, b: R|kotlin/Int|, closure: R|() -> kotlin/Unit|, instance: R|F?|): R|F| {
|
||||
super<R|kotlin/Any|>()
|
||||
|
||||
@@ -13,7 +13,7 @@ FILE: superIsNotAnExpression.kt
|
||||
public final fun act(): R|kotlin/Unit| {
|
||||
<Super cannot be a callee>#()
|
||||
<Unresolved name: invoke>#()
|
||||
<Super cannot be a callee>#(<L> = <Super cannot be a callee>@fun <anonymous>(): <ERROR TYPE REF: Unresolved name: println> <inline=Unknown> {
|
||||
<Super cannot be a callee>#(<L> = <Super cannot be a callee>@fun <anonymous>(): R|ERROR CLASS: Unresolved name: println| <inline=Unknown> {
|
||||
^ <Unresolved name: println>#(ERROR_EXPR(Incorrect character: 'weird'))
|
||||
}
|
||||
)
|
||||
|
||||
@@ -22,10 +22,10 @@ FILE: typeArgumentsNotAllowed.kt
|
||||
}
|
||||
|
||||
}
|
||||
public final val a: <ERROR TYPE REF: Unresolved name: MyClass> = Q|rest|.<Unresolved name: MyClass>#
|
||||
public get(): <ERROR TYPE REF: Unresolved name: MyClass>
|
||||
public final val b: <ERROR TYPE REF: Unresolved name: MyClass> = Q|rest/Best|.<Unresolved name: MyClass>#
|
||||
public get(): <ERROR TYPE REF: Unresolved name: MyClass>
|
||||
public final val a: R|ERROR CLASS: Unresolved name: MyClass| = Q|rest|.<Unresolved name: MyClass>#
|
||||
public get(): R|ERROR CLASS: Unresolved name: MyClass|
|
||||
public final val b: R|ERROR CLASS: Unresolved name: MyClass| = Q|rest/Best|.<Unresolved name: MyClass>#
|
||||
public get(): R|ERROR CLASS: Unresolved name: MyClass|
|
||||
public final class B<E> : R|kotlin/Any| {
|
||||
public constructor<E>(): R|rest/B<E>| {
|
||||
super<R|kotlin/Any|>()
|
||||
|
||||
@@ -22,7 +22,7 @@ FILE: upperBoundViolated.kt
|
||||
lval b1: R|B<kotlin/Int>| = R|/B.B|<R|kotlin/Int|>()
|
||||
lval b2: R|B<C>| = R|/B.B|<R|C|>()
|
||||
lval b3: R|B<kotlin/Any?>| = R|/B.B|<R|kotlin/Any?|>()
|
||||
lval b4: <ERROR TYPE REF: Unresolved name: NumberPhile> = R|/B.B|<<ERROR TYPE REF: Symbol not found for UnexistingType>>().<Unresolved name: NL>#(ERROR_EXPR(No right operand)).<Unresolved name: Int>#(<Call has no callee>#()).<Unresolved name: NumberPhile>#(ERROR_EXPR(No right operand))
|
||||
lval b4: R|ERROR CLASS: Unresolved name: NumberPhile| = R|/B.B|<<ERROR TYPE REF: Symbol not found for UnexistingType>>().<Unresolved name: NL>#(ERROR_EXPR(No right operand)).<Unresolved name: Int>#(<Call has no callee>#()).<Unresolved name: NumberPhile>#(ERROR_EXPR(No right operand))
|
||||
lval b5: R|B<B<ERROR CLASS: Symbol not found for UnexistingType>>| = R|/B.B|<R|B<ERROR CLASS: Symbol not found for UnexistingType>|>()
|
||||
R|/fest|<R|kotlin/Boolean|>()
|
||||
R|/fest|<R|C|>()
|
||||
@@ -58,8 +58,8 @@ FILE: upperBoundViolated.kt
|
||||
|
||||
}
|
||||
public final typealias NL<K> = R|NumColl<kotlin/collections/List<K>>|
|
||||
public final val test7: <ERROR TYPE REF: Unresolved name: NumberPhile> = R|/NumColl.NumColl|<R|kotlin/Int|>().<Unresolved name: NumberPhile>#(ERROR_EXPR(No right operand))
|
||||
public get(): <ERROR TYPE REF: Unresolved name: NumberPhile>
|
||||
public final val test7: R|ERROR CLASS: Unresolved name: NumberPhile| = R|/NumColl.NumColl|<R|kotlin/Int|>().<Unresolved name: NumberPhile>#(ERROR_EXPR(No right operand))
|
||||
public get(): R|ERROR CLASS: Unresolved name: NumberPhile|
|
||||
public final val test8: R|NumColl<kotlin/collections/List<kotlin/String>>| = R|/NumColl.NumColl|<R|kotlin/String|>()
|
||||
public get(): R|NumColl<kotlin/collections/List<kotlin/String>>|
|
||||
public final class NumberPhile<T : R|kotlin/Number|> : R|kotlin/Any| {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
FILE: main.kt
|
||||
public final fun test_1(e: R|JavaEnum|): R|kotlin/Unit| {
|
||||
lval a: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
|
||||
lval a: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
|
||||
==($subj$, Q|JavaEnum|.R|/JavaEnum.A|) -> {
|
||||
Int(1)
|
||||
}
|
||||
@@ -9,7 +9,7 @@ FILE: main.kt
|
||||
}
|
||||
}
|
||||
.<Unresolved name: plus>#(Int(0))
|
||||
lval b: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
|
||||
lval b: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
|
||||
==($subj$, Q|JavaEnum|.R|/JavaEnum.A|) -> {
|
||||
Int(1)
|
||||
}
|
||||
@@ -44,7 +44,7 @@ FILE: main.kt
|
||||
.R|kotlin/Int.plus|(Int(0))
|
||||
}
|
||||
public final fun test_2(e: R|JavaEnum?|): R|kotlin/Unit| {
|
||||
lval a: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
|
||||
lval a: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
|
||||
==($subj$, Q|JavaEnum|.R|/JavaEnum.A|) -> {
|
||||
Int(1)
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ FILE: exhaustiveness_sealedSubClass.kt
|
||||
.R|kotlin/Int.plus|(Int(0))
|
||||
}
|
||||
public final fun test_2(e: R|A|): R|kotlin/Unit| {
|
||||
lval a: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
|
||||
lval a: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
|
||||
($subj$ is R|D|) -> {
|
||||
Int(1)
|
||||
}
|
||||
@@ -86,7 +86,7 @@ FILE: exhaustiveness_sealedSubClass.kt
|
||||
}
|
||||
}
|
||||
.<Unresolved name: plus>#(Int(0))
|
||||
lval b: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
|
||||
lval b: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
|
||||
($subj$ is R|B|) -> {
|
||||
Int(1)
|
||||
}
|
||||
@@ -98,7 +98,7 @@ FILE: exhaustiveness_sealedSubClass.kt
|
||||
}
|
||||
}
|
||||
.<Unresolved name: plus>#(Int(0))
|
||||
lval c: <ERROR TYPE REF: Unresolved name: plus> = when (R|<local>/e|) {
|
||||
lval c: R|ERROR CLASS: Unresolved name: plus| = when (R|<local>/e|) {
|
||||
($subj$ is R|B|) -> {
|
||||
Int(1)
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ fun test_1(e: A) {
|
||||
|
||||
val d = when (e) {
|
||||
is E -> 1
|
||||
<!USELESS_IS_CHECK!>is A<!> -> 2
|
||||
is A -> 2
|
||||
}.plus(0)
|
||||
}
|
||||
|
||||
|
||||
@@ -29,8 +29,8 @@ FILE: CallBasedInExpressionGenerator.kt
|
||||
public final val codegen: R|org/jetbrains/kotlin/codegen/range/inExpression/ExpressionCodegen| = R|<local>/codegen|
|
||||
public get(): R|org/jetbrains/kotlin/codegen/range/inExpression/ExpressionCodegen|
|
||||
|
||||
private final val resolvedCall: <ERROR TYPE REF: Unresolved name: getResolvedCallWithAssert> = R|<local>/operatorReference|.<Unresolved name: getResolvedCallWithAssert>#(this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.codegen|.<Unresolved name: bindingContext>#)
|
||||
private get(): <ERROR TYPE REF: Unresolved name: getResolvedCallWithAssert>
|
||||
private final val resolvedCall: R|ERROR CLASS: Unresolved name: getResolvedCallWithAssert| = R|<local>/operatorReference|.<Unresolved name: getResolvedCallWithAssert>#(this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.codegen|.<Unresolved name: bindingContext>#)
|
||||
private get(): R|ERROR CLASS: Unresolved name: getResolvedCallWithAssert|
|
||||
|
||||
private final val isInverted: R|kotlin/Boolean| = ==(R|<local>/operatorReference|.<Unresolved name: getReferencedNameElementType>#(), <Unresolved name: KtTokens>#.<Unresolved name: NOT_IN>#)
|
||||
private get(): R|kotlin/Boolean|
|
||||
@@ -75,7 +75,7 @@ FILE: CallBasedInExpressionGenerator.kt
|
||||
}
|
||||
|
||||
private final fun invokeFunction(v: R|org/jetbrains/kotlin/codegen/range/inExpression/InstructionAdapter|): R|kotlin/Unit| {
|
||||
lval result: <ERROR TYPE REF: Unresolved name: invokeFunction> = this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.codegen|.<Unresolved name: invokeFunction>#(this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.resolvedCall|.<Unresolved name: call>#, this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.resolvedCall|, <Unresolved name: none>#())
|
||||
lval result: R|ERROR CLASS: Unresolved name: invokeFunction| = this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.codegen|.<Unresolved name: invokeFunction>#(this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.resolvedCall|.<Unresolved name: call>#, this@R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator|.R|org/jetbrains/kotlin/codegen/range/inExpression/CallBasedInExpressionGenerator.resolvedCall|, <Unresolved name: none>#())
|
||||
R|<local>/result|.<Unresolved name: put>#(R|<local>/result|.<Unresolved name: type>#, R|<local>/result|.<Unresolved name: kotlinType>#, R|<local>/v|)
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ FILE: access.kt
|
||||
lval a: R|kotlin/Int| = Int(10)
|
||||
lval b: R|kotlin/Int| = R|<local>/a|
|
||||
lval d: R|kotlin/String| = String()
|
||||
lval c: <ERROR TYPE REF: Unresolved name: c> = <Unresolved name: c>#
|
||||
lval c: R|ERROR CLASS: Unresolved name: c| = <Unresolved name: c>#
|
||||
<Unresolved name: abc>#()
|
||||
local final fun bcd(): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ FILE: Test.kt
|
||||
lval bbd: R|BB.D| = Q|BB.D|
|
||||
lval aac: R|AA.C| = Q|AA.C|
|
||||
Q|JavaClass|.R|/JavaClass.bar|()
|
||||
lval errC: <ERROR TYPE REF: Unresolved name: C> = Q|BB|.<Unresolved name: C>#
|
||||
lval errBarViaBB: <ERROR TYPE REF: Unresolved name: bar> = Q|BB|.<Unresolved name: bar>#()
|
||||
lval errBarViaAA: <ERROR TYPE REF: Unresolved name: bar> = Q|AA|.<Unresolved name: bar>#()
|
||||
lval errC: R|ERROR CLASS: Unresolved name: C| = Q|BB|.<Unresolved name: C>#
|
||||
lval errBarViaBB: R|ERROR CLASS: Unresolved name: bar| = Q|BB|.<Unresolved name: bar>#()
|
||||
lval errBarViaAA: R|ERROR CLASS: Unresolved name: bar| = Q|AA|.<Unresolved name: bar>#()
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ class Factory {
|
||||
}
|
||||
|
||||
companion object {
|
||||
val f = <!NO_COMPANION_OBJECT!>Function<!>
|
||||
val f = Function
|
||||
val x = Function.Default
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,5 +47,5 @@ FILE: companion.kt
|
||||
Q|B|.R|/B.Companion.baz|()
|
||||
lval x: R|kotlin/String| = Q|A|.R|/A.Companion.D|
|
||||
lval y: R|kotlin/String| = Q|B|.R|/B.Companion.C|
|
||||
lval z: <ERROR TYPE REF: Unresolved name: D> = Q|B|.<Unresolved name: D>#
|
||||
lval z: R|ERROR CLASS: Unresolved name: D| = Q|B|.<Unresolved name: D>#
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ FILE: errCallable.kt
|
||||
}
|
||||
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
lval x: <ERROR TYPE REF: Unresolved reference: Nested> = ::<Unresolved reference: Nested>#
|
||||
lval x: R|ERROR CLASS: Unresolved reference: Nested| = ::<Unresolved reference: Nested>#
|
||||
}
|
||||
|
||||
}
|
||||
public final fun R|Your|.foo(): R|kotlin/Unit| {
|
||||
lval x: <ERROR TYPE REF: Unresolved reference: Nested> = ::<Unresolved reference: Nested>#
|
||||
lval x: R|ERROR CLASS: Unresolved reference: Nested| = ::<Unresolved reference: Nested>#
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ class Outer {
|
||||
inner class Inner
|
||||
}
|
||||
|
||||
val x = Outer.<!NO_COMPANION_OBJECT!>Inner<!>
|
||||
val x = Outer.Inner
|
||||
val klass = Outer.Inner::class
|
||||
|
||||
@@ -40,5 +40,5 @@ FILE: localObjects.kt
|
||||
|
||||
Q|B|.R|/B.foo|()
|
||||
}
|
||||
public final val bb: <ERROR TYPE REF: Unresolved name: foo> = <Unresolved name: B>#.<Unresolved name: foo>#()
|
||||
public get(): <ERROR TYPE REF: Unresolved name: foo>
|
||||
public final val bb: R|ERROR CLASS: Unresolved name: foo| = <Unresolved name: B>#.<Unresolved name: foo>#()
|
||||
public get(): R|ERROR CLASS: Unresolved name: foo|
|
||||
|
||||
@@ -25,7 +25,7 @@ FILE: nestedObjects.kt
|
||||
}
|
||||
|
||||
}
|
||||
public final val err: <ERROR TYPE REF: Unresolved name: B> = Q|B|.<Unresolved name: A>#.<Unresolved name: B>#
|
||||
public get(): <ERROR TYPE REF: Unresolved name: B>
|
||||
public final val err: R|ERROR CLASS: Unresolved name: B| = Q|B|.<Unresolved name: A>#.<Unresolved name: B>#
|
||||
public get(): R|ERROR CLASS: Unresolved name: B|
|
||||
public final val correct: R|A.B.A| = Q|A.B.A|
|
||||
public get(): R|A.B.A|
|
||||
|
||||
@@ -33,7 +33,7 @@ FILE: privateObjectLiteral.kt
|
||||
|
||||
internal get(): R|kotlin/Any|
|
||||
|
||||
public final val w: <ERROR TYPE REF: Unresolved name: foo> = this@R|/C|.R|/C.z|.<Unresolved name: foo>#()
|
||||
public get(): <ERROR TYPE REF: Unresolved name: foo>
|
||||
public final val w: R|ERROR CLASS: Unresolved name: foo| = this@R|/C|.R|/C.z|.<Unresolved name: foo>#()
|
||||
public get(): R|ERROR CLASS: Unresolved name: foo|
|
||||
|
||||
}
|
||||
|
||||
@@ -23,8 +23,7 @@ object D {
|
||||
val D.E get() = ""
|
||||
|
||||
val def = D.E.F // object
|
||||
// See KT-46409
|
||||
val de = D.<!NO_COMPANION_OBJECT!>E<!> // Should be: extension & no error, in fact: qualifier
|
||||
val de = D.E // extension
|
||||
|
||||
enum class G {
|
||||
H;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
fun foo() = if (true) 1 else 0
|
||||
|
||||
fun bar(arg: Any?) = when (arg) {
|
||||
is Int -> arg <!USELESS_CAST!>as Int<!>
|
||||
is Int -> arg as Int
|
||||
else -> 42
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ FILE: inner.kt
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
lval o: R|Owner| = R|/Owner.Owner|()
|
||||
R|<local>/o|.R|/Owner.foo|()
|
||||
lval err: <ERROR TYPE REF: Unresolved name: Inner> = Q|Owner|.<Unresolved name: Inner>#()
|
||||
lval err: R|ERROR CLASS: Unresolved name: Inner| = Q|Owner|.<Unresolved name: Inner>#()
|
||||
R|<local>/err|.<Unresolved name: baz>#()
|
||||
lval i: R|Owner.Inner| = R|<local>/o|.R|/Owner.Inner.Inner|()
|
||||
R|<local>/i|.R|/Owner.Inner.gau|()
|
||||
|
||||
@@ -32,7 +32,7 @@ fun case1(javaClass: JavaClass?) {
|
||||
}
|
||||
|
||||
class Case1(val javaClass: JavaClass?) {
|
||||
val x = if (javaClass != null) { it -> <!EQUALITY_NOT_APPLICABLE_WARNING!>it == javaClass<!> } else BooCase2.FILTER
|
||||
val x = if (javaClass != null) { it -> it == javaClass } else BooCase2.FILTER
|
||||
}
|
||||
|
||||
class BooCase1() {
|
||||
|
||||
@@ -35,7 +35,7 @@ FILE: nestedClassContructor.kt
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
lval a: R|A| = R|/A.A|()
|
||||
lval ac: R|A.C| = Q|A|.R|/A.C.C|()
|
||||
lval c: <ERROR TYPE REF: Unresolved name: C> = <Unresolved name: C>#()
|
||||
lval c: R|ERROR CLASS: Unresolved name: C| = <Unresolved name: C>#()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ FILE: test.kt
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
lval descriptor: R|WrappedPropertyDescriptor| = R|/WrappedPropertyDescriptor.WrappedPropertyDescriptor|()
|
||||
lval res1: R|kotlin/String| = R|<local>/descriptor|.R|/WrappedPropertyDescriptor.setter|
|
||||
lval res2: <ERROR TYPE REF: Unresolved name: getSetter> = R|<local>/descriptor|.<Unresolved name: getSetter>#()
|
||||
lval res2: R|ERROR CLASS: Unresolved name: getSetter| = R|<local>/descriptor|.<Unresolved name: getSetter>#()
|
||||
lval res3: R|kotlin/Boolean| = R|<local>/descriptor|.R|/WrappedPropertyDescriptor.isDelegated|
|
||||
lval res4: <ERROR TYPE REF: Unresolved name: isDelegated> = R|<local>/descriptor|.<Unresolved name: isDelegated>#()
|
||||
lval res4: R|ERROR CLASS: Unresolved name: isDelegated| = R|<local>/descriptor|.<Unresolved name: isDelegated>#()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
FILE: main.kt
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
lval some: R|foo/Some| = R|foo/Some.Some|()
|
||||
lval another: <ERROR TYPE REF: Unresolved name: Another> = <Unresolved name: Another>#()
|
||||
lval another: R|ERROR CLASS: Unresolved name: Another| = <Unresolved name: Another>#()
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// FIR_IDE_IGNORE
|
||||
// FILE: foo/Some.java
|
||||
|
||||
package foo;
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
FILE: symbolsAndDescriptors.kt
|
||||
public final class IrClassSymbolImpl : R|IrBindableSymbolBase<kotlin/String>|, R|IrClassSymbol| {
|
||||
public constructor(descriptor: R|kotlin/String?| = Null(null)): R|IrClassSymbolImpl| {
|
||||
super<R|IrBindableSymbolBase<kotlin/String>|>(R|<local>/descriptor|)
|
||||
}
|
||||
|
||||
}
|
||||
public abstract interface IrClassSymbol : R|IrClassifierSymbol|, R|IrBindableSymbol<kotlin/String>| {
|
||||
}
|
||||
public abstract interface IrClassifierSymbol : R|IrSymbol|, R|TypeConstructorMarker| {
|
||||
public abstract override val descriptor: R|kotlin/CharSequence|
|
||||
public get(): R|kotlin/CharSequence|
|
||||
|
||||
}
|
||||
public abstract interface IrSymbol : R|kotlin/Any| {
|
||||
public abstract val descriptor: R|kotlin/Any|
|
||||
public get(): R|kotlin/Any|
|
||||
|
||||
}
|
||||
public abstract interface TypeConstructorMarker : R|kotlin/Any| {
|
||||
}
|
||||
public abstract interface IrBindableSymbol<out D : R|kotlin/Any|> : R|IrSymbol| {
|
||||
public abstract override val descriptor: R|D|
|
||||
public get(): R|D|
|
||||
|
||||
}
|
||||
public abstract class IrBindableSymbolBase<out D : R|kotlin/Any|> : R|IrBindableSymbol<D>|, R|IrSymbolBase<D>| {
|
||||
public constructor<out D : R|kotlin/Any|>(descriptor: R|D?|): R|IrBindableSymbolBase<D>| {
|
||||
super<R|IrSymbolBase<D>|>(R|<local>/descriptor|)
|
||||
}
|
||||
|
||||
}
|
||||
public abstract class IrSymbolBase<out D : R|kotlin/Any|> : R|IrSymbol| {
|
||||
public constructor<out D : R|kotlin/Any|>(_descriptor: R|D?|): R|IrSymbolBase<D>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
private final val _descriptor: R|D?| = R|<local>/_descriptor|
|
||||
private get(): R|D?|
|
||||
|
||||
public open override val descriptor: R|D|
|
||||
public get(): R|D| {
|
||||
^ this@R|/IrSymbolBase|.R|/IrSymbolBase._descriptor|!!
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
class IrClassSymbolImpl(descriptor: String? = null) :
|
||||
IrBindableSymbolBase<String>(descriptor),
|
||||
IrClassSymbol
|
||||
|
||||
interface IrClassSymbol : IrClassifierSymbol, IrBindableSymbol<String>
|
||||
|
||||
interface IrClassifierSymbol : IrSymbol, TypeConstructorMarker {
|
||||
override val descriptor: CharSequence
|
||||
}
|
||||
|
||||
interface IrSymbol {
|
||||
val descriptor: Any
|
||||
}
|
||||
|
||||
interface TypeConstructorMarker
|
||||
|
||||
interface IrBindableSymbol<out D : Any> : IrSymbol {
|
||||
override val descriptor: D
|
||||
}
|
||||
|
||||
abstract class IrBindableSymbolBase<out D : Any>(descriptor: D?) :
|
||||
IrBindableSymbol<D>, IrSymbolBase<D>(descriptor)
|
||||
|
||||
abstract class IrSymbolBase<out D : Any>(
|
||||
private val _descriptor: D?
|
||||
) : IrSymbol {
|
||||
override val descriptor: D
|
||||
get() = _descriptor!!
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
FILE: main.kt
|
||||
public final fun test_1(x: R|A|): R|kotlin/Unit| {
|
||||
lval str1: R|ft<kotlin/String, kotlin/String?>| = R|<local>/x|.R|/A.vmParameters|
|
||||
lval str2: <ERROR TYPE REF: Unresolved name: vMParameters> = R|<local>/x|.<Unresolved name: vMParameters>#
|
||||
lval str2: R|ERROR CLASS: Unresolved name: vMParameters| = R|<local>/x|.<Unresolved name: vMParameters>#
|
||||
}
|
||||
public final fun test_2(x: R|B|): R|kotlin/Unit| {
|
||||
lval int: R|ft<kotlin/Int, kotlin/Int?>| = R|<local>/x|.R|/B.vmParameters|
|
||||
lval error: <ERROR TYPE REF: Unresolved name: vMParameters> = R|<local>/x|.<Unresolved name: vMParameters>#
|
||||
lval error: R|ERROR CLASS: Unresolved name: vMParameters| = R|<local>/x|.<Unresolved name: vMParameters>#
|
||||
}
|
||||
public final fun test_3(x: R|C|): R|kotlin/Unit| {
|
||||
lval error: <ERROR TYPE REF: Ambiguity: vmParameters, [/C.vmParameters, /C.vmParameters]> = R|<local>/x|.<Ambiguity: vmParameters, [/C.vmParameters, /C.vmParameters]>#
|
||||
lval int: <ERROR TYPE REF: Unresolved name: vMParameters> = R|<local>/x|.<Unresolved name: vMParameters>#
|
||||
lval error: R|ERROR CLASS: Ambiguity: vmParameters, [/C.vmParameters, /C.vmParameters]| = R|<local>/x|.<Ambiguity: vmParameters, [/C.vmParameters, /C.vmParameters]>#
|
||||
lval int: R|ERROR CLASS: Unresolved name: vMParameters| = R|<local>/x|.<Unresolved name: vMParameters>#
|
||||
}
|
||||
public final class Foo : R|kotlin/Any| {
|
||||
public constructor(): R|Foo| {
|
||||
|
||||
@@ -7,7 +7,7 @@ FILE: leakedImplicitType.kt
|
||||
public final fun bar(): R|kotlin/Unit| {
|
||||
}
|
||||
|
||||
public final fun f(): <ERROR TYPE REF: Unresolved reference: bar> {
|
||||
public final fun f(): R|ERROR CLASS: Unresolved reference: bar| {
|
||||
^f <Unresolved name: Unresolved>#()::<Unresolved reference: bar>#
|
||||
}
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ FILE: referenceToExtension.kt
|
||||
}
|
||||
|
||||
public final fun test_2(): R|kotlin/Unit| {
|
||||
lval extensionValRef: <ERROR TYPE REF: Unresolved reference: extensionVal> = Q|GenericTest.B|::<Unresolved reference: extensionVal>#
|
||||
lval extensionFunRef: <ERROR TYPE REF: Unresolved reference: extensionFun> = Q|GenericTest.B|::<Unresolved reference: extensionFun>#
|
||||
lval extensionValRef: R|ERROR CLASS: Unresolved reference: extensionVal| = Q|GenericTest.B|::<Unresolved reference: extensionVal>#
|
||||
lval extensionFunRef: R|ERROR CLASS: Unresolved reference: extensionFun| = Q|GenericTest.B|::<Unresolved reference: extensionFun>#
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ class Some
|
||||
fun foo(): () -> Boolean {
|
||||
val s = Some()
|
||||
if (true) {
|
||||
return { if (<!USELESS_IS_CHECK!>s is Some<!>) true else false }
|
||||
return { if (s is Some) true else false }
|
||||
} else {
|
||||
return { true }
|
||||
}
|
||||
|
||||
@@ -45,12 +45,12 @@ fun case3() {
|
||||
|
||||
val flag = "" //A
|
||||
val l1 = <!NO_ELSE_IN_WHEN!>when<!> (flag<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>) {// should be NO_ELSE_IN_WHEN
|
||||
<!INCOMPATIBLE_TYPES!>A.A1<!> -> B() //should be INCOMPATIBLE_TYPES
|
||||
<!INCOMPATIBLE_TYPES!>A.A2<!> -> B() //should be INCOMPATIBLE_TYPES
|
||||
A.A1 -> B() //should be INCOMPATIBLE_TYPES
|
||||
A.A2 -> B() //should be INCOMPATIBLE_TYPES
|
||||
}
|
||||
|
||||
val l2 = <!NO_ELSE_IN_WHEN!>when<!> (flag) {// should be NO_ELSE_IN_WHEN
|
||||
<!INCOMPATIBLE_TYPES!>A.A1<!> -> B() //should be INCOMPATIBLE_TYPES
|
||||
<!INCOMPATIBLE_TYPES!>A.A2<!> -> B() //should be INCOMPATIBLE_TYPES
|
||||
A.A1 -> B() //should be INCOMPATIBLE_TYPES
|
||||
A.A2 -> B() //should be INCOMPATIBLE_TYPES
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ FILE: beyoundCalls.kt
|
||||
}
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
lval x: R|(kotlin/String) -> kotlin/Int| = ::R|/bar|
|
||||
lval y: <ERROR TYPE REF: Ambiguity: bar, [/bar, /bar]> = ::<Ambiguity: bar, [/bar, /bar]>#
|
||||
lval y: R|ERROR CLASS: Ambiguity: bar, [/bar, /bar]| = ::<Ambiguity: bar, [/bar, /bar]>#
|
||||
lval z: R|kotlin/reflect/KFunction1<kotlin/String, kotlin/Int>| = ::R|/baz|
|
||||
lval w: R|(kotlin/String) -> kotlin/Int| = ::R|/foobaz<kotlin/String, kotlin/Int>|
|
||||
::R|/baz|
|
||||
|
||||
@@ -9,7 +9,7 @@ FILE: moreSpecificAmbiguousExtensions.kt
|
||||
}
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
lval extFun1: R|@ExtensionFunctionType kotlin/reflect/KFunction2<IA, IB, kotlin/Unit>| = Q|IA|::R|/extFun|
|
||||
lval extFun2: <ERROR TYPE REF: Ambiguity: extFun, [/extFun, /extFun]> = Q|IB|::<Ambiguity: extFun, [/extFun, /extFun]>#
|
||||
lval extFun2: R|ERROR CLASS: Ambiguity: extFun, [/extFun, /extFun]| = Q|IB|::<Ambiguity: extFun, [/extFun, /extFun]>#
|
||||
}
|
||||
public final fun testWithExpectedType(): R|kotlin/Unit| {
|
||||
lval extFun_AB_A: R|IA.(IB) -> kotlin/Unit| = Q|IA|::R|/extFun|
|
||||
|
||||
@@ -172,9 +172,9 @@ FILE: forLoopChecker.kt
|
||||
}
|
||||
public final fun test(notRange1: R|NotRange1|, notRange2: R|NotRange2|, notRange3: R|NotRange3|, notRange4: R|NotRange4|, notRange5: R|NotRange5|, notRange6: R|NotRange6|, notRange7: R|NotRange7|, notRange8: R|NotRange8|, notRange9: R|NotRange9|, range0: R|Range0|, range1: R|Range1|): R|kotlin/Unit| {
|
||||
{
|
||||
lval <iterator>: <ERROR TYPE REF: Unresolved name: iterator> = R|<local>/notRange1|.<Unresolved name: iterator>#()
|
||||
lval <iterator>: R|ERROR CLASS: Unresolved name: iterator| = R|<local>/notRange1|.<Unresolved name: iterator>#()
|
||||
while(R|<local>/<iterator>|.<Unresolved name: hasNext>#()) {
|
||||
lval i: <ERROR TYPE REF: Unresolved name: next> = R|<local>/<iterator>|.<Unresolved name: next>#()
|
||||
lval i: R|ERROR CLASS: Unresolved name: next| = R|<local>/<iterator>|.<Unresolved name: next>#()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -182,7 +182,7 @@ FILE: forLoopChecker.kt
|
||||
{
|
||||
lval <iterator>: R|kotlin/Unit| = R|<local>/notRange2|.R|/NotRange2.iterator|()
|
||||
while(R|<local>/<iterator>|.<Unresolved name: hasNext>#()) {
|
||||
lval i: <ERROR TYPE REF: Unresolved name: next> = R|<local>/<iterator>|.<Unresolved name: next>#()
|
||||
lval i: R|ERROR CLASS: Unresolved name: next| = R|<local>/<iterator>|.<Unresolved name: next>#()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -190,7 +190,7 @@ FILE: forLoopChecker.kt
|
||||
{
|
||||
lval <iterator>: R|ImproperIterator1| = R|<local>/notRange3|.R|/NotRange3.iterator|()
|
||||
while(R|<local>/<iterator>|.R|/ImproperIterator1.hasNext|()) {
|
||||
lval i: <ERROR TYPE REF: Unresolved name: next> = R|<local>/<iterator>|.<Unresolved name: next>#()
|
||||
lval i: R|ERROR CLASS: Unresolved name: next| = R|<local>/<iterator>|.<Unresolved name: next>#()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// FIR_IDE_IGNORE
|
||||
// FILE: K1.kt
|
||||
class KSub : J1()
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ FILE: test.kt
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
private final val klass: R|java/lang/Class<out MyTest>| = <getClass>(this@R|/MyTest|).R|kotlin/jvm/java|<R|MyTest|>
|
||||
private get(): R|java/lang/Class<out MyTest>|
|
||||
private final val klass: R|java/lang/Class<MyTest>| = <getClass>(this@R|/MyTest|).R|kotlin/jvm/java|<R|MyTest|>
|
||||
private get(): R|java/lang/Class<MyTest>|
|
||||
|
||||
private final val logger: R|ft<Logger, Logger?>| = Q|Logger|.R|/Logger.getInstance|(this@R|/MyTest|.R|/MyTest.klass|)
|
||||
private get(): R|ft<Logger, Logger?>|
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
// FIR_IDE_IGNORE
|
||||
// FILE: K1.kt
|
||||
class K2: J1() {
|
||||
class Q : <!UNRESOLVED_REFERENCE!>Nested<!>()
|
||||
|
||||
@@ -14,7 +14,7 @@ class Case1() {
|
||||
|
||||
this.yield("") //UNRESOLVED_REFERENCE
|
||||
|
||||
this <!USELESS_CAST!>as SequenceScope<String><!>
|
||||
this as SequenceScope<String>
|
||||
|
||||
yield("") // resolved to SequenceScope.yield
|
||||
|
||||
@@ -31,10 +31,10 @@ fun case2() {
|
||||
|
||||
this.yield("") //UNRESOLVED_REFERENCE
|
||||
|
||||
this <!USELESS_CAST!>as SequenceScope<String><!>
|
||||
this as SequenceScope<String>
|
||||
|
||||
yield("") // UNRESOLVED_REFERENCE
|
||||
|
||||
this.yield("") // UNRESOLVED_REFERENCE
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3159,12 +3159,6 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("symbolsAndDescriptors.kt")
|
||||
public void testSymbolsAndDescriptors() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("transform.kt")
|
||||
public void testTransform() throws Exception {
|
||||
|
||||
@@ -3159,12 +3159,6 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/secondaryConstructorCfg.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("symbolsAndDescriptors.kt")
|
||||
public void testSymbolsAndDescriptors() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/symbolsAndDescriptors.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("transform.kt")
|
||||
public void testTransform() throws Exception {
|
||||
|
||||
@@ -620,12 +620,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("RecursiveTypeParameterEqualityCheck.kt")
|
||||
public void testRecursiveTypeParameterEqualityCheck() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/RecursiveTypeParameterEqualityCheck.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ReserveYield.kt")
|
||||
public void testReserveYield() throws Exception {
|
||||
@@ -9077,12 +9071,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/enum/starImportNestedClassAndEntries.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typeCompatibility.kt")
|
||||
public void testTypeCompatibility() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/enum/typeCompatibility.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typeParametersInEnum.kt")
|
||||
public void testTypeParametersInEnum() throws Exception {
|
||||
@@ -12599,12 +12587,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/inference/violatingUpperBoundForSelfType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("violatingUpperBoundForSelfTypeError.kt")
|
||||
public void testViolatingUpperBoundForSelfTypeError() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/violatingUpperBoundForSelfTypeError.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@@ -16858,12 +16840,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("abstractBaseClassMemberNotImplemented_15.kt")
|
||||
public void testAbstractBaseClassMemberNotImplemented_15() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("abstractVsAbstract.kt")
|
||||
public void testAbstractVsAbstract() throws Exception {
|
||||
@@ -16893,12 +16869,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/java8Overrides/implementingMethodOfAny.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt45508.kt")
|
||||
public void testKt45508() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/java8Overrides/kt45508.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("notAMethodOfAny.kt")
|
||||
public void testNotAMethodOfAny() throws Exception {
|
||||
@@ -21160,18 +21130,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/arrays.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt")
|
||||
public void testDontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt")
|
||||
public void testDontSubstituteAnotherErasedTypeArgumentIfRecursive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("errorType.kt")
|
||||
public void testErrorType() throws Exception {
|
||||
@@ -21262,30 +21220,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/starProjectionToRaw.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("substituteAnotherErasedTypeArgument.kt")
|
||||
public void testSubstituteAnotherErasedTypeArgument() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("substituteOtherErasedDeepTypeArguments.kt")
|
||||
public void testSubstituteOtherErasedDeepTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("substituteSeveralOtherErasedDependentTypeArguments.kt")
|
||||
public void testSubstituteSeveralOtherErasedDependentTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("substituteSeveralOtherErasedTypeArguments.kt")
|
||||
public void testSubstituteSeveralOtherErasedTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typeEnhancement.kt")
|
||||
public void testTypeEnhancement() throws Exception {
|
||||
@@ -29213,12 +29147,6 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42042.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt42042Error.kt")
|
||||
public void testKt42042Error() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42042Error.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt42396.kt")
|
||||
public void testKt42396() throws Exception {
|
||||
|
||||
@@ -620,12 +620,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/RecursiveTypeInference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("RecursiveTypeParameterEqualityCheck.kt")
|
||||
public void testRecursiveTypeParameterEqualityCheck() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/RecursiveTypeParameterEqualityCheck.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("ReserveYield.kt")
|
||||
public void testReserveYield() throws Exception {
|
||||
@@ -9077,12 +9071,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/enum/starImportNestedClassAndEntries.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typeCompatibility.kt")
|
||||
public void testTypeCompatibility() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/enum/typeCompatibility.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typeParametersInEnum.kt")
|
||||
public void testTypeParametersInEnum() throws Exception {
|
||||
@@ -12599,12 +12587,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/inference/violatingUpperBoundForSelfType.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("violatingUpperBoundForSelfTypeError.kt")
|
||||
public void testViolatingUpperBoundForSelfTypeError() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/inference/violatingUpperBoundForSelfTypeError.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/inference/builderInference")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@@ -16858,12 +16840,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("abstractBaseClassMemberNotImplemented_15.kt")
|
||||
public void testAbstractBaseClassMemberNotImplemented_15() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/java8Overrides/abstractBaseClassMemberNotImplemented_15.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("abstractVsAbstract.kt")
|
||||
public void testAbstractVsAbstract() throws Exception {
|
||||
@@ -16893,12 +16869,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/java8Overrides/implementingMethodOfAny.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt45508.kt")
|
||||
public void testKt45508() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/java8Overrides/kt45508.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("notAMethodOfAny.kt")
|
||||
public void testNotAMethodOfAny() throws Exception {
|
||||
@@ -21160,18 +21130,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/arrays.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt")
|
||||
public void testDontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedRecursiveTypeArgumentAndNonRecursive.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt")
|
||||
public void testDontSubstituteAnotherErasedTypeArgumentIfRecursive() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/dontSubstituteAnotherErasedTypeArgumentIfRecursive.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("errorType.kt")
|
||||
public void testErrorType() throws Exception {
|
||||
@@ -21262,30 +21220,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/starProjectionToRaw.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("substituteAnotherErasedTypeArgument.kt")
|
||||
public void testSubstituteAnotherErasedTypeArgument() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteAnotherErasedTypeArgument.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("substituteOtherErasedDeepTypeArguments.kt")
|
||||
public void testSubstituteOtherErasedDeepTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteOtherErasedDeepTypeArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("substituteSeveralOtherErasedDependentTypeArguments.kt")
|
||||
public void testSubstituteSeveralOtherErasedDependentTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedDependentTypeArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("substituteSeveralOtherErasedTypeArguments.kt")
|
||||
public void testSubstituteSeveralOtherErasedTypeArguments() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/platformTypes/rawTypes/substituteSeveralOtherErasedTypeArguments.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typeEnhancement.kt")
|
||||
public void testTypeEnhancement() throws Exception {
|
||||
@@ -29213,12 +29147,6 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42042.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt42042Error.kt")
|
||||
public void testKt42042Error() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/typeParameters/kt42042Error.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt42396.kt")
|
||||
public void testKt42396() throws Exception {
|
||||
|
||||
@@ -94,7 +94,7 @@ class Generator(
|
||||
printPackageAndCopyright()
|
||||
printImports()
|
||||
printGeneratedMessage()
|
||||
println("class $composedComponentName : $checkersComponentName() {")
|
||||
println("internal class $composedComponentName : $checkersComponentName() {")
|
||||
withIndent {
|
||||
// public overrides
|
||||
for (alias in configuration.aliases.values) {
|
||||
@@ -122,7 +122,7 @@ class Generator(
|
||||
|
||||
// register function
|
||||
println(CHECKERS_COMPONENT_INTERNAL_ANNOTATION)
|
||||
println("fun register(checkers: $checkersComponentName) {")
|
||||
println("internal fun register(checkers: $checkersComponentName) {")
|
||||
withIndent {
|
||||
for (alias in configuration.aliases.values) {
|
||||
println("_${alias.fieldName} += checkers.${alias.fieldName}")
|
||||
|
||||
@@ -38,8 +38,6 @@ fun main(args: Array<String>) {
|
||||
alias<FirEqualityOperatorCall>("EqualityOperatorCallChecker")
|
||||
alias<FirAnonymousFunction>("AnonymousFunctionAsExpressionChecker")
|
||||
alias<FirStringConcatenationCall>("StringConcatenationCallChecker")
|
||||
alias<FirTypeOperatorCall>("TypeOperatorCallChecker")
|
||||
alias<FirResolvedQualifier>("ResolvedQualifierChecker")
|
||||
}
|
||||
|
||||
val declarationPackage = "org.jetbrains.kotlin.fir.analysis.checkers.declaration"
|
||||
|
||||
@@ -52,7 +52,6 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
CONST_MODIFIER,
|
||||
ARRAY_ACCESS,
|
||||
SAFE_ACCESS,
|
||||
AS_TYPE,
|
||||
USELESS_ELVIS,
|
||||
NAME_OF_NAMED_ARGUMENT,
|
||||
VALUE_ARGUMENTS,
|
||||
@@ -68,7 +67,6 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
FUN_MODIFIER,
|
||||
SUSPEND_MODIFIER,
|
||||
FUN_INTERFACE,
|
||||
RESERVED_UNDERSCORE,
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -82,10 +82,6 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val NO_THIS by error<PsiElement>()
|
||||
}
|
||||
|
||||
val CALL_RESOLUTION by object : DiagnosticGroup("Call resolution") {
|
||||
val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error<KtExpression>()
|
||||
}
|
||||
|
||||
val SUPER by object : DiagnosticGroup("Super") {
|
||||
val SUPER_IS_NOT_AN_EXPRESSION by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val SUPER_NOT_AVAILABLE by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
@@ -255,8 +251,6 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val NAMED_PARAMETER_NOT_FOUND by error<KtValueArgument>(PositioningStrategy.NAME_OF_NAMED_ARGUMENT) {
|
||||
parameter<String>("name")
|
||||
}
|
||||
|
||||
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error<KtValueArgument>()
|
||||
}
|
||||
|
||||
val AMBIGUITY by object : DiagnosticGroup("Ambiguity") {
|
||||
@@ -360,16 +354,6 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning<KtTypeParameter>()
|
||||
|
||||
val DYNAMIC_UPPER_BOUND by error<KtTypeReference>()
|
||||
|
||||
val INCOMPATIBLE_TYPES by error<KtElement> {
|
||||
parameter<ConeKotlinType>("typeA")
|
||||
parameter<ConeKotlinType>("typeB")
|
||||
}
|
||||
|
||||
val INCOMPATIBLE_TYPES_WARNING by warning<KtElement> {
|
||||
parameter<ConeKotlinType>("typeA")
|
||||
parameter<ConeKotlinType>("typeB")
|
||||
}
|
||||
}
|
||||
|
||||
val REFLECTION by object : DiagnosticGroup("Reflection") {
|
||||
@@ -664,13 +648,6 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val USELESS_ELVIS_RIGHT_IS_NULL by warning<KtBinaryExpression>(PositioningStrategy.USELESS_ELVIS)
|
||||
}
|
||||
|
||||
val CASTS_AND_IS_CHECKS by object : DiagnosticGroup("Casts and is-checks") {
|
||||
val USELESS_CAST by warning<KtBinaryExpressionWithTypeRHS>(PositioningStrategy.AS_TYPE)
|
||||
val USELESS_IS_CHECK by warning<KtElement> {
|
||||
parameter<Boolean>("compileTimeCheckResult")
|
||||
}
|
||||
}
|
||||
|
||||
val WHEN_EXPRESSIONS by object : DiagnosticGroup("When expressions") {
|
||||
val NO_ELSE_IN_WHEN by error<KtWhenExpression>(PositioningStrategy.WHEN_EXPRESSION) {
|
||||
parameter<List<WhenMissingCase>>("missingWhenCases")
|
||||
@@ -686,10 +663,6 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val TYPE_PARAMETER_ON_LHS_OF_DOT by error<KtSimpleNameExpression> {
|
||||
parameter<FirTypeParameterSymbol>("typeParameter")
|
||||
}
|
||||
val NO_COMPANION_OBJECT by error<KtSimpleNameExpression>(PositioningStrategy.SELECTOR_BY_QUALIFIED) {
|
||||
parameter<FirRegularClassSymbol>("klass")
|
||||
}
|
||||
val EXPRESSION_EXPECTED_PACKAGE_FOUND by error<KtSimpleNameExpression>(PositioningStrategy.SELECTOR_BY_QUALIFIED)
|
||||
}
|
||||
|
||||
val FUNCTION_CONTRACTS by object : DiagnosticGroup("Function contracts") {
|
||||
@@ -723,29 +696,6 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
parameter<String>("expectedFunctionSignature")
|
||||
parameter<Collection<AbstractFirBasedSymbol<*>>>("candidates")
|
||||
}
|
||||
val DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH by error<KtExpression> {
|
||||
parameter<String>("delegateFunction")
|
||||
parameter<ConeKotlinType>("expected")
|
||||
parameter<ConeKotlinType>("actual")
|
||||
}
|
||||
|
||||
val UNDERSCORE_IS_RESERVED by error<KtExpression>(PositioningStrategy.RESERVED_UNDERSCORE)
|
||||
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error<KtExpression>(PositioningStrategy.RESERVED_UNDERSCORE)
|
||||
|
||||
val EQUALITY_NOT_APPLICABLE by error<KtBinaryExpression> {
|
||||
parameter<String>("operator")
|
||||
parameter<ConeKotlinType>("leftType")
|
||||
parameter<ConeKotlinType>("rightType")
|
||||
}
|
||||
val EQUALITY_NOT_APPLICABLE_WARNING by warning<KtBinaryExpression> {
|
||||
parameter<String>("operator")
|
||||
parameter<ConeKotlinType>("leftType")
|
||||
parameter<ConeKotlinType>("rightType")
|
||||
}
|
||||
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error<KtElement> {
|
||||
parameter<ConeKotlinType>("leftType")
|
||||
parameter<ConeKotlinType>("rightType")
|
||||
}
|
||||
}
|
||||
|
||||
val TYPE_ALIAS by object : DiagnosticGroup("Type alias") {
|
||||
@@ -775,49 +725,6 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val RETURN_NOT_ALLOWED by error<KtReturnExpression>(PositioningStrategy.RETURN_WITH_LABEL)
|
||||
val RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY by error<KtReturnExpression>(PositioningStrategy.RETURN_WITH_LABEL)
|
||||
}
|
||||
|
||||
val INLINE by object : DiagnosticGroup("Inline") {
|
||||
val USAGE_IS_NOT_INLINABLE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("parameter")
|
||||
}
|
||||
|
||||
val NON_LOCAL_RETURN_NOT_ALLOWED by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("parameter")
|
||||
}
|
||||
|
||||
val RECURSION_IN_INLINE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("symbol")
|
||||
}
|
||||
|
||||
val NON_PUBLIC_CALL_FROM_PUBLIC_INLINE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("inlineDeclaration")
|
||||
parameter<Symbol>("referencedDeclaration")
|
||||
}
|
||||
|
||||
val PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("inlineDeclaration")
|
||||
parameter<Symbol>("referencedDeclaration")
|
||||
}
|
||||
|
||||
val PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("inlineDeclaration")
|
||||
parameter<Symbol>("referencedDeclaration")
|
||||
}
|
||||
|
||||
val PROTECTED_CALL_FROM_PUBLIC_INLINE by warning<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("inlineDeclaration")
|
||||
parameter<Symbol>("referencedDeclaration")
|
||||
}
|
||||
|
||||
val PRIVATE_CLASS_MEMBER_FROM_INLINE by error<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("inlineDeclaration")
|
||||
parameter<Symbol>("referencedDeclaration")
|
||||
}
|
||||
|
||||
val SUPER_CALL_FROM_PUBLIC_INLINE by warning<KtElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
|
||||
parameter<Symbol>("symbol")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = {
|
||||
|
||||
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.cfa.FirControlFlowChecker
|
||||
* DO NOT MODIFY IT MANUALLY
|
||||
*/
|
||||
|
||||
class ComposedDeclarationCheckers : DeclarationCheckers() {
|
||||
internal class ComposedDeclarationCheckers : DeclarationCheckers() {
|
||||
override val basicDeclarationCheckers: Set<FirBasicDeclarationChecker>
|
||||
get() = _basicDeclarationCheckers
|
||||
override val memberDeclarationCheckers: Set<FirMemberDeclarationChecker>
|
||||
@@ -54,7 +54,7 @@ class ComposedDeclarationCheckers : DeclarationCheckers() {
|
||||
private val _variableAssignmentCfaBasedCheckers: MutableSet<AbstractFirPropertyInitializationChecker> = mutableSetOf()
|
||||
|
||||
@CheckersComponentInternal
|
||||
fun register(checkers: DeclarationCheckers) {
|
||||
internal fun register(checkers: DeclarationCheckers) {
|
||||
_basicDeclarationCheckers += checkers.basicDeclarationCheckers
|
||||
_memberDeclarationCheckers += checkers.memberDeclarationCheckers
|
||||
_functionCheckers += checkers.functionCheckers
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal
|
||||
* DO NOT MODIFY IT MANUALLY
|
||||
*/
|
||||
|
||||
class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
internal class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
override val basicExpressionCheckers: Set<FirBasicExpressionChecker>
|
||||
get() = _basicExpressionCheckers
|
||||
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
|
||||
@@ -45,10 +45,6 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
get() = _anonymousFunctionAsExpressionCheckers
|
||||
override val stringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker>
|
||||
get() = _stringConcatenationCallCheckers
|
||||
override val typeOperatorCallCheckers: Set<FirTypeOperatorCallChecker>
|
||||
get() = _typeOperatorCallCheckers
|
||||
override val resolvedQualifierCheckers: Set<FirResolvedQualifierChecker>
|
||||
get() = _resolvedQualifierCheckers
|
||||
|
||||
private val _basicExpressionCheckers: MutableSet<FirBasicExpressionChecker> = mutableSetOf()
|
||||
private val _qualifiedAccessCheckers: MutableSet<FirQualifiedAccessChecker> = mutableSetOf()
|
||||
@@ -66,11 +62,9 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
private val _equalityOperatorCallCheckers: MutableSet<FirEqualityOperatorCallChecker> = mutableSetOf()
|
||||
private val _anonymousFunctionAsExpressionCheckers: MutableSet<FirAnonymousFunctionAsExpressionChecker> = mutableSetOf()
|
||||
private val _stringConcatenationCallCheckers: MutableSet<FirStringConcatenationCallChecker> = mutableSetOf()
|
||||
private val _typeOperatorCallCheckers: MutableSet<FirTypeOperatorCallChecker> = mutableSetOf()
|
||||
private val _resolvedQualifierCheckers: MutableSet<FirResolvedQualifierChecker> = mutableSetOf()
|
||||
|
||||
@CheckersComponentInternal
|
||||
fun register(checkers: ExpressionCheckers) {
|
||||
internal fun register(checkers: ExpressionCheckers) {
|
||||
_basicExpressionCheckers += checkers.basicExpressionCheckers
|
||||
_qualifiedAccessCheckers += checkers.qualifiedAccessCheckers
|
||||
_functionCallCheckers += checkers.functionCallCheckers
|
||||
@@ -87,7 +81,5 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
_equalityOperatorCallCheckers += checkers.equalityOperatorCallCheckers
|
||||
_anonymousFunctionAsExpressionCheckers += checkers.anonymousFunctionAsExpressionCheckers
|
||||
_stringConcatenationCallCheckers += checkers.stringConcatenationCallCheckers
|
||||
_typeOperatorCallCheckers += checkers.typeOperatorCallCheckers
|
||||
_resolvedQualifierCheckers += checkers.resolvedQualifierCheckers
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,8 +33,6 @@ abstract class ExpressionCheckers {
|
||||
open val equalityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> = emptySet()
|
||||
open val anonymousFunctionAsExpressionCheckers: Set<FirAnonymousFunctionAsExpressionChecker> = emptySet()
|
||||
open val stringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> = emptySet()
|
||||
open val typeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> = emptySet()
|
||||
open val resolvedQualifierCheckers: Set<FirResolvedQualifierChecker> = emptySet()
|
||||
|
||||
@CheckersComponentInternal internal val allBasicExpressionCheckers: Set<FirBasicExpressionChecker> get() = basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allQualifiedAccessCheckers: Set<FirQualifiedAccessChecker> get() = qualifiedAccessCheckers + basicExpressionCheckers
|
||||
@@ -52,6 +50,4 @@ abstract class ExpressionCheckers {
|
||||
@CheckersComponentInternal internal val allEqualityOperatorCallCheckers: Set<FirEqualityOperatorCallChecker> get() = equalityOperatorCallCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allAnonymousFunctionAsExpressionCheckers: Set<FirAnonymousFunctionAsExpressionChecker> get() = anonymousFunctionAsExpressionCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allStringConcatenationCallCheckers: Set<FirStringConcatenationCallChecker> get() = stringConcatenationCallCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allTypeOperatorCallCheckers: Set<FirTypeOperatorCallChecker> get() = typeOperatorCallCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allResolvedQualifierCheckers: Set<FirResolvedQualifierChecker> get() = resolvedQualifierCheckers + basicExpressionCheckers
|
||||
}
|
||||
|
||||
@@ -19,13 +19,11 @@ import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStatement
|
||||
import org.jetbrains.kotlin.fir.expressions.FirStringConcatenationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirTryExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirTypeOperatorCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||
|
||||
@@ -45,5 +43,3 @@ typealias FirSafeCallExpressionChecker = FirExpressionChecker<FirSafeCallExpress
|
||||
typealias FirEqualityOperatorCallChecker = FirExpressionChecker<FirEqualityOperatorCall>
|
||||
typealias FirAnonymousFunctionAsExpressionChecker = FirExpressionChecker<FirAnonymousFunction>
|
||||
typealias FirStringConcatenationCallChecker = FirExpressionChecker<FirStringConcatenationCall>
|
||||
typealias FirTypeOperatorCallChecker = FirExpressionChecker<FirTypeOperatorCall>
|
||||
typealias FirResolvedQualifierChecker = FirExpressionChecker<FirResolvedQualifier>
|
||||
|
||||
@@ -12,14 +12,14 @@ import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal
|
||||
* DO NOT MODIFY IT MANUALLY
|
||||
*/
|
||||
|
||||
class ComposedTypeCheckers : TypeCheckers() {
|
||||
internal class ComposedTypeCheckers : TypeCheckers() {
|
||||
override val typeRefCheckers: Set<FirTypeRefChecker>
|
||||
get() = _typeRefCheckers
|
||||
|
||||
private val _typeRefCheckers: MutableSet<FirTypeRefChecker> = mutableSetOf()
|
||||
|
||||
@CheckersComponentInternal
|
||||
fun register(checkers: TypeCheckers) {
|
||||
internal fun register(checkers: TypeCheckers) {
|
||||
_typeRefCheckers += checkers.typeRefCheckers
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.KtAnnotation
|
||||
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpression
|
||||
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
|
||||
import org.jetbrains.kotlin.psi.KtClass
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
@@ -106,9 +105,6 @@ object FirErrors {
|
||||
val MISSING_STDLIB_CLASS by error0<PsiElement>()
|
||||
val NO_THIS by error0<PsiElement>()
|
||||
|
||||
// Call resolution
|
||||
val CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS by error0<KtExpression>()
|
||||
|
||||
// Super
|
||||
val SUPER_IS_NOT_AN_EXPRESSION by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val SUPER_NOT_AVAILABLE by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
@@ -213,7 +209,6 @@ object FirErrors {
|
||||
val TOO_MANY_ARGUMENTS by error1<PsiElement, FirCallableDeclaration<*>>()
|
||||
val NO_VALUE_FOR_PARAMETER by error1<KtElement, FirValueParameter>(SourceElementPositioningStrategies.VALUE_ARGUMENTS)
|
||||
val NAMED_PARAMETER_NOT_FOUND by error1<KtValueArgument, String>(SourceElementPositioningStrategies.NAME_OF_NAMED_ARGUMENT)
|
||||
val MANY_LAMBDA_EXPRESSION_ARGUMENTS by error0<KtValueArgument>()
|
||||
|
||||
// Ambiguity
|
||||
val OVERLOAD_RESOLUTION_AMBIGUITY by error1<PsiElement, Collection<AbstractFirBasedSymbol<*>>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
@@ -259,8 +254,6 @@ object FirErrors {
|
||||
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error0<KtDeclaration>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
|
||||
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0<KtTypeParameter>()
|
||||
val DYNAMIC_UPPER_BOUND by error0<KtTypeReference>()
|
||||
val INCOMPATIBLE_TYPES by error2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
val INCOMPATIBLE_TYPES_WARNING by warning2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
|
||||
// Reflection
|
||||
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<KtExpression, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
@@ -393,10 +386,6 @@ object FirErrors {
|
||||
val USELESS_ELVIS by warning1<KtBinaryExpression, ConeKotlinType>(SourceElementPositioningStrategies.USELESS_ELVIS)
|
||||
val USELESS_ELVIS_RIGHT_IS_NULL by warning0<KtBinaryExpression>(SourceElementPositioningStrategies.USELESS_ELVIS)
|
||||
|
||||
// Casts and is-checks
|
||||
val USELESS_CAST by warning0<KtBinaryExpressionWithTypeRHS>(SourceElementPositioningStrategies.AS_TYPE)
|
||||
val USELESS_IS_CHECK by warning1<KtElement, Boolean>()
|
||||
|
||||
// When expressions
|
||||
val NO_ELSE_IN_WHEN by error1<KtWhenExpression, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
|
||||
val INVALID_IF_AS_EXPRESSION by error0<KtIfExpression>(SourceElementPositioningStrategies.IF_EXPRESSION)
|
||||
@@ -405,8 +394,6 @@ object FirErrors {
|
||||
// Context tracking
|
||||
val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1<KtSimpleNameExpression, FirTypeParameterSymbol>()
|
||||
val TYPE_PARAMETER_ON_LHS_OF_DOT by error1<KtSimpleNameExpression, FirTypeParameterSymbol>()
|
||||
val NO_COMPANION_OBJECT by error1<KtSimpleNameExpression, FirRegularClassSymbol>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||
val EXPRESSION_EXPECTED_PACKAGE_FOUND by error0<KtSimpleNameExpression>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||
|
||||
// Function contracts
|
||||
val ERROR_IN_CONTRACT_DESCRIPTION by error1<KtElement, String>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||
@@ -422,12 +409,6 @@ object FirErrors {
|
||||
val DELEGATE_SPECIAL_FUNCTION_MISSING by error3<KtExpression, String, ConeKotlinType, String>()
|
||||
val DELEGATE_SPECIAL_FUNCTION_AMBIGUITY by error2<KtExpression, String, Collection<AbstractFirBasedSymbol<*>>>()
|
||||
val DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE by error2<KtExpression, String, Collection<AbstractFirBasedSymbol<*>>>()
|
||||
val DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH by error3<KtExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||
val UNDERSCORE_IS_RESERVED by error0<KtExpression>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
|
||||
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error0<KtExpression>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
|
||||
val EQUALITY_NOT_APPLICABLE by error3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||
val EQUALITY_NOT_APPLICABLE_WARNING by warning3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
|
||||
// Type alias
|
||||
val TOPLEVEL_TYPEALIASES_ONLY by error0<KtTypeAlias>()
|
||||
@@ -454,15 +435,4 @@ object FirErrors {
|
||||
val RETURN_NOT_ALLOWED by error0<KtReturnExpression>(SourceElementPositioningStrategies.RETURN_WITH_LABEL)
|
||||
val RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY by error0<KtReturnExpression>(SourceElementPositioningStrategies.RETURN_WITH_LABEL)
|
||||
|
||||
// Inline
|
||||
val USAGE_IS_NOT_INLINABLE by error1<KtElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val NON_LOCAL_RETURN_NOT_ALLOWED by error1<KtElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val RECURSION_IN_INLINE by error1<KtElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val NON_PUBLIC_CALL_FROM_PUBLIC_INLINE by error2<KtElement, AbstractFirBasedSymbol<*>, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE by error2<KtElement, AbstractFirBasedSymbol<*>, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR by error2<KtElement, AbstractFirBasedSymbol<*>, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val PROTECTED_CALL_FROM_PUBLIC_INLINE by warning2<KtElement, AbstractFirBasedSymbol<*>, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val PRIVATE_CLASS_MEMBER_FROM_INLINE by error2<KtElement, AbstractFirBasedSymbol<*>, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val SUPER_CALL_FROM_PUBLIC_INLINE by warning1<KtElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.FirDiagnosticsCollector
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporterFactory
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
||||
@@ -20,7 +19,7 @@ class FirCheckersResolveProcessor(
|
||||
session: FirSession,
|
||||
scopeSession: ScopeSession
|
||||
) : FirTransformerBasedResolveProcessor(session, scopeSession) {
|
||||
val diagnosticCollector: AbstractDiagnosticCollector = FirDiagnosticsCollector.create(session, scopeSession)
|
||||
val diagnosticCollector = FirDiagnosticsCollector.create(session, scopeSession)
|
||||
|
||||
override val transformer: FirTransformer<Nothing?> = FirCheckersRunnerTransformer(diagnosticCollector)
|
||||
}
|
||||
@@ -31,8 +30,7 @@ class FirCheckersRunnerTransformer(private val diagnosticCollector: AbstractDiag
|
||||
}
|
||||
|
||||
override fun transformFile(file: FirFile, data: Nothing?): FirDeclaration {
|
||||
val reporter = DiagnosticReporterFactory.createReporter()
|
||||
diagnosticCollector.collectDiagnostics(file, reporter)
|
||||
diagnosticCollector.collectDiagnostics(file)
|
||||
return file
|
||||
}
|
||||
}
|
||||
@@ -1,468 +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.fir.analysis.checkers
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.isPrimitiveType
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.fullyExpandedClass
|
||||
import org.jetbrains.kotlin.fir.resolve.getSymbolByLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
/**
|
||||
* Checks if a given collection of [ConeKotlinType] are compatible. In other words, the types are compatible if it's possible at all to
|
||||
* define a type that's a subtype of all of the given types. The compatibility of a given set of types concept is closely related to whether
|
||||
* the intersection of these types is inhabited. But it's not identical because 1) one can manually control visibility of constructors and
|
||||
* 2) there can be unused type parameters.
|
||||
*
|
||||
* The compatibility check is done recursively on the given types and all type arguments passed to each corresponding type parameters. For
|
||||
* example, consider the following two types:
|
||||
*
|
||||
* ```
|
||||
* - ArrayList<Set<String>>
|
||||
* - List<HashSet<Int>>
|
||||
* ```
|
||||
*
|
||||
* The checker first checks the base types `ArrayList` and `List`, and it sees no issue since `ArrayList <: List`. Next it checks the type
|
||||
* parameters bound to these base types: `T1` in `ArrayList<T1>` and `T2` in `List<T2>`. For `T1`, there is only one bound type argument
|
||||
* `Set<String>`, so it's good. For `T2`, there are two bound type arguments: `Set<String>` and `HashSet<Int>`. Now the checker recursively
|
||||
* checks whether these two types are compatible. Again, it first checks the base type `Set` and `HashSet`, and it finds no problem since
|
||||
* `HashSet <: Set`. Finally, checks the type arguments `String` and `Int` that are bound to `T` in `Set<T>`. They are incompatible since
|
||||
* `String` and `Int` are unrelated classes.
|
||||
*
|
||||
* The above example only goes over covariant type arguments. For contravariant types, the checker simply checks whether the range formed by
|
||||
* covariant and contravariant bounds is empty. For example, a range like `[Collection, List]` is empty and hence invalid because `List` is
|
||||
* not a super class/interface of `Collection`
|
||||
*/
|
||||
internal object ConeTypeCompatibilityChecker {
|
||||
|
||||
/**
|
||||
* The result returned by [ConeTypeCompatibilityChecker]. Note the order of enum entries matters.
|
||||
*/
|
||||
enum class Compatibility : Comparable<Compatibility> {
|
||||
/** The given types are fully compatible. */
|
||||
COMPATIBLE,
|
||||
|
||||
/** The given types may not be compatible. But the compiler would allow such comparisons. */
|
||||
SOFT_INCOMPATIBLE,
|
||||
|
||||
/**
|
||||
* The given types are definitely incompatible. If the established contracts of Kotlin code are respected, values of the given
|
||||
* types can never be considered equal.
|
||||
*/
|
||||
HARD_INCOMPATIBLE,
|
||||
}
|
||||
|
||||
fun Collection<ConeKotlinType>.areCompatible(ctx: ConeInferenceContext): Compatibility {
|
||||
// If all types are nullable, then `null` makes the given types compatible.
|
||||
if (all { with(ctx) { it.isNullableType() } }) return Compatibility.COMPATIBLE
|
||||
|
||||
// Next can simply focus on the type hierarchy and don't need to worry about nullability.
|
||||
val compatibilityUpperBound = when {
|
||||
all {
|
||||
it.classId in StandardClassIds.primitiveTypes
|
||||
} -> Compatibility.SOFT_INCOMPATIBLE // TODO: remove after KT-46383 is fixed
|
||||
all {
|
||||
it.isConcreteType()
|
||||
} -> Compatibility.HARD_INCOMPATIBLE
|
||||
// If any type is not concrete, for example, type parameter, we only report warning for incompatible types.
|
||||
// This is to stay compatible with FE1.0.
|
||||
else -> Compatibility.SOFT_INCOMPATIBLE
|
||||
}
|
||||
return ctx.areCompatible(flatMap { it.collectUpperBounds() }.toSet(), emptySet(), compatibilityUpperBound)
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.isConcreteType(): Boolean {
|
||||
return when (this) {
|
||||
is ConeClassLikeType -> true
|
||||
is ConeDefinitelyNotNullType -> original.isConcreteType()
|
||||
is ConeIntersectionType -> intersectedTypes.all { it.isConcreteType() }
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param compatibilityUpperBound the max compatibility result that can be returned by this method. For example, if this is set to
|
||||
* [Compatibility.SOFT_INCOMPATIBLE], then even if the given bounds don't match the hard way (for example, incompatible primitives) the
|
||||
* method should still return [Compatibility.SOFT_INCOMPATIBLE]. This is useful for checking type parameters since we don't want to
|
||||
* dictate what semantics a type parameter may have in user code. In other words, if user wants to compare `MyCustom<out String>` with
|
||||
* `MyCustom<out Int>`, we let them do so since we do not know what class `MyCustom` uses the type parameter for. Empty containers are
|
||||
* another example: `emptyList<Int>() == emptyList<String>()`.
|
||||
*/
|
||||
private fun ConeInferenceContext.areCompatible(
|
||||
upperBounds: Set<ConeClassLikeType>,
|
||||
lowerBounds: Set<ConeClassLikeType>,
|
||||
compatibilityUpperBound: Compatibility,
|
||||
checkedTypeParameters: MutableSet<FirTypeParameterRef> = mutableSetOf(),
|
||||
): Compatibility {
|
||||
val upperBoundClasses: Set<FirClassWithSuperClasses> = upperBounds.mapNotNull { it.toFirClassWithSuperClasses(this) }.toSet()
|
||||
|
||||
// Following if condition is an optimization: if we ignore the subtyping relation and treat all upper bounds as unrelated
|
||||
// classes/interfaces, yet the types are deemed compatible for sure, then we just bail out early.
|
||||
if (lowerBounds.isEmpty() &&
|
||||
(upperBounds.size < 2 ||
|
||||
this.areClassesOrInterfacesCompatible(upperBoundClasses, compatibilityUpperBound) == Compatibility.COMPATIBLE)
|
||||
) {
|
||||
return Compatibility.COMPATIBLE
|
||||
}
|
||||
|
||||
val leafClassesOrInterfaces = computeLeafClassesOrInterfaces(upperBoundClasses)
|
||||
this.areClassesOrInterfacesCompatible(leafClassesOrInterfaces, compatibilityUpperBound)?.let { return it }
|
||||
|
||||
// Check if the range formed by upper bounds and lower bounds is empty.
|
||||
if (!lowerBounds.all { lowerBoundType ->
|
||||
val classesSatisfyingLowerBounds =
|
||||
lowerBoundType.toFirClassWithSuperClasses(this)?.thisAndAllSuperClasses ?: emptySet()
|
||||
leafClassesOrInterfaces.all { it in classesSatisfyingLowerBounds }
|
||||
}
|
||||
) {
|
||||
return compatibilityUpperBound
|
||||
}
|
||||
|
||||
if (upperBounds.size < 2) return Compatibility.COMPATIBLE
|
||||
|
||||
// Base types are compatible. Now we check type parameters.
|
||||
|
||||
val typeArgumentMapping = mutableMapOf<FirTypeParameterRef, BoundTypeArguments>().apply {
|
||||
for (type in upperBounds) {
|
||||
collectTypeArgumentMapping(type, this@areCompatible, compatibilityUpperBound)
|
||||
}
|
||||
}
|
||||
var result = Compatibility.COMPATIBLE
|
||||
val typeArgsCompatibility = typeArgumentMapping.asSequence()
|
||||
.map { (paramRef, boundTypeArguments) ->
|
||||
val (upper, lower, compatibility) = boundTypeArguments
|
||||
if (paramRef in checkedTypeParameters) {
|
||||
// if we are already checking this type parameter, simply bail out to prevent infinite recursion.
|
||||
Compatibility.COMPATIBLE
|
||||
} else {
|
||||
checkedTypeParameters.add(paramRef)
|
||||
areCompatible(upper, lower, compatibility, checkedTypeParameters)
|
||||
}
|
||||
}
|
||||
for (compatibility in typeArgsCompatibility) {
|
||||
if (compatibility == compatibilityUpperBound) return compatibility
|
||||
if (compatibility > result) {
|
||||
result = compatibility
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the upper bound classes into the class hierarchy and count hows many subclasses are there for each encountered class. Then
|
||||
* output a list of leaf classes or interfaces in the class hierarchy.
|
||||
*/
|
||||
private fun computeLeafClassesOrInterfaces(upperBoundClasses: Set<FirClassWithSuperClasses>): Set<FirClassWithSuperClasses> {
|
||||
val isLeaf = mutableMapOf<FirClassWithSuperClasses, Boolean>()
|
||||
upperBoundClasses.associateWithTo(isLeaf) { true } // implementation of keysToMap actually ends up creating 2 maps so this is better
|
||||
val queue = ArrayDeque(upperBoundClasses)
|
||||
while (queue.isNotEmpty()) {
|
||||
for (superClass in queue.removeFirst().superClasses) {
|
||||
when (isLeaf[superClass]) {
|
||||
true -> isLeaf[superClass] = false
|
||||
false -> {
|
||||
// nothing to be done since this super class has already been handled.
|
||||
}
|
||||
else -> {
|
||||
isLeaf[superClass] = false
|
||||
queue.addLast(superClass)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return isLeaf.filterValues { it }.keys
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given classes are compatible. In other words, check if it's possible for objects of the given classes to be
|
||||
* considered equal by [Any.equals].
|
||||
*
|
||||
* @return null if this check is inconclusive
|
||||
*/
|
||||
private fun ConeInferenceContext.areClassesOrInterfacesCompatible(
|
||||
classesOrInterfaces: Collection<FirClassWithSuperClasses>,
|
||||
compatibilityUpperBound: Compatibility
|
||||
): Compatibility? {
|
||||
val classes = classesOrInterfaces.filter { !it.isInterface }
|
||||
// Java force single inheritance, so any pair of unrelated classes are incompatible.
|
||||
if (classes.size >= 2) {
|
||||
return if (classes.any { it.getHasPredefinedEqualityContract(this) }) {
|
||||
compatibilityUpperBound
|
||||
} else {
|
||||
Compatibility.SOFT_INCOMPATIBLE
|
||||
}
|
||||
}
|
||||
val finalClass = classes.firstOrNull { it.isFinal } ?: return null
|
||||
// One final class and some other unrelated interface are not compatible
|
||||
if (classesOrInterfaces.size > classes.size) {
|
||||
return if (finalClass.getHasPredefinedEqualityContract(this)) {
|
||||
compatibilityUpperBound
|
||||
} else {
|
||||
Compatibility.SOFT_INCOMPATIBLE
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the upper bounds as [ConeClassLikeType].
|
||||
*/
|
||||
private fun ConeKotlinType?.collectUpperBounds(): Set<ConeClassLikeType> {
|
||||
if (this == null) return emptySet()
|
||||
return when (this) {
|
||||
is ConeClassErrorType -> emptySet() // Ignore error types
|
||||
is ConeLookupTagBasedType -> when (this) {
|
||||
is ConeClassLikeType -> setOf(this)
|
||||
is ConeTypeVariableType -> when (val tag = lookupTag) {
|
||||
is ConeTypeVariableTypeConstructor -> (tag.originalTypeParameter as? ConeTypeParameterLookupTag)?.typeParameterSymbol.collectUpperBounds()
|
||||
else -> throw IllegalStateException("missing branch for ${lookupTag.javaClass.name}")
|
||||
}
|
||||
is ConeTypeParameterType -> lookupTag.typeParameterSymbol.collectUpperBounds()
|
||||
else -> throw IllegalStateException("missing branch for ${javaClass.name}")
|
||||
}
|
||||
is ConeDefinitelyNotNullType -> original.collectUpperBounds()
|
||||
is ConeIntersectionType -> intersectedTypes.flatMap { it.collectUpperBounds() }.toSet()
|
||||
is ConeFlexibleType -> upperBound.collectUpperBounds()
|
||||
is ConeCapturedType, is ConeStubType, is ConeIntegerLiteralType -> throw IllegalStateException("$this should not reach here")
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirTypeParameterSymbol?.collectUpperBounds(): Set<ConeClassLikeType> {
|
||||
if (this == null) return emptySet()
|
||||
return fir.bounds.flatMap { it.coneTypeSafe<ConeKotlinType>().collectUpperBounds() }.toSet()
|
||||
}
|
||||
|
||||
private fun ConeKotlinType?.collectLowerBounds(): Set<ConeClassLikeType> {
|
||||
if (this == null) return emptySet()
|
||||
return when (this) {
|
||||
is ConeClassErrorType -> emptySet() // Ignore error types
|
||||
is ConeLookupTagBasedType -> when (this) {
|
||||
is ConeClassLikeType -> setOf(this)
|
||||
is ConeTypeVariableType -> emptySet()
|
||||
is ConeTypeParameterType -> emptySet()
|
||||
else -> throw IllegalStateException("missing branch for ${javaClass.name}")
|
||||
}
|
||||
is ConeDefinitelyNotNullType -> original.collectLowerBounds()
|
||||
is ConeIntersectionType -> intersectedTypes.flatMap { it.collectLowerBounds() }.toSet()
|
||||
is ConeFlexibleType -> lowerBound.collectLowerBounds()
|
||||
is ConeCapturedType, is ConeStubType, is ConeIntegerLiteralType -> throw IllegalStateException("$this should not reach here")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For each type parameters appeared in the class hierarchy, collect all type arguments that eventually mapped to it. For example,
|
||||
* given type `List<String>`, the returned map contains
|
||||
*
|
||||
* - type parameter of `List` -> upper:[`String`], lower:[]
|
||||
* - type parameter of `Collection` -> upper:[`String`], lower:[]
|
||||
* - type parameter of `Iterable` -> upper:[`String`], lower:[]
|
||||
*
|
||||
* If later `Collection<Int>` is passed to this method with the same receiver map, the receiver map would become:
|
||||
*
|
||||
* - type parameter of `List` -> upper:[`String`], lower:[]
|
||||
* - type parameter of `Collection` -> upper:[`String`, `Int`], lower:[]
|
||||
* - type parameter of `Iterable` -> upper:[`String`, `Int`], lower:[]
|
||||
*/
|
||||
private fun MutableMap<FirTypeParameterRef, BoundTypeArguments>.collectTypeArgumentMapping(
|
||||
coneType: ConeClassLikeType,
|
||||
ctx: ConeInferenceContext,
|
||||
compatibilityUpperBound: Compatibility
|
||||
) {
|
||||
val queue = ArrayDeque<TypeArgumentMapping>()
|
||||
queue.addLast(coneType.toTypeArgumentMapping(ctx) ?: return)
|
||||
while (queue.isNotEmpty()) {
|
||||
val (typeParameterOwner, mapping) = queue.removeFirst()
|
||||
val superTypes = typeParameterOwner.getSuperTypes()
|
||||
for (superType in superTypes) {
|
||||
queue.addLast(superType.toTypeArgumentMapping(ctx, mapping) ?: continue)
|
||||
}
|
||||
for ((firTypeParameterRef, boundTypeArgument) in mapping) {
|
||||
this.collect(ctx, typeParameterOwner, firTypeParameterRef, boundTypeArgument, compatibilityUpperBound)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Converts type arguments in a [ConeClassLikeType] to a [TypeArgumentMapping]. */
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
private fun ConeClassLikeType.toTypeArgumentMapping(
|
||||
ctx: ConeInferenceContext,
|
||||
envMapping: Map<FirTypeParameterRef, BoundTypeArgument> = emptyMap(),
|
||||
): TypeArgumentMapping? {
|
||||
val typeParameterOwner = getClassLikeElement(ctx) ?: return null
|
||||
val mapping = buildMap<FirTypeParameterRef, BoundTypeArgument> {
|
||||
typeArguments.forEachIndexed { index, coneTypeProjection ->
|
||||
val typeParameter: FirTypeParameterRef = typeParameterOwner.getTypeParameter(index) ?: return@forEachIndexed
|
||||
var boundTypeArgument: BoundTypeArgument = when (coneTypeProjection) {
|
||||
// Ignore star since it doesn't provide any constraints.
|
||||
ConeStarProjection -> return@forEachIndexed
|
||||
// Ignore contravariant projection because they induces union types. Hence, whatever type argument should always be
|
||||
// considered compatible.
|
||||
is ConeKotlinTypeProjectionIn -> BoundTypeArgument(coneTypeProjection.type, Variance.IN_VARIANCE)
|
||||
is ConeKotlinTypeProjectionOut -> BoundTypeArgument(coneTypeProjection.type, Variance.OUT_VARIANCE)
|
||||
is ConeKotlinType ->
|
||||
when ((typeParameter as? FirTypeParameter)?.variance) {
|
||||
Variance.IN_VARIANCE -> BoundTypeArgument(coneTypeProjection.type, Variance.IN_VARIANCE)
|
||||
Variance.OUT_VARIANCE -> BoundTypeArgument(coneTypeProjection.type, Variance.OUT_VARIANCE)
|
||||
else -> BoundTypeArgument(coneTypeProjection.type, Variance.INVARIANT)
|
||||
}
|
||||
}
|
||||
val coneKotlinType = boundTypeArgument.type
|
||||
if (coneKotlinType is ConeTypeParameterType) {
|
||||
val envTypeParameter = coneKotlinType.lookupTag.typeParameterSymbol.fir
|
||||
val envTypeArgument = envMapping[envTypeParameter]
|
||||
if (envTypeArgument != null) {
|
||||
boundTypeArgument = envTypeArgument
|
||||
}
|
||||
}
|
||||
put(typeParameter, boundTypeArgument)
|
||||
}
|
||||
}
|
||||
return TypeArgumentMapping(typeParameterOwner, mapping)
|
||||
}
|
||||
|
||||
private fun MutableMap<FirTypeParameterRef, BoundTypeArguments>.collect(
|
||||
ctx: ConeInferenceContext,
|
||||
typeParameterOwner: FirClassLikeDeclaration<*>,
|
||||
parameter: FirTypeParameterRef,
|
||||
boundTypeArgument: BoundTypeArgument,
|
||||
compatibilityUpperBound: Compatibility,
|
||||
) {
|
||||
computeIfAbsent(parameter) {
|
||||
// the semantic of type parameter in Enum and KClass are fixed: values of types with incompatible type parameters are always
|
||||
// incompatible.
|
||||
val compatibilityUpperBoundForTypeArg =
|
||||
if ((ctx.prohibitComparisonOfIncompatibleEnums && typeParameterOwner.symbol.classId == StandardClassIds.Enum) ||
|
||||
(ctx.prohibitComparisonOfIncompatibleClasses && typeParameterOwner.symbol.classId == StandardClassIds.KClass)
|
||||
) {
|
||||
compatibilityUpperBound
|
||||
} else {
|
||||
Compatibility.SOFT_INCOMPATIBLE
|
||||
}
|
||||
BoundTypeArguments(mutableSetOf(), mutableSetOf(), compatibilityUpperBoundForTypeArg)
|
||||
}.let {
|
||||
val type = boundTypeArgument.type
|
||||
if (boundTypeArgument.variance.allowsInPosition) {
|
||||
it.lower += type.collectLowerBounds()
|
||||
}
|
||||
if (boundTypeArgument.variance.allowsOutPosition) {
|
||||
it.upper += type.collectUpperBounds()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirClassLikeDeclaration<*>.getSuperTypes(): List<ConeClassLikeType> {
|
||||
return when (this) {
|
||||
is FirTypeAlias -> listOfNotNull(expandedTypeRef.coneTypeSafe())
|
||||
is FirClass<*> -> superTypeRefs.mapNotNull { it.coneTypeSafe() }
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeClassLikeType.getClassLikeElement(ctx: ConeInferenceContext): FirClassLikeDeclaration<*>? =
|
||||
ctx.symbolProvider.getSymbolByLookupTag(lookupTag)?.fir
|
||||
|
||||
private fun FirClassLikeDeclaration<*>.getTypeParameter(index: Int): FirTypeParameterRef? {
|
||||
return when (this) {
|
||||
is FirTypeAlias -> typeParameters[index]
|
||||
is FirClass<*> -> typeParameters[index]
|
||||
else -> return null
|
||||
}
|
||||
}
|
||||
|
||||
/** A class declaration and the arguments bound to the declared type parameters. */
|
||||
private data class TypeArgumentMapping(
|
||||
val typeParameterOwner: FirClassLikeDeclaration<*>,
|
||||
val mapping: Map<FirTypeParameterRef, BoundTypeArgument>
|
||||
)
|
||||
|
||||
/** A single bound type argument to a type parameter declared in a class. */
|
||||
private data class BoundTypeArgument(val type: ConeKotlinType, val variance: Variance)
|
||||
|
||||
/** Accumulated type arguments bound to a type parameter declared in a class. */
|
||||
private data class BoundTypeArguments(
|
||||
val upper: MutableSet<ConeClassLikeType>,
|
||||
val lower: MutableSet<ConeClassLikeType>,
|
||||
val compatibilityUpperBound: Compatibility
|
||||
)
|
||||
|
||||
private fun ConeClassLikeType.toFirClassWithSuperClasses(ctx: ConeInferenceContext): FirClassWithSuperClasses? {
|
||||
return lookupTag.toFirClassWithSuperClasses(ctx)
|
||||
}
|
||||
|
||||
private fun ConeClassLikeLookupTag.toFirClassWithSuperClasses(
|
||||
ctx: ConeInferenceContext
|
||||
): FirClassWithSuperClasses? = when (val klass = ctx.symbolProvider.getSymbolByLookupTag(this)?.fir) {
|
||||
is FirTypeAlias -> klass.fullyExpandedClass(ctx.session)?.let { FirClassWithSuperClasses(it, ctx) }
|
||||
is FirClass<*> -> FirClassWithSuperClasses(klass, ctx)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private data class FirClassWithSuperClasses(val firClass: FirClass<*>, val ctx: ConeInferenceContext) {
|
||||
val isInterface: Boolean get() = firClass.isInterface
|
||||
|
||||
val superClasses: Set<FirClassWithSuperClasses> by lazy {
|
||||
firClass.superConeTypes.mapNotNull { it.lookupTag.toFirClassWithSuperClasses(ctx) }.toSet()
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
val thisAndAllSuperClasses: Set<FirClassWithSuperClasses> by lazy {
|
||||
val queue = ArrayDeque<FirClassWithSuperClasses>()
|
||||
queue.addLast(this)
|
||||
buildSet {
|
||||
add(this@FirClassWithSuperClasses)
|
||||
while (queue.isNotEmpty()) {
|
||||
val current = queue.removeFirst()
|
||||
val superTypes = current.superClasses
|
||||
superTypes.filterNotTo(queue) { it in this@buildSet }
|
||||
addAll(superTypes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val isFinal: Boolean get() = firClass.isFinal
|
||||
|
||||
/**
|
||||
* The following are considered to have a predefined equality contract:
|
||||
* - enums
|
||||
* - primitives (including unsigned integer types)
|
||||
* - classes
|
||||
* - strings
|
||||
* - objects of data classes
|
||||
* - objects of inline classes
|
||||
* - kotlin.Unit
|
||||
*/
|
||||
fun getHasPredefinedEqualityContract(ctx: ConeInferenceContext): Boolean {
|
||||
return (ctx.prohibitComparisonOfIncompatibleEnums && (firClass.isEnumClass || firClass.classId == StandardClassIds.Enum)) ||
|
||||
firClass.isPrimitiveType() ||
|
||||
(ctx.prohibitComparisonOfIncompatibleClasses && firClass.classId == StandardClassIds.KClass) ||
|
||||
firClass.classId == StandardClassIds.String || firClass.classId == StandardClassIds.Unit ||
|
||||
(firClass is FirRegularClass && (firClass.isData || firClass.isInline))
|
||||
}
|
||||
|
||||
private val FirClass<*>.isFinal: Boolean
|
||||
get() {
|
||||
return when (this) {
|
||||
is FirAnonymousObject -> true
|
||||
is FirRegularClass -> status.modality == Modality.FINAL
|
||||
else -> throw java.lang.IllegalStateException("unknown type of FirClass $this")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val ConeInferenceContext.prohibitComparisonOfIncompatibleEnums: Boolean
|
||||
get() = session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitComparisonOfIncompatibleEnums)
|
||||
|
||||
private val ConeInferenceContext.prohibitComparisonOfIncompatibleClasses: Boolean
|
||||
get() = session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitComparisonOfIncompatibleClasses)
|
||||
}
|
||||
@@ -9,14 +9,12 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.FirSymbolOwner
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.modalityModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.overrideModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.visibilityModifier
|
||||
import org.jetbrains.kotlin.fir.analysis.getChild
|
||||
import org.jetbrains.kotlin.fir.containingClass
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirComponentCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
@@ -36,7 +34,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
@@ -91,14 +88,6 @@ fun FirClass<*>.isSupertypeOf(other: FirClass<*>, session: FirSession): Boolean
|
||||
return isSupertypeOf(other, mutableSetOf())
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the FirClass associated with this
|
||||
* or null of something goes wrong.
|
||||
*/
|
||||
fun ConeClassLikeType.toClass(session: FirSession): FirClass<*>? {
|
||||
return lookupTag.toSymbol(session).safeAs<FirClassSymbol<*>>()?.fir
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the FirRegularClass associated with this
|
||||
* or null of something goes wrong.
|
||||
|
||||
@@ -1,70 +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.fir.analysis.checkers
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirLightSourceElement
|
||||
import org.jetbrains.kotlin.fir.FirPsiSourceElement
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.getAncestors
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.psi.KtConstructorCalleeExpression
|
||||
import org.jetbrains.kotlin.psi.KtTypeReference
|
||||
|
||||
/**
|
||||
* Service to answer source-related questions in generic fashion.
|
||||
* Shouldn't expose (receive or return) any specific source tree types
|
||||
*/
|
||||
interface SourceNavigator {
|
||||
|
||||
fun FirTypeRef.isInConstructorCallee(): Boolean
|
||||
|
||||
fun FirTypeRef.isInTypeConstraint(): Boolean
|
||||
|
||||
companion object {
|
||||
|
||||
private val lightTreeInstance = LightTreeSourceNavigator()
|
||||
|
||||
fun forElement(e: FirElement): SourceNavigator = when (e.source) {
|
||||
is FirLightSourceElement -> lightTreeInstance
|
||||
is FirPsiSourceElement<*> -> PsiSourceNavigator
|
||||
null -> lightTreeInstance //shouldn't matter
|
||||
}
|
||||
|
||||
inline fun <R> FirElement.withNavigator(block: SourceNavigator.() -> R): R = with(forElement(this), block)
|
||||
}
|
||||
}
|
||||
|
||||
open class LightTreeSourceNavigator : SourceNavigator {
|
||||
|
||||
private fun <T> FirElement.withSource(f: (FirSourceElement) -> T): T? =
|
||||
source?.let { f(it) }
|
||||
|
||||
override fun FirTypeRef.isInConstructorCallee(): Boolean = withSource { source ->
|
||||
source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.CONSTRUCTOR_CALLEE
|
||||
} ?: false
|
||||
|
||||
override fun FirTypeRef.isInTypeConstraint(): Boolean {
|
||||
val source = source ?: return false
|
||||
return source.treeStructure.getAncestors(source.lighterASTNode)
|
||||
.find { it.tokenType == KtNodeTypes.TYPE_CONSTRAINT || it.tokenType == KtNodeTypes.TYPE_PARAMETER }
|
||||
?.tokenType == KtNodeTypes.TYPE_CONSTRAINT
|
||||
}
|
||||
}
|
||||
|
||||
//by default psi tree can reuse light tree manipulations
|
||||
object PsiSourceNavigator : LightTreeSourceNavigator() {
|
||||
|
||||
//Swallows incorrect casts!!!
|
||||
private inline fun <reified P : PsiElement> FirElement.psi(): P? {
|
||||
val psi = (source as? FirPsiSourceElement<*>)?.psi
|
||||
return psi as? P
|
||||
}
|
||||
|
||||
override fun FirTypeRef.isInConstructorCallee(): Boolean = psi<KtTypeReference>()?.parent is KtConstructorCalleeExpression
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.fir.analysis.checkers.expression
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.ConstantArgumentKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.checkConstantArguments
|
||||
@@ -13,17 +14,20 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
|
||||
object FirAnnotationArgumentChecker : FirAnnotationCallChecker() {
|
||||
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val argumentMapping = expression.argumentMapping ?: return
|
||||
for ((arg, _) in argumentMapping) {
|
||||
val argExpression = (arg as? FirNamedArgumentExpression)?.expression ?: arg
|
||||
object FirAnnotationArgumentChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration !is FirAnnotationContainer) return
|
||||
for (declarationOfAnnotation in declaration.annotations) {
|
||||
for ((arg, _) in declarationOfAnnotation.argumentMapping ?: continue) {
|
||||
val expression = (arg as? FirNamedArgumentExpression)?.expression ?: arg
|
||||
|
||||
checkAnnotationArgumentWithSubElements(argExpression, context.session, reporter, context)
|
||||
?.let { reporter.reportOn(argExpression.source, it, context) }
|
||||
checkAnnotationArgumentWithSubElements(expression, context.session, reporter, context)
|
||||
?.let { reporter.reportOn(expression.source, it, context) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,8 +186,7 @@ internal val FirDeclaration.isEnumEntryInitializer: Boolean
|
||||
return (containingClassAttr as? ConeClassLookupTagWithFixedSymbol)?.symbol?.fir?.classKind == ClassKind.ENUM_ENTRY
|
||||
}
|
||||
|
||||
// contract: returns(true) implies (this is FirMemberDeclaration)
|
||||
internal val FirDeclaration.isLocalMember: Boolean
|
||||
internal val FirMemberDeclaration.isLocalMember: Boolean
|
||||
get() = when (this) {
|
||||
is FirProperty -> this.isLocal
|
||||
is FirRegularClass -> this.isLocal
|
||||
|
||||
@@ -21,23 +21,18 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinErrorType
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.render
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
object FirDelegatedPropertyChecker : FirPropertyChecker() {
|
||||
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val delegate = declaration.delegate ?: return
|
||||
val delegateType = delegate.typeRef.coneType
|
||||
|
||||
// TODO: Also suppress delegate issue if type inference failed. For example, in
|
||||
// compiler/testData/diagnostics/tests/delegatedProperty/inference/differentDelegatedExpressions.fir.kt, no delegate issues are
|
||||
// reported due to the inference issue.
|
||||
if (delegateType is ConeKotlinErrorType) {
|
||||
val delegateSource = delegate.source
|
||||
// Implicit recursion type is not reported since the type ref does not have a real source.
|
||||
@@ -52,13 +47,8 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
|
||||
override fun visitElement(element: FirElement) = element.acceptChildren(this)
|
||||
|
||||
override fun visitFunctionCall(functionCall: FirFunctionCall) {
|
||||
val hasReferenceError = hasFunctionReferenceErrors(functionCall)
|
||||
if (isGet && !hasReferenceError) checkReturnType(functionCall)
|
||||
}
|
||||
|
||||
private fun hasFunctionReferenceErrors(functionCall: FirFunctionCall): Boolean {
|
||||
val errorNamedReference = functionCall.calleeReference as? FirErrorNamedReference ?: return false
|
||||
if (errorNamedReference.source?.kind != FirFakeSourceElementKind.DelegatedPropertyAccessor) return false
|
||||
val errorNamedReference = functionCall.calleeReference as? FirErrorNamedReference ?: return
|
||||
if (errorNamedReference.source?.kind != FirFakeSourceElementKind.DelegatedPropertyAccessor) return
|
||||
val expectedFunctionSignature =
|
||||
(if (isGet) "getValue" else "setValue") + "(${functionCall.arguments.joinToString(", ") { it.typeRef.coneType.render() }})"
|
||||
val delegateDescription = if (isGet) "delegate" else "delegate for var (read-write property)"
|
||||
@@ -87,7 +77,7 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
return when (val diagnostic = errorNamedReference.diagnostic) {
|
||||
when (val diagnostic = errorNamedReference.diagnostic) {
|
||||
is ConeUnresolvedNameError -> {
|
||||
reporter.reportOn(
|
||||
errorNamedReference.source,
|
||||
@@ -97,7 +87,6 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
|
||||
delegateDescription,
|
||||
context
|
||||
)
|
||||
true
|
||||
}
|
||||
is ConeAmbiguityError -> {
|
||||
if (diagnostic.applicability.isSuccess) {
|
||||
@@ -112,28 +101,10 @@ object FirDelegatedPropertyChecker : FirPropertyChecker() {
|
||||
} else {
|
||||
reportInapplicableDiagnostics(diagnostic.applicability, diagnostic.candidates.map { it.symbol })
|
||||
}
|
||||
true
|
||||
}
|
||||
is ConeInapplicableCandidateError -> {
|
||||
reportInapplicableDiagnostics(diagnostic.applicability, listOf(diagnostic.candidate.symbol))
|
||||
true
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkReturnType(functionCall: FirFunctionCall) {
|
||||
val returnType = functionCall.typeRef.coneType
|
||||
val propertyType = declaration.returnTypeRef.coneType
|
||||
if (!AbstractTypeChecker.isSubtypeOf(context.session.typeContext, returnType, propertyType)) {
|
||||
reporter.reportOn(
|
||||
delegate.source,
|
||||
FirErrors.DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH,
|
||||
"getValue",
|
||||
propertyType,
|
||||
returnType,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||
import org.jetbrains.kotlin.fir.declarations.isInterface
|
||||
|
||||
object FirDelegationInInterfaceChecker : FirRegularClassChecker() {
|
||||
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.isInterface) {
|
||||
return
|
||||
}
|
||||
|
||||
for (superTypeRef in declaration.superTypeRefs) {
|
||||
val source = superTypeRef.source ?: continue
|
||||
if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.DELEGATED_SUPER_TYPE_ENTRY) {
|
||||
reporter.reportOn(source, FirErrors.DELEGATION_IN_INTERFACE, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.toFirLightSourceElement
|
||||
|
||||
object FirFunctionTypeParametersChecker : FirSimpleFunctionChecker() {
|
||||
|
||||
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
declaration.source?.let { source ->
|
||||
if (source.kind is FirFakeSourceElementKind) return
|
||||
|
||||
val typeParamsNode = source.treeStructure.typeParametersList(source.lighterASTNode)
|
||||
val nameNode = source.treeStructure.nameIdentifier(source.lighterASTNode)
|
||||
if (typeParamsNode != null && nameNode != null && typeParamsNode.startOffset > nameNode.startOffset) {
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.DEPRECATED_TYPE_PARAMETER_SYNTAX,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,312 +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.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.util.checkChildrenWithCustomVisitor
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.references.FirSuperReference
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.isFunctionalType
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.publishedApiEffectiveVisibility
|
||||
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.isMarkedNullable
|
||||
import org.jetbrains.kotlin.fir.types.toSymbol
|
||||
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
object FirInlineDeclarationChecker : FirMemberDeclarationChecker() {
|
||||
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (!declaration.isInline) return
|
||||
// local inline functions are prohibited
|
||||
if (declaration.isLocalMember) return
|
||||
if (declaration !is FirPropertyAccessor && declaration !is FirSimpleFunction) return
|
||||
|
||||
val effectiveVisibility = declaration.effectiveVisibility
|
||||
val function = declaration as FirFunction<*>
|
||||
checkInlineFunctionBody(function, effectiveVisibility, context, reporter)
|
||||
}
|
||||
|
||||
private fun checkInlineFunctionBody(
|
||||
function: FirFunction<*>,
|
||||
effectiveVisibility: EffectiveVisibility,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
val body = function.body ?: return
|
||||
val inlinableParameters = function.valueParameters.filter {
|
||||
if (it.isNoinline) return@filter false
|
||||
val type = it.returnTypeRef.coneType
|
||||
!type.isMarkedNullable && type.isFunctionalType(context.session) { kind -> !kind.isReflectType }
|
||||
}
|
||||
|
||||
val visitor = Visitor(
|
||||
function,
|
||||
effectiveVisibility,
|
||||
inlinableParameters,
|
||||
context.session,
|
||||
reporter
|
||||
)
|
||||
body.checkChildrenWithCustomVisitor(context, visitor)
|
||||
}
|
||||
|
||||
private class Visitor(
|
||||
val inlineFunction: FirFunction<*>,
|
||||
val inlineFunEffectiveVisibility: EffectiveVisibility,
|
||||
val inlinableParameters: List<FirValueParameter>,
|
||||
val session: FirSession,
|
||||
val reporter: DiagnosticReporter
|
||||
) : FirDefaultVisitor<Unit, CheckerContext>() {
|
||||
private val isEffectivelyPrivateApiFunction: Boolean = inlineFunEffectiveVisibility.privateApi
|
||||
|
||||
private val prohibitProtectedCallFromInline: Boolean =
|
||||
session.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitProtectedCallFromInline)
|
||||
|
||||
override fun visitElement(element: FirElement, data: CheckerContext) {}
|
||||
|
||||
override fun visitFunctionCall(functionCall: FirFunctionCall, data: CheckerContext) {
|
||||
val targetSymbol = functionCall.toResolvedCallableSymbol()
|
||||
checkReceiversOfQualifiedAccessExpression(functionCall, targetSymbol, data)
|
||||
checkArgumentsOfCall(functionCall, targetSymbol, data)
|
||||
checkQualifiedAccess(functionCall, targetSymbol, data)
|
||||
}
|
||||
|
||||
override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: CheckerContext) {
|
||||
val targetSymbol = qualifiedAccessExpression.toResolvedCallableSymbol()
|
||||
checkQualifiedAccess(qualifiedAccessExpression, targetSymbol, data)
|
||||
checkReceiversOfQualifiedAccessExpression(qualifiedAccessExpression, targetSymbol, data)
|
||||
}
|
||||
|
||||
override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: CheckerContext) {
|
||||
val propertySymbol = variableAssignment.calleeReference.toResolvedCallableSymbol() as? FirPropertySymbol ?: return
|
||||
val setterSymbol = propertySymbol.fir.setter?.symbol ?: return
|
||||
checkQualifiedAccess(variableAssignment, setterSymbol, data)
|
||||
}
|
||||
|
||||
private fun checkReceiversOfQualifiedAccessExpression(
|
||||
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||
targetSymbol: AbstractFirBasedSymbol<*>?,
|
||||
context: CheckerContext
|
||||
) {
|
||||
checkReceiver(qualifiedAccessExpression, qualifiedAccessExpression.dispatchReceiver, targetSymbol, context)
|
||||
checkReceiver(qualifiedAccessExpression, qualifiedAccessExpression.extensionReceiver, targetSymbol, context)
|
||||
}
|
||||
|
||||
private fun checkArgumentsOfCall(
|
||||
functionCall: FirFunctionCall,
|
||||
targetSymbol: AbstractFirBasedSymbol<*>?,
|
||||
context: CheckerContext
|
||||
) {
|
||||
val calledFunction = (targetSymbol as? FirNamedFunctionSymbol)?.fir ?: return
|
||||
val argumentMapping = functionCall.resolvedArgumentMapping ?: return
|
||||
for ((wrappedArgument, valueParameter) in argumentMapping) {
|
||||
val argument = wrappedArgument.unwrapArgument()
|
||||
val resolvedArgumentSymbol = argument.toResolvedCallableSymbol() as? FirVariableSymbol<*> ?: continue
|
||||
|
||||
val valueParameterOfOriginalInlineFunction = inlinableParameters.firstOrNull { it == resolvedArgumentSymbol.fir }
|
||||
if (valueParameterOfOriginalInlineFunction != null) {
|
||||
val factory = when {
|
||||
calledFunction.isInline -> when {
|
||||
valueParameter.isNoinline -> FirErrors.USAGE_IS_NOT_INLINABLE
|
||||
valueParameter.isCrossinline && !valueParameterOfOriginalInlineFunction.isCrossinline
|
||||
-> FirErrors.NON_LOCAL_RETURN_NOT_ALLOWED
|
||||
else -> continue
|
||||
}
|
||||
else -> FirErrors.USAGE_IS_NOT_INLINABLE
|
||||
}
|
||||
reporter.reportOn(argument.source, factory, valueParameterOfOriginalInlineFunction.symbol, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkReceiver(
|
||||
qualifiedAccessExpression: FirQualifiedAccessExpression,
|
||||
receiverExpression: FirExpression,
|
||||
targetSymbol: AbstractFirBasedSymbol<*>?,
|
||||
context: CheckerContext
|
||||
) {
|
||||
val receiverSymbol = receiverExpression.toResolvedCallableSymbol() ?: return
|
||||
if (receiverSymbol.fir in inlinableParameters) {
|
||||
val valueParameter = receiverSymbol.fir as FirValueParameter
|
||||
if (!isInvokeOrInlineExtension(targetSymbol)) {
|
||||
reporter.reportOn(
|
||||
qualifiedAccessExpression.source,
|
||||
FirErrors.USAGE_IS_NOT_INLINABLE,
|
||||
valueParameter.symbol,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isInvokeOrInlineExtension(targetSymbol: AbstractFirBasedSymbol<*>?): Boolean {
|
||||
if (targetSymbol !is FirNamedFunctionSymbol) return false
|
||||
val function = targetSymbol.fir
|
||||
if (function.isInline) return true
|
||||
return function.name == OperatorNameConventions.INVOKE &&
|
||||
function.dispatchReceiverType?.isBuiltinFunctionalType(session) == true
|
||||
}
|
||||
|
||||
private fun checkQualifiedAccess(
|
||||
qualifiedAccess: FirQualifiedAccess,
|
||||
targetSymbol: AbstractFirBasedSymbol<*>?,
|
||||
context: CheckerContext
|
||||
) {
|
||||
val source = qualifiedAccess.source ?: return
|
||||
if (targetSymbol == null) return
|
||||
val targetFir = targetSymbol.fir as? FirCallableMemberDeclaration<*>
|
||||
|
||||
if (targetSymbol.fir in inlinableParameters) {
|
||||
if (!qualifiedAccess.partOfCall(context)) {
|
||||
val valueParameter = targetSymbol.fir as FirValueParameter
|
||||
reporter.reportOn(source, FirErrors.USAGE_IS_NOT_INLINABLE, valueParameter.symbol, context)
|
||||
}
|
||||
}
|
||||
checkVisibilityAndAccess(qualifiedAccess, targetFir, source, context)
|
||||
checkRecursion(targetSymbol, source, context)
|
||||
}
|
||||
|
||||
private fun FirQualifiedAccess.partOfCall(context: CheckerContext): Boolean {
|
||||
if (this !is FirExpression) return false
|
||||
val containingQualifiedAccess = context.qualifiedAccesses.getOrNull(context.qualifiedAccesses.size - 2) ?: return false
|
||||
if (this == containingQualifiedAccess.explicitReceiver) return true
|
||||
val call = containingQualifiedAccess as? FirCall ?: return false
|
||||
return call.arguments.any { it.unwrapArgument() == this }
|
||||
}
|
||||
|
||||
private fun checkVisibilityAndAccess(
|
||||
accessExpression: FirQualifiedAccess,
|
||||
calledDeclaration: FirCallableMemberDeclaration<*>?,
|
||||
source: FirSourceElement,
|
||||
context: CheckerContext
|
||||
) {
|
||||
if (calledDeclaration == null) return
|
||||
val recordedEffectiveVisibility = calledDeclaration.publishedApiEffectiveVisibility ?: calledDeclaration.effectiveVisibility
|
||||
val calledFunEffectiveVisibility = recordedEffectiveVisibility.let {
|
||||
if (it == EffectiveVisibility.Local) {
|
||||
EffectiveVisibility.Public
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
val isCalledFunPublicOrPublishedApi = calledFunEffectiveVisibility.publicApi
|
||||
val isInlineFunPublicOrPublishedApi = inlineFunEffectiveVisibility.publicApi
|
||||
if (isInlineFunPublicOrPublishedApi &&
|
||||
!isCalledFunPublicOrPublishedApi &&
|
||||
calledDeclaration.visibility !== Visibilities.Local
|
||||
) {
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.NON_PUBLIC_CALL_FROM_PUBLIC_INLINE,
|
||||
calledDeclaration.symbol,
|
||||
inlineFunction.symbol,
|
||||
context
|
||||
)
|
||||
} else {
|
||||
checkPrivateClassMemberAccess(calledDeclaration, source, context)
|
||||
if (isInlineFunPublicOrPublishedApi) {
|
||||
checkSuperCalls(calledDeclaration, accessExpression, context)
|
||||
}
|
||||
}
|
||||
|
||||
val isConstructorCall = calledDeclaration is FirConstructor
|
||||
if (
|
||||
isInlineFunPublicOrPublishedApi &&
|
||||
inlineFunEffectiveVisibility.toVisibility() !== Visibilities.Protected &&
|
||||
calledFunEffectiveVisibility.toVisibility() === Visibilities.Protected
|
||||
) {
|
||||
val factory = when {
|
||||
isConstructorCall -> FirErrors.PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE
|
||||
prohibitProtectedCallFromInline -> FirErrors.PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR
|
||||
else -> FirErrors.PROTECTED_CALL_FROM_PUBLIC_INLINE
|
||||
}
|
||||
reporter.reportOn(source, factory, calledDeclaration.symbol, inlineFunction.symbol, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPrivateClassMemberAccess(
|
||||
calledDeclaration: FirCallableMemberDeclaration<*>,
|
||||
source: FirSourceElement,
|
||||
context: CheckerContext
|
||||
) {
|
||||
if (!isEffectivelyPrivateApiFunction) {
|
||||
if (calledDeclaration.isInsidePrivateClass()) {
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.PRIVATE_CLASS_MEMBER_FROM_INLINE,
|
||||
calledDeclaration.symbol,
|
||||
inlineFunction.symbol,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkSuperCalls(
|
||||
calledDeclaration: FirCallableMemberDeclaration<*>,
|
||||
callExpression: FirQualifiedAccess,
|
||||
context: CheckerContext
|
||||
) {
|
||||
val receiver = callExpression.dispatchReceiver as? FirQualifiedAccessExpression ?: return
|
||||
if (receiver.calleeReference is FirSuperReference) {
|
||||
val dispatchReceiverType = receiver.dispatchReceiver.typeRef.coneType
|
||||
val classSymbol = dispatchReceiverType.toSymbol(session) ?: return
|
||||
if (!classSymbol.isDefinedInInlineFunction()) {
|
||||
reporter.reportOn(
|
||||
callExpression.dispatchReceiver.source,
|
||||
FirErrors.SUPER_CALL_FROM_PUBLIC_INLINE,
|
||||
calledDeclaration.symbol,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun AbstractFirBasedSymbol<*>.isDefinedInInlineFunction(): Boolean {
|
||||
return when (val fir = this.fir) {
|
||||
is FirAnonymousFunction -> true
|
||||
is FirMemberDeclaration -> fir.isLocalMember
|
||||
is FirAnonymousObject -> true
|
||||
is FirRegularClass -> fir.classId.isLocal
|
||||
else -> error("Unknown callable declaration type: ${fir.render()}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkRecursion(
|
||||
targetSymbol: AbstractFirBasedSymbol<*>,
|
||||
source: FirSourceElement,
|
||||
context: CheckerContext
|
||||
) {
|
||||
if (targetSymbol == inlineFunction.symbol) {
|
||||
reporter.reportOn(source, FirErrors.RECURSION_IN_INLINE, targetSymbol, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirCallableMemberDeclaration<*>.isInsidePrivateClass(): Boolean {
|
||||
val containingClass = this.containingClass()?.toSymbol(session)?.fir ?: return false
|
||||
|
||||
val containingClassVisibility = when (containingClass) {
|
||||
is FirAnonymousObject -> return false
|
||||
is FirRegularClass -> containingClass.visibility
|
||||
is FirTypeAlias -> containingClass.visibility
|
||||
}
|
||||
return containingClassVisibility == Visibilities.Private || containingClassVisibility == Visibilities.PrivateToThis
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,58 +63,11 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
return false
|
||||
}
|
||||
|
||||
fun FirIntersectionCallableSymbol.subjectToManyNotImplemented(): Boolean {
|
||||
var nonAbstractCountInClass = 0
|
||||
var nonAbstractCountInInterface = 0
|
||||
var abstractCountInInterface = 0
|
||||
for (intersectionSymbol in intersections) {
|
||||
val intersection = intersectionSymbol.fir as FirCallableMemberDeclaration
|
||||
val containingClass = intersection.getContainingClass(context) as? FirRegularClass
|
||||
val hasInterfaceContainer = containingClass?.classKind == ClassKind.INTERFACE
|
||||
if (intersection.modality != Modality.ABSTRACT) {
|
||||
if (hasInterfaceContainer) {
|
||||
nonAbstractCountInInterface++
|
||||
} else {
|
||||
nonAbstractCountInClass++
|
||||
}
|
||||
} else if (hasInterfaceContainer) {
|
||||
abstractCountInInterface++
|
||||
}
|
||||
if (nonAbstractCountInClass + nonAbstractCountInInterface > 1) {
|
||||
return true
|
||||
}
|
||||
if (nonAbstractCountInInterface > 0 && abstractCountInInterface > 0) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun FirIntersectionCallableSymbol.shouldBeImplemented(): Boolean {
|
||||
// In Java 8, non-abstract intersection overrides having abstract symbol from base class
|
||||
// still should be implemented in current class (even when they have default interface implementation)
|
||||
if (intersections.none {
|
||||
val fir = (it.fir as FirCallableMemberDeclaration).unwrapFakeOverrides()
|
||||
fir.isAbstract && (fir.getContainingClass(context) as? FirRegularClass)?.classKind == ClassKind.CLASS
|
||||
}
|
||||
) return false
|
||||
// Exception from the rule above: interface implementation via delegation
|
||||
if (intersections.any {
|
||||
val fir = (it.fir as FirCallableMemberDeclaration)
|
||||
fir.origin == FirDeclarationOrigin.Delegated && !fir.isAbstract
|
||||
}
|
||||
) return false
|
||||
return true
|
||||
}
|
||||
|
||||
fun FirCallableMemberDeclaration<*>.shouldBeImplemented(): Boolean {
|
||||
if (!isAbstract) return false
|
||||
val containingClass = getContainingClass(context)
|
||||
if (containingClass is FirRegularClass && containingClass.isExpect) return false
|
||||
if (!isAbstract) {
|
||||
val symbol = symbol as? FirIntersectionCallableSymbol ?: return false
|
||||
return symbol.shouldBeImplemented()
|
||||
}
|
||||
if (containingClass === declaration && origin == FirDeclarationOrigin.Source) return false
|
||||
if (containingClass is FirRegularClass && containingClass.isExpect) return false
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -122,8 +75,9 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
classScope.processFunctionsByName(name) { namedFunctionSymbol ->
|
||||
val simpleFunction = namedFunctionSymbol.fir
|
||||
if (namedFunctionSymbol is FirIntersectionOverrideFunctionSymbol) {
|
||||
if (simpleFunction.getContainingClass(context) === declaration &&
|
||||
namedFunctionSymbol.subjectToManyNotImplemented()
|
||||
if (namedFunctionSymbol.intersections.count {
|
||||
(it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT
|
||||
} > 1 && simpleFunction.getContainingClass(context) === declaration
|
||||
) {
|
||||
notImplementedIntersectionSymbols += namedFunctionSymbol
|
||||
return@processFunctionsByName
|
||||
@@ -145,8 +99,9 @@ object FirNotImplementedOverrideChecker : FirClassChecker() {
|
||||
classScope.processPropertiesByName(name) { propertySymbol ->
|
||||
val property = propertySymbol.fir as? FirProperty ?: return@processPropertiesByName
|
||||
if (propertySymbol is FirIntersectionOverridePropertySymbol) {
|
||||
if (property.getContainingClass(context) === declaration &&
|
||||
propertySymbol.subjectToManyNotImplemented()
|
||||
if (propertySymbol.intersections.count {
|
||||
(it.fir as FirCallableMemberDeclaration).modality != Modality.ABSTRACT
|
||||
} > 1 && property.getContainingClass(context) === declaration
|
||||
) {
|
||||
notImplementedIntersectionSymbols += propertySymbol
|
||||
return@processPropertiesByName
|
||||
|
||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.SourceNavigator
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
@@ -26,11 +25,10 @@ import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
|
||||
object FirPrimaryConstructorSuperTypeChecker : FirRegularClassChecker() {
|
||||
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration.isInterface) {
|
||||
with(SourceNavigator.forElement(declaration)) {
|
||||
for (superTypeRef in declaration.superTypeRefs) {
|
||||
if (superTypeRef.isInConstructorCallee()) {
|
||||
reporter.reportOn(superTypeRef.source, FirErrors.SUPERTYPE_INITIALIZED_IN_INTERFACE, context)
|
||||
}
|
||||
for (superTypeRef in declaration.superTypeRefs) {
|
||||
val source = superTypeRef.source ?: continue
|
||||
if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.CONSTRUCTOR_CALLEE) {
|
||||
reporter.reportOn(source, FirErrors.SUPERTYPE_INITIALIZED_IN_INTERFACE, context)
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -99,11 +97,10 @@ object FirPrimaryConstructorSuperTypeChecker : FirRegularClassChecker() {
|
||||
reporter: DiagnosticReporter,
|
||||
context: CheckerContext
|
||||
) {
|
||||
with(SourceNavigator.forElement(regularClass)) {
|
||||
for (superTypeRef in regularClass.superTypeRefs) {
|
||||
if (superTypeRef.isInConstructorCallee()) {
|
||||
reporter.reportOn(regularClass.source, FirErrors.SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, context)
|
||||
}
|
||||
for (superTypeRef in regularClass.superTypeRefs) {
|
||||
val source = superTypeRef.source ?: continue
|
||||
if (source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.CONSTRUCTOR_CALLEE) {
|
||||
reporter.reportOn(regularClass.source, FirErrors.SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.getAncestors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
@@ -41,6 +43,7 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
|
||||
checkBoundUniqueness(declaration, context, reporter)
|
||||
checkConflictingBounds(declaration, context, reporter)
|
||||
checkTypeAliasBound(declaration, containingDeclaration, context, reporter)
|
||||
checkBoundsPlacement(declaration, context, reporter)
|
||||
checkDynamicBounds(declaration, context, reporter)
|
||||
}
|
||||
|
||||
@@ -89,9 +92,7 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
|
||||
// report the diagnostic on that bound
|
||||
|
||||
//take TypeConstraint bounds only to report on the same point as old FE
|
||||
val constraintBounds = with(SourceNavigator.forElement(declaration)){
|
||||
bounds.filter { it.isInTypeConstraint() }.toSet()
|
||||
}
|
||||
val constraintBounds = bounds.filter { it.isInTypeConstraint() }.toSet()
|
||||
val reportOn =
|
||||
if (bounds.size == 2) {
|
||||
val boundDecl = otherBounds.firstOrNull() ?: boundWithParam.last()
|
||||
@@ -104,6 +105,14 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirTypeRef.isInTypeConstraint(): Boolean {
|
||||
val source = source ?: return false
|
||||
return source.treeStructure.getAncestors(source.lighterASTNode)
|
||||
.find { it.tokenType == KtNodeTypes.TYPE_CONSTRAINT || it.tokenType == KtNodeTypes.TYPE_PARAMETER }
|
||||
?.tokenType == KtNodeTypes.TYPE_CONSTRAINT
|
||||
}
|
||||
|
||||
|
||||
private fun checkBoundUniqueness(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val seenClasses = mutableSetOf<FirRegularClass>()
|
||||
val allNonErrorBounds = declaration.bounds.filter { it !is FirErrorTypeRef }
|
||||
@@ -143,6 +152,16 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO should be moved to extended checkers (because this is basically a code-style warning)
|
||||
private fun checkBoundsPlacement(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration.bounds.size < 2) return
|
||||
|
||||
val (constraint, params) = declaration.bounds.partition { it.isInTypeConstraint() }
|
||||
if (params.isNotEmpty() && constraint.isNotEmpty()) {
|
||||
reporter.reportOn(declaration.source, FirErrors.MISPLACED_TYPE_PARAMETER_CONSTRAINTS, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDynamicBounds(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
declaration.bounds.forEach { bound ->
|
||||
if (bound is FirDynamicTypeRef) {
|
||||
|
||||
@@ -20,5 +20,22 @@ object FirAnonymousFunctionChecker : FirAnonymousFunctionAsExpressionChecker() {
|
||||
reporter.reportOn(source, FirErrors.USELESS_VARARG_ON_PARAMETER, context)
|
||||
}
|
||||
}
|
||||
|
||||
checkTypeParameters(expression, reporter, context)
|
||||
}
|
||||
|
||||
private fun checkTypeParameters(
|
||||
expression: FirAnonymousFunction,
|
||||
reporter: DiagnosticReporter,
|
||||
context: CheckerContext
|
||||
) {
|
||||
val source = expression.source ?: return
|
||||
source.treeStructure.typeParametersList(source.lighterASTNode)?.let { _ ->
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.TYPE_PARAMETERS_NOT_ALLOWED,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +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.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.isAbstract
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
|
||||
object FirConstructorCallChecker : FirFunctionCallChecker() {
|
||||
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val constructorSymbol =
|
||||
(expression.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirConstructorSymbol ?: return
|
||||
val declarationClass = constructorSymbol.fir.returnTypeRef.coneType.toRegularClass(context.session)
|
||||
|
||||
if (declarationClass != null && declarationClass.isAbstract && declarationClass.classKind == ClassKind.CLASS) {
|
||||
reporter.reportOn(expression.source, FirErrors.CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +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.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.isEnumClass
|
||||
import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.inferenceComponents
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClass
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.ConeTypeCompatibilityChecker.areCompatible
|
||||
|
||||
object FirEqualityCompatibilityChecker : FirEqualityOperatorCallChecker() {
|
||||
override fun check(expression: FirEqualityOperatorCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val arguments = expression.argumentList.arguments
|
||||
if (arguments.size != 2) return
|
||||
val lType = arguments[0].typeRef.coneType
|
||||
val rType = arguments[1].typeRef.coneType
|
||||
// If one of the type is already `Nothing?`, we skip reporting further comparison. This is to allow comparing with `null`, which has
|
||||
// type `Nothing?`
|
||||
if (lType.isNullableNothing || rType.isNullableNothing) return
|
||||
val inferenceContext = context.session.inferenceComponents.ctx
|
||||
val intersectionType = inferenceContext.intersectTypesOrNull(listOf(lType, rType)) as? ConeIntersectionType ?: return
|
||||
|
||||
val compatibility = intersectionType.intersectedTypes.areCompatible(inferenceContext)
|
||||
if (compatibility != ConeTypeCompatibilityChecker.Compatibility.COMPATIBLE) {
|
||||
when (expression.source?.kind) {
|
||||
FirRealSourceElementKind -> {
|
||||
// Note: FE1.0 reports INCOMPATIBLE_ENUM_COMPARISON_ERROR only when TypeIntersector.isIntersectionEmpty() thinks the
|
||||
// given types are compatible. Exactly mimicking the behavior of FE1.0 is difficult and does not seem to provide any
|
||||
// value. So instead, we deterministically output INCOMPATIBLE_ENUM_COMPARISON_ERROR if at least one of the value is an
|
||||
// enum.
|
||||
if (compatibility == ConeTypeCompatibilityChecker.Compatibility.HARD_INCOMPATIBLE &&
|
||||
(lType.isEnumType(context) || rType.isEnumType(context))
|
||||
) {
|
||||
reporter.reportOn(
|
||||
expression.source,
|
||||
FirErrors.INCOMPATIBLE_ENUM_COMPARISON_ERROR,
|
||||
lType,
|
||||
rType,
|
||||
context
|
||||
)
|
||||
} else {
|
||||
reporter.reportOn(
|
||||
expression.source,
|
||||
if (compatibility == ConeTypeCompatibilityChecker.Compatibility.HARD_INCOMPATIBLE) {
|
||||
FirErrors.EQUALITY_NOT_APPLICABLE
|
||||
} else {
|
||||
FirErrors.EQUALITY_NOT_APPLICABLE_WARNING
|
||||
},
|
||||
expression.operation.operator,
|
||||
lType,
|
||||
rType,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
else -> reporter.reportOn(
|
||||
expression.source,
|
||||
if (compatibility == ConeTypeCompatibilityChecker.Compatibility.HARD_INCOMPATIBLE) {
|
||||
FirErrors.INCOMPATIBLE_TYPES
|
||||
} else {
|
||||
FirErrors.INCOMPATIBLE_TYPES_WARNING
|
||||
},
|
||||
lType,
|
||||
rType,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ConeKotlinType.isEnumType(
|
||||
context: CheckerContext
|
||||
): Boolean {
|
||||
if (isEnum) return true
|
||||
val firRegularClass = (this as? ConeClassLikeType)?.lookupTag?.toFirRegularClass(context.session) ?: return false
|
||||
return firRegularClass.isEnumClass
|
||||
}
|
||||
}
|
||||
@@ -1,206 +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.fir.analysis.checkers.expression
|
||||
|
||||
import com.intellij.lang.LighterASTNode
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.fir.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.FirBasicDeclarationChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtDotQualifiedExpressionElementType
|
||||
import org.jetbrains.kotlin.psi.stubs.elements.KtNameReferenceExpressionElementType
|
||||
|
||||
object FirReservedUnderscoreExpressionChecker : FirBasicExpressionChecker() {
|
||||
override fun check(expression: FirStatement, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val source = expression.source
|
||||
|
||||
if (expression is FirFunctionCall) {
|
||||
val calleeReferenceSource = expression.calleeReference.source
|
||||
if (calleeReferenceSource is FirLightSourceElement && calleeReferenceSource.lighterASTNode.tokenType == KtNodeTypes.OPERATION_REFERENCE) {
|
||||
return
|
||||
}
|
||||
|
||||
reportIfUnderscore(
|
||||
expression.calleeReference.source.text, expression.calleeReference.source, context, reporter,
|
||||
isExpression = true
|
||||
)
|
||||
} else if (expression is FirQualifiedAccess) {
|
||||
if (source is FirPsiSourceElement<*>) {
|
||||
reportIfUnderscoreInQualifiedAccess(source, expression, context, reporter)
|
||||
} else if (source is FirLightSourceElement) {
|
||||
reportIfUnderscoreInQualifiedAccess(source, expression, context, reporter)
|
||||
}
|
||||
} else if (expression is FirGetClassCall) {
|
||||
for (argument in expression.argumentList.arguments) {
|
||||
reportIfUnderscore(argument.source.text, expression.source, context, reporter, isExpression = true)
|
||||
}
|
||||
} else if (expression is FirReturnExpression) {
|
||||
var labelName: String? = null
|
||||
if (source is FirPsiSourceElement<*>) {
|
||||
labelName = (source.psi.parent as? KtLabeledExpression)?.getLabelName()
|
||||
} else if (source is FirLightSourceElement) {
|
||||
val parent = source.treeStructure.getParent(source.lighterASTNode)
|
||||
if (parent != null && parent.tokenType == KtNodeTypes.LABELED_EXPRESSION) {
|
||||
labelName = source.treeStructure.findDescendantByType(parent, KtNodeTypes.LABEL).toString()
|
||||
labelName = labelName.substring(0, labelName.length - 1)
|
||||
}
|
||||
}
|
||||
|
||||
reportIfUnderscore(labelName, expression.source, context, reporter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportIfUnderscoreInQualifiedAccess(
|
||||
source: FirPsiSourceElement<*>,
|
||||
expression: FirStatement,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
fun processQualifiedAccess(psi: PsiElement?) {
|
||||
if (psi is KtNameReferenceExpression) {
|
||||
reportIfUnderscore(psi.text, expression.source, context, reporter, isExpression = true)
|
||||
} else if (psi is KtDotQualifiedExpression || psi is KtCallableReferenceExpression) {
|
||||
processQualifiedAccess(psi.firstChild)
|
||||
processQualifiedAccess(psi.lastChild)
|
||||
}
|
||||
}
|
||||
|
||||
val psi = source.psi
|
||||
if (psi.parent !is KtDotQualifiedExpression && psi.parent !is KtCallableReferenceExpression) {
|
||||
processQualifiedAccess(psi)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportIfUnderscoreInQualifiedAccess(
|
||||
source: FirLightSourceElement,
|
||||
expression: FirStatement,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
fun processQualifiedAccess(lightSourceElement: LighterASTNode?) {
|
||||
val tokenType = lightSourceElement?.tokenType
|
||||
if (tokenType is KtNameReferenceExpressionElementType) {
|
||||
reportIfUnderscore(lightSourceElement.toString(), expression.source, context, reporter, isExpression = true)
|
||||
} else if (lightSourceElement != null && (tokenType is KtDotQualifiedExpressionElementType || tokenType == KtNodeTypes.CALLABLE_REFERENCE_EXPRESSION)) {
|
||||
val children = lightSourceElement.getChildren(source.treeStructure)
|
||||
processQualifiedAccess(children.first())
|
||||
processQualifiedAccess(children.last())
|
||||
}
|
||||
}
|
||||
|
||||
val astNode = source.lighterASTNode
|
||||
val parent = source.treeStructure.getParent(astNode)
|
||||
if (parent?.tokenType !is KtDotQualifiedExpressionElementType && parent?.tokenType != KtNodeTypes.CALLABLE_REFERENCE_EXPRESSION) {
|
||||
processQualifiedAccess(astNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object FirReservedUnderscoreDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (
|
||||
declaration is FirClass<*> ||
|
||||
declaration is FirFunction<*> ||
|
||||
declaration is FirTypeParameter ||
|
||||
declaration is FirProperty ||
|
||||
declaration is FirTypeAlias
|
||||
) {
|
||||
reportIfUnderscore(declaration, context, reporter)
|
||||
|
||||
if (declaration is FirFunction<*>) {
|
||||
for (parameter in declaration.valueParameters) {
|
||||
reportIfUnderscore(
|
||||
parameter,
|
||||
context,
|
||||
reporter,
|
||||
isSingleUnderscoreAllowed = declaration is FirAnonymousFunction || declaration is FirPropertyAccessor
|
||||
)
|
||||
}
|
||||
}
|
||||
} else if (declaration is FirFile) {
|
||||
for (import in declaration.imports) {
|
||||
reportIfUnderscore(import.aliasName?.asString(), import.source, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportIfUnderscore(
|
||||
declaration: FirDeclaration,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
isSingleUnderscoreAllowed: Boolean = false
|
||||
) {
|
||||
val source = declaration.source
|
||||
val rawIdentifier = when (source) {
|
||||
is FirPsiSourceElement<*> ->
|
||||
(source.psi as? PsiNameIdentifierOwner)?.nameIdentifier?.text
|
||||
is FirLightSourceElement ->
|
||||
source.treeStructure.nameIdentifier(source.lighterASTNode)?.toString()
|
||||
else ->
|
||||
null
|
||||
}
|
||||
|
||||
reportIfUnderscore(rawIdentifier, source, context, reporter, isSingleUnderscoreAllowed)
|
||||
|
||||
val returnOrReceiverTypeRef = when (declaration) {
|
||||
is FirValueParameter -> declaration.returnTypeRef.source
|
||||
is FirFunction<*> -> declaration.receiverTypeRef?.source
|
||||
else -> null
|
||||
}
|
||||
|
||||
val isReportUnderscoreInReturnOrReceiverTypeRef = when (returnOrReceiverTypeRef) {
|
||||
is FirPsiSourceElement<*> -> {
|
||||
val psi = returnOrReceiverTypeRef.psi
|
||||
psi is KtTypeReference && psi.anyDescendantOfType<LeafPsiElement> { isUnderscore(it.text) }
|
||||
}
|
||||
is FirLightSourceElement -> {
|
||||
val lighterASTNode = returnOrReceiverTypeRef.lighterASTNode
|
||||
lighterASTNode.tokenType == KtNodeTypes.TYPE_REFERENCE &&
|
||||
source?.treeStructure?.findFirstDescendant(lighterASTNode)
|
||||
{ it.tokenType == KtNodeTypes.REFERENCE_EXPRESSION && isUnderscore(it.toString()) } != null
|
||||
}
|
||||
else -> {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
if (isReportUnderscoreInReturnOrReceiverTypeRef) {
|
||||
reporter.reportOn(returnOrReceiverTypeRef, FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS, context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportIfUnderscore(
|
||||
text: CharSequence?,
|
||||
source: FirSourceElement?,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter,
|
||||
isSingleUnderscoreAllowed: Boolean = false,
|
||||
isExpression: Boolean = false
|
||||
) {
|
||||
if (text == null || isSingleUnderscoreAllowed && text == "_") {
|
||||
return
|
||||
}
|
||||
|
||||
if (isUnderscore(text)) {
|
||||
reporter.reportOn(
|
||||
source,
|
||||
if (isExpression) FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS else FirErrors.UNDERSCORE_IS_RESERVED,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isUnderscore(text: CharSequence) = text.all { it == '_' }
|
||||
@@ -1,36 +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.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.isUnit
|
||||
|
||||
object FirStandaloneQualifierChecker : FirResolvedQualifierChecker() {
|
||||
override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val lastQualifiedAccess = context.qualifiedAccesses.lastOrNull()
|
||||
if (lastQualifiedAccess?.explicitReceiver === expression) return
|
||||
val lastGetClass = context.getClassCalls.lastOrNull()
|
||||
if (lastGetClass?.argument === expression) return
|
||||
// Note: if it's real Unit, it will be filtered by ClassKind.OBJECT check below
|
||||
if (!expression.typeRef.isUnit) return
|
||||
|
||||
when (val symbol = expression.symbol) {
|
||||
is FirRegularClassSymbol -> {
|
||||
if (symbol.fir.classKind == ClassKind.OBJECT) return
|
||||
reporter.reportOn(expression.source, FirErrors.NO_COMPANION_OBJECT, symbol, context)
|
||||
}
|
||||
null -> {
|
||||
reporter.reportOn(expression.source, FirErrors.EXPRESSION_EXPECTED_PACKAGE_FOUND, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +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.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
// See .../types/CastDiagnosticsUtil.kt for counterparts, including isRefinementUseless, isExactTypeCast, isUpcast.
|
||||
object FirUselessTypeOperationCallChecker : FirTypeOperatorCallChecker() {
|
||||
override fun check(expression: FirTypeOperatorCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (expression.operation !in FirOperation.TYPES) return
|
||||
val arg = expression.argument
|
||||
|
||||
val candidateType = arg.typeRef.coneType.upperBoundIfFlexible().fullyExpandedType(context.session)
|
||||
if (candidateType is ConeKotlinErrorType) return
|
||||
|
||||
val targetType = expression.conversionTypeRef.coneType.fullyExpandedType(context.session)
|
||||
if (targetType is ConeKotlinErrorType) return
|
||||
|
||||
// x as? Type <=> x as Type?
|
||||
val refinedTargetType =
|
||||
if (expression.operation == FirOperation.SAFE_AS) {
|
||||
targetType.withNullability(ConeNullability.NULLABLE, context.session.typeContext)
|
||||
} else {
|
||||
targetType
|
||||
}
|
||||
if (isRefinementUseless(context, candidateType, refinedTargetType, shouldCheckForExactType(expression, context))) {
|
||||
when (expression.operation) {
|
||||
FirOperation.IS -> reporter.reportOn(expression.source, FirErrors.USELESS_IS_CHECK, true, context)
|
||||
FirOperation.NOT_IS -> reporter.reportOn(expression.source, FirErrors.USELESS_IS_CHECK, false, context)
|
||||
FirOperation.AS, FirOperation.SAFE_AS -> reporter.reportOn(expression.source, FirErrors.USELESS_CAST, context)
|
||||
else -> throw AssertionError("Should not be here: ${expression.operation}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
private fun shouldCheckForExactType(expression: FirTypeOperatorCall, context: CheckerContext): Boolean {
|
||||
return when (expression.operation) {
|
||||
FirOperation.IS, FirOperation.NOT_IS -> false
|
||||
// TODO: differentiate if this expression defines the enclosing thing's type
|
||||
// e.g.,
|
||||
// val c1 get() = 1 as Number
|
||||
// val c2: Number get() = 1 <!USELESS_CAST!>as Number<!>
|
||||
FirOperation.AS, FirOperation.SAFE_AS -> true
|
||||
else -> throw AssertionError("Should not be here: ${expression.operation}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun isRefinementUseless(
|
||||
context: CheckerContext,
|
||||
candidateType: ConeKotlinType,
|
||||
targetType: ConeKotlinType,
|
||||
shouldCheckForExactType: Boolean,
|
||||
): Boolean {
|
||||
return if (shouldCheckForExactType) {
|
||||
isExactTypeCast(context, candidateType, targetType)
|
||||
} else {
|
||||
isUpcast(context, candidateType, targetType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isExactTypeCast(context: CheckerContext, candidateType: ConeKotlinType, targetType: ConeKotlinType): Boolean {
|
||||
if (!AbstractTypeChecker.equalTypes(context.session.typeContext, candidateType, targetType, stubTypesEqualToAnything = false))
|
||||
return false
|
||||
// See comments at [isUpcast] why we need to check the existence of @ExtensionFunctionType
|
||||
return candidateType.isExtensionFunctionType == targetType.isExtensionFunctionType
|
||||
}
|
||||
|
||||
private fun isUpcast(context: CheckerContext, candidateType: ConeKotlinType, targetType: ConeKotlinType): Boolean {
|
||||
if (!AbstractTypeChecker.isSubtypeOf(context.session.typeContext, candidateType, targetType, stubTypesEqualToAnything = false))
|
||||
return false
|
||||
|
||||
// E.g., foo(p1: (X) -> Y), where p1 has a functional type whose receiver type is X and return type is Y.
|
||||
// For bar(p2: X.() -> Y), p2 has the same functional type (with same receiver and return types).
|
||||
// The only difference is the existence of type annotation, @ExtensionFunctionType,
|
||||
// which indicates that the annotated type represents an extension function.
|
||||
// If one casts p1 to p2 (or vice versa), it is _not_ up cast, i.e., not redundant, yet meaningful.
|
||||
return candidateType.isExtensionFunctionType == targetType.isExtensionFunctionType
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user