PsiErrorBuilder - error reporting abstraction for JVM_IR

This commit is contained in:
Dmitry Petrov
2020-01-24 16:33:10 +03:00
parent afb2e9f38d
commit dc4d453879
5 changed files with 138 additions and 8 deletions
@@ -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()
@@ -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) }
@@ -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
@@ -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 <E : PsiElement> at(irDeclaration: IrDeclaration, psiElementClass: KClass<E>): Location<E> =
Location(
psiSourceManager.findPsiElement(irDeclaration, psiElementClass)
?: throw AssertionError("No ${psiElementClass.simpleName} found for '${irDeclaration.render()}'")
)
fun at(irDeclaration: IrDeclaration): Location<PsiElement> =
Location(
psiSourceManager.findPsiElement(irDeclaration)
?: throw AssertionError("No PsiElement found for '${irDeclaration.render()}'")
)
fun <E : PsiElement> at(irElement: IrElement, irDeclaration: IrDeclaration, psiElementClass: KClass<E>): Location<E> =
Location(
psiSourceManager.findPsiElement(irElement, irDeclaration, psiElementClass)
?: throw AssertionError("No ${psiElementClass.simpleName} found for '${irElement.render()}'")
)
fun at(irElement: IrElement, irDeclaration: IrDeclaration): Location<PsiElement> =
Location(
psiSourceManager.findPsiElement(irElement, irDeclaration)
?: throw AssertionError("No PsiElement found for '${irElement.render()}'")
)
fun <E : PsiElement> at(irElement: IrElement, irFile: IrFile, psiElementClass: KClass<E>): Location<E> =
Location(
psiSourceManager.findPsiElement(irElement, irFile, psiElementClass)
?: throw AssertionError("No ${psiElementClass.simpleName} found for '${irElement.render()}'")
)
fun at(irElement: IrElement, irFile: IrFile): Location<PsiElement> =
Location(
psiSourceManager.findPsiElement(irElement, irFile)
?: throw AssertionError("No PsiElement found for '${irElement.render()}'")
)
inner class Location<E : PsiElement>(private val psiElement: E) {
fun report(diagnosticFactory: DiagnosticFactory0<E>) {
diagnosticSink.report(diagnosticFactory.on(psiElement))
}
fun <A> report(diagnosticFactory: DiagnosticFactory1<E, A>, a: A) {
diagnosticSink.report(diagnosticFactory.on(psiElement, a))
}
fun <A, B> report(diagnosticFactory: DiagnosticFactory2<E, A, B>, a: A, b: B) {
diagnosticSink.report(diagnosticFactory.on(psiElement, a, b))
}
fun <A, B, C> report(diagnosticFactory: DiagnosticFactory3<E, A, B, C>, a: A, b: B, c: C) {
diagnosticSink.report(diagnosticFactory.on(psiElement, a, b, c))
}
}
}
@@ -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 <E : PsiElement> findPsiElement(irElement: IrElement, psiElementClass: KClass<E>): E? =
findPsiElement(irElement)?.let {
PsiTreeUtil.getParentOfType(it, psiElementClass.java, false)
}
}
private val fileEntriesByKtFile = HashMap<KtFile, PsiFileEntry>()
@@ -97,4 +117,32 @@ class PsiSourceManager : SourceManager {
override fun getFileEntry(irFile: IrFile): SourceManager.FileEntry? =
fileEntriesByIrFile[irFile]
fun <E : PsiElement> findPsiElement(irElement: IrElement, irFile: IrFile, psiElementClass: KClass<E>): 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 <E : PsiElement> findPsiElement(irElement: IrElement, irDeclaration: IrDeclaration, psiElementClass: KClass<E>): 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 <E : PsiElement> findPsiElement(irDeclaration: IrDeclaration, psiElementClass: KClass<E>): E? =
findPsiElement(irDeclaration, irDeclaration, psiElementClass)
fun findPsiElement(irDeclaration: IrDeclaration): PsiElement? =
findPsiElement(irDeclaration, irDeclaration)
}