Safe reporting PSI elements in KEWA

This commit is contained in:
Vladimir Dolzhenko
2021-09-28 22:04:06 +02:00
committed by teamcity
parent 20871dd555
commit 5dc2442872
16 changed files with 63 additions and 52 deletions
@@ -5,9 +5,11 @@
package org.jetbrains.kotlin.utils
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.Attachment
import com.intellij.openapi.diagnostic.ExceptionWithAttachments
import java.nio.charset.StandardCharsets
import com.intellij.psi.*
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@@ -38,6 +40,12 @@ open class KotlinExceptionWithAttachments : RuntimeException, ExceptionWithAttac
attachments.add(Attachment(name, content?.toString() ?: "<null>"))
return this
}
fun withPsiAttachment(name: String, element: PsiElement?): KotlinExceptionWithAttachments {
kotlin.runCatching { ApplicationManager.getApplication().runReadAction<String> { element?.let(::getElementTextWithContext) } }
.getOrNull()?.let { withAttachment(name, it) }
return this
}
}
@@ -50,4 +58,4 @@ inline fun checkWithAttachment(value: Boolean, lazyMessage: () -> String, attach
attachments(e)
throw e
}
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2022 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.utils
import com.intellij.injected.editor.VirtualFileWindow
import com.intellij.psi.*
import com.intellij.psi.util.PsiTreeUtil
fun getElementTextWithContext(psiElement: PsiElement): String {
if (!psiElement.isValid) return "<invalid element $psiElement>"
if (psiElement is PsiFile) {
return psiElement.containingFile.text
}
// Find parent for element among file children
val topLevelElement = PsiTreeUtil.findFirstParent(psiElement) { it.parent is PsiFile }
?: throw AssertionError("For non-file element we should always be able to find parent in file children")
val startContextOffset = topLevelElement.textRange.startOffset
val elementContextOffset = psiElement.textRange.startOffset
val inFileParentOffset = elementContextOffset - startContextOffset
val containingFile = psiElement.containingFile
val isInjected = containingFile is VirtualFileWindow
return StringBuilder(topLevelElement.text)
.insert(inFileParentOffset, "<caret>")
.insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n")
.toString()
}