Compare commits

..

3 Commits

Author SHA1 Message Date
Dmitry Petrov
ef461d4a3a JVM_IR KT-36646 fuze primitive equality with safe call 2021-04-27 16:22:53 +03:00
Dmitry Petrov
eaf870bfd4 JVM_IR update test for KT-36637 2021-04-27 16:22:52 +03:00
Dmitry Petrov
e8982765c8 JVM_IR use static 'hashCode' for boxed primitives on JVM 1.8+ 2021-04-27 16:22:52 +03:00
1998 changed files with 10480 additions and 71199 deletions

View File

@@ -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

View File

@@ -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",

View File

@@ -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")}")

View File

@@ -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")
}
}

View File

@@ -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) {

View File

@@ -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()
}
}

View 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"))
}
}
}
}

View File

@@ -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

View File

@@ -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() -> {

View File

@@ -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());
}
}
}

View File

@@ -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> {

View File

@@ -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)

View File

@@ -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))

View File

@@ -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)
}

View File

@@ -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> {

View File

@@ -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)
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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))

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View 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
}
}

View File

@@ -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)

View File

@@ -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");

View File

@@ -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>#()
}

View File

@@ -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)
}

View File

@@ -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
}
}

View File

@@ -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|>()

View File

@@ -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'))
}
)

View File

@@ -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|>()

View File

@@ -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| {

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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|)
}

View File

@@ -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| {
}

View File

@@ -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>#()
}

View File

@@ -4,7 +4,7 @@ class Factory {
}
companion object {
val f = <!NO_COMPANION_OBJECT!>Function<!>
val f = Function
val x = Function.Default
}
}

View File

@@ -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>#
}

View File

@@ -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>#
}

View File

@@ -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

View File

@@ -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|

View File

@@ -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|

View File

@@ -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|
}

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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|()

View File

@@ -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() {

View File

@@ -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>#()
}
}

View File

@@ -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>#()
}

View File

@@ -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>#()
}

View File

@@ -1,4 +1,3 @@
// FIR_IDE_IGNORE
// FILE: foo/Some.java
package foo;

View File

@@ -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|!!
}
}

View File

@@ -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!!
}

View File

@@ -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| {

View File

@@ -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>#
}

View File

@@ -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>#
}
}

View File

@@ -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 }
}

View File

@@ -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
}
}

View File

@@ -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|

View File

@@ -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|

View File

@@ -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>#()
}
}

View File

@@ -1,4 +1,3 @@
// FIR_IDE_IGNORE
// FILE: K1.kt
class KSub : J1()

View File

@@ -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?>|

View File

@@ -1,4 +1,3 @@
// FIR_IDE_IGNORE
// FILE: K1.kt
class K2: J1() {
class Q : <!UNRESOLVED_REFERENCE!>Nested<!>()

View File

@@ -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
}
}
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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}")

View File

@@ -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"

View File

@@ -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,
;

View File

@@ -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 = {

View File

@@ -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

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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>

View File

@@ -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
}
}

View File

@@ -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)
}

View File

@@ -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
}
}

View 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)
}

View File

@@ -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.

View File

@@ -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
}

View File

@@ -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) }
}
}
}

View File

@@ -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

View File

@@ -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
)
}
}
}

View File

@@ -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)
}
}
}
}

View File

@@ -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
)
}
}
}
}

View File

@@ -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
}
}
}

View File

@@ -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

View File

@@ -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)
}
}
}

View File

@@ -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) {

View File

@@ -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
)
}
}
}

View File

@@ -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)
}
}
}

View File

@@ -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
}
}

View File

@@ -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 == '_' }

View File

@@ -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)
}
}
}
}

View File

@@ -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