diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt index 388f960cff4..a4e2a68ffca 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrUtils.kt @@ -42,7 +42,7 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Descriptor import java.io.StringWriter -fun ir2string(ir: IrElement?): String = ir2stringWhole(ir).takeWhile { it != '\n' } +fun ir2string(ir: IrElement?): String = ir?.render() ?: "" fun ir2stringWhole(ir: IrElement?, withDescriptors: Boolean = false): String { val strWriter = StringWriter() diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt index a39eb9f5604..594ff1bf6dc 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmBackendContext.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.SymbolTable import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi2ir.PsiErrorBuilder import org.jetbrains.kotlin.psi2ir.PsiSourceManager import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.org.objectweb.asm.Type @@ -66,6 +67,8 @@ class JvmBackendContext( override val declarationFactory: JvmDeclarationFactory = JvmDeclarationFactory(methodSignatureMapper) override val sharedVariablesManager = JvmSharedVariablesManager(state.module, builtIns, irBuiltIns) + val psiErrorBuilder = PsiErrorBuilder(psiSourceManager, state.diagnostics) + override val ir = JvmIr(irModuleFragment, this.symbolTable) val irIntrinsics by lazy { IrIntrinsicMethods(irBuiltIns, ir.symbols) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt index 9c6d7157ac7..77c1257cfe5 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt @@ -24,11 +24,13 @@ import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.ir.declarations.IrAttributeContainer import org.jetbrains.kotlin.ir.declarations.IrClass +import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature @@ -159,7 +161,9 @@ class IrSourceCompilerForInline( // TODO: Find a way to avoid using PSI here override fun reportSuspensionPointInsideMonitor(stackTraceElement: String) { - org.jetbrains.kotlin.codegen.coroutines.reportSuspensionPointInsideMonitor(findElement()!!, state, stackTraceElement) + codegen.context.psiErrorBuilder + .at(callElement.symbol.owner as IrDeclaration) + .report(SUSPENSION_POINT_INSIDE_MONITOR, stackTraceElement) } private fun findElement() = (callElement.symbol.descriptor.original as? DeclarationDescriptorWithSource)?.source?.getPsi() as? KtElement diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/PsiErrorBuilder.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/PsiErrorBuilder.kt new file mode 100644 index 00000000000..24578f43cc7 --- /dev/null +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/PsiErrorBuilder.kt @@ -0,0 +1,75 @@ +/* + * 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.psi2ir + +import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.diagnostics.* +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.util.render +import kotlin.reflect.KClass + +class PsiErrorBuilder( + private val psiSourceManager: PsiSourceManager, + private val diagnosticSink: DiagnosticSink +) { + + fun at(irDeclaration: IrDeclaration, psiElementClass: KClass): Location = + Location( + psiSourceManager.findPsiElement(irDeclaration, psiElementClass) + ?: throw AssertionError("No ${psiElementClass.simpleName} found for '${irDeclaration.render()}'") + ) + + fun at(irDeclaration: IrDeclaration): Location = + Location( + psiSourceManager.findPsiElement(irDeclaration) + ?: throw AssertionError("No PsiElement found for '${irDeclaration.render()}'") + ) + + fun at(irElement: IrElement, irDeclaration: IrDeclaration, psiElementClass: KClass): Location = + Location( + psiSourceManager.findPsiElement(irElement, irDeclaration, psiElementClass) + ?: throw AssertionError("No ${psiElementClass.simpleName} found for '${irElement.render()}'") + ) + + fun at(irElement: IrElement, irDeclaration: IrDeclaration): Location = + Location( + psiSourceManager.findPsiElement(irElement, irDeclaration) + ?: throw AssertionError("No PsiElement found for '${irElement.render()}'") + ) + + fun at(irElement: IrElement, irFile: IrFile, psiElementClass: KClass): Location = + Location( + psiSourceManager.findPsiElement(irElement, irFile, psiElementClass) + ?: throw AssertionError("No ${psiElementClass.simpleName} found for '${irElement.render()}'") + ) + + fun at(irElement: IrElement, irFile: IrFile): Location = + Location( + psiSourceManager.findPsiElement(irElement, irFile) + ?: throw AssertionError("No PsiElement found for '${irElement.render()}'") + ) + + inner class Location(private val psiElement: E) { + + fun report(diagnosticFactory: DiagnosticFactory0) { + diagnosticSink.report(diagnosticFactory.on(psiElement)) + } + + fun report(diagnosticFactory: DiagnosticFactory1, a: A) { + diagnosticSink.report(diagnosticFactory.on(psiElement, a)) + } + + fun report(diagnosticFactory: DiagnosticFactory2, a: A, b: B) { + diagnosticSink.report(diagnosticFactory.on(psiElement, a, b)) + } + + fun report(diagnosticFactory: DiagnosticFactory3, a: A, b: B, c: C) { + diagnosticSink.report(diagnosticFactory.on(psiElement, a, b, c)) + } + } +} \ No newline at end of file diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/PsiSourceManager.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/PsiSourceManager.kt index 16128d05ac5..bc0848bd49c 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/PsiSourceManager.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/PsiSourceManager.kt @@ -16,12 +16,21 @@ package org.jetbrains.kotlin.psi2ir +import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile +import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0 +import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.SourceManager import org.jetbrains.kotlin.ir.SourceRangeInfo +import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.util.fileOrNull import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.psiUtil.endOffset import java.util.* +import kotlin.reflect.KClass class PsiSourceManager : SourceManager { class PsiFileEntry(psiFile: PsiFile) : SourceManager.FileEntry { @@ -29,15 +38,12 @@ class PsiSourceManager : SourceManager { override val maxOffset: Int private val lineStartOffsets: IntArray + private val fileViewProvider = psiFile.viewProvider init { - val document = psiFile.viewProvider.document ?: throw AssertionError("No document for $psiFile") - + val document = fileViewProvider.document ?: throw AssertionError("No document for $psiFile") maxOffset = document.textLength - - lineStartOffsets = (0..document.lineCount - 1) - .map { document.getLineStartOffset(it) } - .toIntArray() + lineStartOffsets = IntArray(document.lineCount) { document.getLineStartOffset(it) } } override fun getLineNumber(offset: Int): Int { @@ -68,6 +74,20 @@ class PsiSourceManager : SourceManager { override val name: String get() = getRecognizableName() override fun toString(): String = getRecognizableName() + + fun findPsiElement(irElement: IrElement): PsiElement? { + var psiElement = fileViewProvider.findElementAt(irElement.startOffset) + while (psiElement != null) { + if (psiElement.endOffset == irElement.endOffset) break + psiElement = psiElement.parent + } + return psiElement + } + + fun findPsiElement(irElement: IrElement, psiElementClass: KClass): E? = + findPsiElement(irElement)?.let { + PsiTreeUtil.getParentOfType(it, psiElementClass.java, false) + } } private val fileEntriesByKtFile = HashMap() @@ -97,4 +117,32 @@ class PsiSourceManager : SourceManager { override fun getFileEntry(irFile: IrFile): SourceManager.FileEntry? = fileEntriesByIrFile[irFile] + + fun findPsiElement(irElement: IrElement, irFile: IrFile, psiElementClass: KClass): E? { + val psiFileEntry = fileEntriesByIrFile[irFile] + ?: throw AssertionError("No PSI file for irFile $irFile") + return psiFileEntry.findPsiElement(irElement, psiElementClass) + } + + fun findPsiElement(irElement: IrElement, irFile: IrFile): PsiElement? { + val psiFileEntry = fileEntriesByIrFile[irFile] + ?: throw AssertionError("No PSI file for irFile $irFile") + return psiFileEntry.findPsiElement(irElement) + } + + fun findPsiElement(irElement: IrElement, irDeclaration: IrDeclaration, psiElementClass: KClass): E? { + val irFile = irDeclaration.fileOrNull ?: return null + return findPsiElement(irElement, irFile, psiElementClass) + } + + fun findPsiElement(irElement: IrElement, irDeclaration: IrDeclaration): PsiElement? { + val irFile = irDeclaration.fileOrNull ?: return null + return findPsiElement(irElement, irFile) + } + + fun findPsiElement(irDeclaration: IrDeclaration, psiElementClass: KClass): E? = + findPsiElement(irDeclaration, irDeclaration, psiElementClass) + + fun findPsiElement(irDeclaration: IrDeclaration): PsiElement? = + findPsiElement(irDeclaration, irDeclaration) }