[klib] Fix exception for clashing signatures from different modules

If we encounter a declaration in the current module whose signature
is the same as that of a declaration in another module which we happen
to also reference from the current module, don't report any errors,
just like we don't do it in Kotlin/JVM. This leaves the user in the KLIB
hell situation, but this is intentional, because otherwise a legitimate
change like moving a declaration to another module and marking
the original one as `@Deprecated("", level = DeprecationLevel.HIDDEN)`
would lead to a error, and we don't want that.

Also, don't try to show the diagnostics on a declaration that doesn't
have an IrFile.

^KT-65063 Fixed
This commit is contained in:
Sergej Jaskiewicz
2024-01-18 15:58:50 +01:00
committed by Space Team
parent a5c8ecae0b
commit 6900e20096
8 changed files with 62 additions and 14 deletions
@@ -9,7 +9,8 @@ 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.file
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
@@ -53,17 +54,34 @@ abstract class SignatureClashDetector<Signature : Any, Declaration : IrDeclarati
}
}
protected inline fun <Data : Any, ConflictingDeclaration : IrDeclaration> reportSignatureClashTo(
protected fun <Data : Any, ConflictingDeclaration : IrDeclaration> reportSignatureClashTo(
diagnosticReporter: IrDiagnosticReporter,
diagnosticFactory: KtDiagnosticFactory1<Data>,
declarations: Collection<ConflictingDeclaration>,
data: Data,
reportOnIfSynthetic: (ConflictingDeclaration) -> IrElement,
reportOnIfSynthetic: (ConflictingDeclaration) -> IrElement?,
) {
declarations.mapTo(LinkedHashSet()) { declaration ->
val reportOn = declaration.takeUnless { it.startOffset < 0 } ?: reportOnIfSynthetic(declaration)
diagnosticReporter.at(reportOn.sourceElement(), reportOn, declaration.file)
}.forEach {
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)
}
}