From eec511a7670c73e90d6bbf9baf37dbf45c423e94 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Mon, 17 Oct 2022 20:52:28 +0200 Subject: [PATCH] [PL] Fix line/column numbers in error messages --- .../kotlin/backend/wasm/WasmBackendContext.kt | 24 +++++----- .../org/jetbrains/kotlin/ir/IrFileEntry.kt | 2 + .../org/jetbrains/kotlin/ir/PsiIrFileEntry.kt | 6 +-- .../kotlin/ir/util/AdditionalIrUtils.kt | 6 +-- .../unlinked/UnlinkedDeclarationsProcessor.kt | 46 +++++++++++++++---- 5 files changed, 56 insertions(+), 28 deletions(-) diff --git a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt index 439f7375510..ecf17c4984c 100644 --- a/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt +++ b/compiler/ir/backend.wasm/src/org/jetbrains/kotlin/backend/wasm/WasmBackendContext.kt @@ -86,15 +86,15 @@ class WasmBackendContext( SourceRangeInfo( "", UNDEFINED_OFFSET, + UNDEFINED_LINE_NUMBER, + UNDEFINED_COLUMN_NUMBER, UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - UNDEFINED_OFFSET + UNDEFINED_LINE_NUMBER, + UNDEFINED_COLUMN_NUMBER ) - override fun getLineNumber(offset: Int) = UNDEFINED_OFFSET - override fun getColumnNumber(offset: Int) = UNDEFINED_OFFSET + override fun getLineNumber(offset: Int) = UNDEFINED_LINE_NUMBER + override fun getColumnNumber(offset: Int) = UNDEFINED_COLUMN_NUMBER }, internalPackageFragmentDescriptor, irModuleFragment).also { irModuleFragment.files += it } @@ -158,15 +158,15 @@ class WasmBackendContext( SourceRangeInfo( "", UNDEFINED_OFFSET, + UNDEFINED_LINE_NUMBER, + UNDEFINED_COLUMN_NUMBER, UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - UNDEFINED_OFFSET, - UNDEFINED_OFFSET + UNDEFINED_LINE_NUMBER, + UNDEFINED_COLUMN_NUMBER ) - override fun getLineNumber(offset: Int) = UNDEFINED_OFFSET - override fun getColumnNumber(offset: Int) = UNDEFINED_OFFSET + override fun getLineNumber(offset: Int) = UNDEFINED_LINE_NUMBER + override fun getColumnNumber(offset: Int) = UNDEFINED_COLUMN_NUMBER }, internalPackageFragmentDescriptor, module).also { module.files += it } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrFileEntry.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrFileEntry.kt index d8a86433102..6e74083ab3f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrFileEntry.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/IrFileEntry.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.ir const val UNDEFINED_OFFSET: Int = -1 +const val UNDEFINED_LINE_NUMBER: Int = UNDEFINED_OFFSET +const val UNDEFINED_COLUMN_NUMBER: Int = UNDEFINED_OFFSET data class SourceRangeInfo( val filePath: String, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/PsiIrFileEntry.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/PsiIrFileEntry.kt index 3b1b00556d1..a6922c63513 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/PsiIrFileEntry.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/PsiIrFileEntry.kt @@ -24,15 +24,15 @@ class PsiIrFileEntry(val psiFile: PsiFile) : IrFileEntry { } override fun getLineNumber(offset: Int): Int { - if (offset < 0) return -1 + if (offset < 0) return UNDEFINED_LINE_NUMBER val index = lineStartOffsets.binarySearch(offset) return if (index >= 0) index else -index - 2 } override fun getColumnNumber(offset: Int): Int { - if (offset < 0) return -1 + if (offset < 0) return UNDEFINED_COLUMN_NUMBER val lineNumber = getLineNumber(offset) - if (lineNumber < 0) return -1 + if (lineNumber < 0) return UNDEFINED_COLUMN_NUMBER return offset - lineStartOffsets[lineNumber] } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt index 971d78dad32..3e1909e0599 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/AdditionalIrUtils.kt @@ -227,15 +227,15 @@ class NaiveSourceBasedFileEntryImpl( override fun getLineNumber(offset: Int): Int { if (offset == SYNTHETIC_OFFSET) return 0 - if (offset < 0) return -1 + if (offset < 0) return UNDEFINED_LINE_NUMBER return synchronized(lineNumberLock) { calculatedBeforeLineNumbers.get(offset) } } override fun getColumnNumber(offset: Int): Int { if (offset == SYNTHETIC_OFFSET) return 0 - if (offset < 0) return -1 + if (offset < 0) return UNDEFINED_COLUMN_NUMBER val lineNumber = getLineNumber(offset) - return if (lineNumber < 0) -1 else offset - lineStartOffsets[lineNumber] + return if (lineNumber < 0) UNDEFINED_COLUMN_NUMBER else offset - lineStartOffsets[lineNumber] } override fun getSourceRangeInfo(beginOffset: Int, endOffset: Int): SourceRangeInfo = diff --git a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsProcessor.kt b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsProcessor.kt index 2d5354c98d8..49dc8bccb50 100644 --- a/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsProcessor.kt +++ b/compiler/ir/serialization.common/src/org/jetbrains/kotlin/backend/common/serialization/unlinked/UnlinkedDeclarationsProcessor.kt @@ -6,13 +6,12 @@ package org.jetbrains.kotlin.backend.common.serialization.unlinked import org.jetbrains.kotlin.backend.common.serialization.unlinked.PartialLinkageSupport.UnlinkedMarkerTypeHandler +import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedDeclarationsProcessor.Companion.MISSING_ABSTRACT_CALLABLE_MEMBER_IMPLEMENTATION import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedIrElementRenderer.appendDeclaration import org.jetbrains.kotlin.backend.common.serialization.unlinked.UnlinkedIrElementRenderer.renderError import org.jetbrains.kotlin.backend.common.serialization.unlinked.UsedClassifierSymbolStatus.Companion.isUnlinked import org.jetbrains.kotlin.descriptors.DescriptorVisibilities -import org.jetbrains.kotlin.ir.IrBuiltIns -import org.jetbrains.kotlin.ir.IrElement -import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.* import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl @@ -348,12 +347,39 @@ private fun IrDeclaration.location(): Location? = locationIn(fileOrNull) private fun IrElement.locationIn(currentFile: IrFile?): Location? { if (currentFile == null) return null - val moduleName = currentFile.module.name - val fileEntry = currentFile.fileEntry - val fileName = fileEntry.name - val lineNumber = fileEntry.getLineNumber(startOffset) + 1 // since humans count from 1, not 0 - val columnNumber = fileEntry.getColumnNumber(startOffset) + 1 + val moduleName: String = currentFile.module.name.asString() + val filePath: String = currentFile.fileEntry.name - // unsure whether should module name be added here - return Location("$moduleName @ $fileName", lineNumber, columnNumber) + val lineNumber: Int + val columnNumber: Int + + when (val effectiveStartOffset = startOffsetOfFirstNonSyntheticIrElement()) { + UNDEFINED_OFFSET -> { + lineNumber = UNDEFINED_LINE_NUMBER + columnNumber = UNDEFINED_COLUMN_NUMBER + } + else -> { + lineNumber = currentFile.fileEntry.getLineNumber(effectiveStartOffset) + 1 // since humans count from 1, not 0 + columnNumber = currentFile.fileEntry.getColumnNumber(effectiveStartOffset) + 1 + } + } + + // TODO: should module name still be added here? + return Location("$moduleName @ $filePath", lineNumber, columnNumber) +} + +private tailrec fun IrElement.startOffsetOfFirstNonSyntheticIrElement(): Int = when (this) { + is IrPackageFragment -> UNDEFINED_OFFSET + !is IrDeclaration -> { + // We don't generate synthetic IR expressions in the course of partial linkage. + startOffset + } + else -> when (origin) { + MISSING_ABSTRACT_CALLABLE_MEMBER_IMPLEMENTATION -> { + // There is no sense to take coordinates from the declaration that does not exist in the code. + // Let's take the coordinates of the parent. + parent.startOffsetOfFirstNonSyntheticIrElement() + } + else -> startOffset + } }