org.jetbrains.kotlin.ir.linkage.SignatureClashDetector.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* Copyright 2010-2023 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.ir.linkage
import org.jetbrains.kotlin.diagnostics.KtDiagnosticFactory1
import org.jetbrains.kotlin.ir.IrDiagnosticReporter
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.util.fileOrNull
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.util.sourceElement
import org.jetbrains.kotlin.utils.SmartSet
/**
* Collects the information about declarations and their signatures and reports cases when multiple declarations have the same signature.
*/
abstract class SignatureClashDetector {
private val declarationsBySignature: HashMap> = LinkedHashMap()
/**
* Returns all the declarations that have [signature] previously recorded by [trackDeclaration].
*/
protected fun declarationsWithSignature(signature: Signature): Set =
declarationsBySignature[signature] ?: emptySet()
/**
* Records the declaration, so it could later participate in signature clash detection.
*/
fun trackDeclaration(declaration: Declaration, rawSignature: Signature) {
declarationsBySignature.computeIfAbsent(rawSignature) { SmartSet.create() }.add(declaration)
}
/**
* Invoked by [reportErrorsTo] whenever at least two declarations with the same [signature] are detected.
*
* Use [reportSignatureClashTo] in the implementation to report a diagnostic.
*/
protected abstract fun reportSignatureConflict(
signature: Signature,
declarations: Collection,
diagnosticReporter: IrDiagnosticReporter,
)
/**
* Reports all detected signature clashes.
*/
open fun reportErrorsTo(diagnosticReporter: IrDiagnosticReporter) {
for ((signature, declarations) in declarationsBySignature) {
if (declarations.size <= 1) continue
reportSignatureConflict(signature, declarations, diagnosticReporter)
}
}
protected fun reportSignatureClashTo(
diagnosticReporter: IrDiagnosticReporter,
diagnosticFactory: KtDiagnosticFactory1,
declarations: Collection,
data: Data,
reportOnIfSynthetic: (ConflictingDeclaration) -> IrElement?,
) {
val diagnostics = declarations.mapNotNullTo(LinkedHashSet()) { declaration ->
// Declarations that come from other modules may not have a file, so we don't show diagnostics on them.
val containingFile = declaration.fileOrNull ?: return@mapNotNullTo null
val reportOn = declaration.takeUnless { it.startOffset < 0 } ?: reportOnIfSynthetic(declaration) ?: return@mapNotNullTo null
diagnosticReporter.at(reportOn.sourceElement(), reportOn, containingFile)
}
assert(diagnostics.isEmpty() == declarations.isEmpty()) {
buildString {
append("Different declarations with the same signatures were detected, but no diagnostics will be reported ")
append("because none of those declarations have any source location info associated with them. ")
append("This could happen because the declarations came from an external module, or were generated by a compiler plugin. ")
appendLine("The following declarations have conflicting signatures:")
for (declaration in declarations) {
append(" - ")
appendLine(declaration.render())
}
}
}
diagnostics.forEach {
it.report(diagnosticFactory, data)
}
}
}