diff --git a/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/DecompiledLightClassesFactory.kt b/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/DecompiledLightClassesFactory.kt index 36ca1de576a..5069a70a69a 100644 --- a/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/DecompiledLightClassesFactory.kt +++ b/analysis/decompiled/light-classes-for-decompiled/src/org/jetbrains/kotlin/analysis/decompiled/light/classes/DecompiledLightClassesFactory.kt @@ -57,12 +57,12 @@ object DecompiledLightClassesFactory { innerClass != null, { "Could not find corresponding inner/nested class " + relativeFqName + " in class " + decompiledClassOrObject.fqName + "\nFile: " + decompiledClassOrObject.containingKtFile.virtualFile.name }, { - it.withAttachment("decompiledClassOrObject.txt", decompiledClassOrObject.text) + it.withPsiAttachment("decompiledClassOrObject.txt", decompiledClassOrObject) it.withAttachment("fileClass.txt", decompiledClassOrObject.containingFile::class) - it.withAttachment("file.txt", decompiledClassOrObject.containingFile.text) - it.withAttachment("root.txt", rootLightClassForDecompiledFile.text) + it.withPsiAttachment("file.txt", decompiledClassOrObject.containingFile) + it.withPsiAttachment("root.txt", rootLightClassForDecompiledFile) it.withAttachment("currentName.txt", current.name) - it.withAttachment("current.txt", current.text) + it.withPsiAttachment("current.txt", current) it.withAttachment("innerClasses.txt", current.innerClasses.map { psiClass -> psiClass.name }) it.withAttachment("innerName.txt", name.asString()) }, diff --git a/analysis/light-classes-base/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt b/analysis/light-classes-base/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt index a2a3e155a37..8c7027e00fe 100644 --- a/analysis/light-classes-base/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt +++ b/analysis/light-classes-base/src/org/jetbrains/kotlin/asJava/LightClassUtil.kt @@ -156,7 +156,7 @@ object LightClassUtil { checkWithAttachment(parent.parent is KtClassOrObject, { "Bad parent: ${parent.parent?.javaClass}" }) { - it.withAttachment("parent", parent.text) + it.withPsiAttachment("parent", parent) } return (parent.parent as KtClassOrObject).toLightClass() } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CompilationException.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CompilationException.java index 2279b34d47b..7a60a7a6f9d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CompilationException.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CompilationException.java @@ -21,9 +21,7 @@ public class CompilationException extends KotlinExceptionWithAttachments { cause); this.element = element; - if (element != null) { - withAttachment("element.kt", element.getText()); - } + withPsiAttachment("element.kt", element); } @Nullable diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java index a887679d58e..180173e8941 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PackageCodegenImpl.java @@ -174,7 +174,7 @@ public class PackageCodegenImpl implements PackageCodegen { if (fragment == null) { LOG.error(new KotlinExceptionWithAttachments( "package fragment is not found for module:" + state.getModule() + " file:" + file) - .withAttachment("file.kt", file.getText())); + .withPsiAttachment("file.kt", file)); } else if (!expectedPackageFqName.equals(fragment.getFqName())) { LOG.error("expected package fq name: " + expectedPackageFqName + ", actual: " + fragment.getFqName()); } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java index ddbda0bfb41..db20578a778 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenBinding.java @@ -123,7 +123,7 @@ public class CodegenBinding { Type result = asmTypeForAnonymousClassOrNull(bindingContext, expression); if (result == null) { throw new KotlinExceptionWithAttachments("Couldn't compute ASM type for expression") - .withAttachment("expression.kt", PsiUtilsKt.getElementTextWithContext(expression)); + .withPsiAttachment("expression.kt", expression); } return result; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/idea/MainFunctionDetector.kt b/compiler/frontend/src/org/jetbrains/kotlin/idea/MainFunctionDetector.kt index 3c0eef4a88c..13e9f81f716 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/idea/MainFunctionDetector.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/idea/MainFunctionDetector.kt @@ -42,7 +42,7 @@ class MainFunctionDetector { this.getFunctionDescriptor = { function -> bindingContext.get(BindingContext.FUNCTION, function) ?: throw throw KotlinExceptionWithAttachments("No descriptor resolved for $function") - .withAttachment("function.text", function.text) + .withPsiAttachment("function.text", function) } this.languageVersionSettings = languageVersionSettings } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/bindingContextUtil/BindingContextUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/bindingContextUtil/BindingContextUtils.kt index 0c0f9be1ef0..7cb18767ccb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/bindingContextUtil/BindingContextUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/bindingContextUtil/BindingContextUtils.kt @@ -146,13 +146,13 @@ fun getEnclosingDescriptor(context: BindingContext, element: KtElement): Declara val declaration = element.getParentOfTypeCodeFragmentAware(KtNamedDeclaration::class.java) ?: throw KotlinExceptionWithAttachments("No parent KtNamedDeclaration for of type ${element.javaClass}") - .withAttachment("element.kt", element.text) + .withPsiAttachment("element.kt", element) return if (declaration is KtFunctionLiteral) { getEnclosingDescriptor(context, declaration) } else { context.get(DECLARATION_TO_DESCRIPTOR, declaration) ?: throw KotlinExceptionWithAttachments("No descriptor for named declaration of type ${declaration.javaClass}") - .withAttachment("declaration.kt", declaration.text) + .withPsiAttachment("declaration.kt", declaration) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index 08b745d7124..3f027f63d00 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -626,8 +626,8 @@ class PSICallResolver( } if (allValueArguments.isEmpty()) { throw KotlinExceptionWithAttachments("Can not find an external argument for 'set' method") - .withAttachment("callElement.kt", oldCall.callElement.text) - .withAttachment("file.kt", oldCall.callElement.takeIf { it.isValid }?.containingFile?.text ?: "") + .withPsiAttachment("callElement.kt", oldCall.callElement) + .withPsiAttachment("file.kt", oldCall.callElement.takeIf { it.isValid }?.containingFile) } allValueArguments.last() } else { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/AbsentDescriptorHandler.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/AbsentDescriptorHandler.kt index a646a0a9335..7b6437cfb25 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/AbsentDescriptorHandler.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/AbsentDescriptorHandler.kt @@ -24,6 +24,6 @@ class NoDescriptorForDeclarationException @JvmOverloads constructor(declaration: + (additionalDetails?.let { "\n---------------------------------------------------\n$it" } ?: "") ) { init { - withAttachment("declaration.kt", declaration.getElementTextWithContext()) + withPsiAttachment("declaration.kt", declaration) } } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorDispatcher.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorDispatcher.java index 6a809208fef..e323ddcb2b6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorDispatcher.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingVisitorDispatcher.java @@ -252,7 +252,7 @@ public abstract class ExpressionTypingVisitorDispatcher extends KtVisitor" - - if (this is PsiFile) { - return containingFile.text - } - - // Find parent for element among file children - val topLevelElement = PsiTreeUtil.findFirstParent(this, { it.parent is PsiFile }) - ?: throw AssertionError("For non-file element we should always be able to find parent in file children") - - val startContextOffset = topLevelElement.startOffset - val elementContextOffset = textRange.startOffset - - val inFileParentOffset = elementContextOffset - startContextOffset - - - val isInjected = containingFile is VirtualFileWindow - return StringBuilder(topLevelElement.text) - .insert(inFileParentOffset, "") - .insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n") - .toString() -} +fun PsiElement.getElementTextWithContext(): String = org.jetbrains.kotlin.utils.getElementTextWithContext(this) fun PsiElement.getTextWithLocation(): String = "'${this.text}' at ${PsiDiagnosticUtils.atLocation(this)}" diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt index 9f4a0ea1a5a..6db3c0b66d9 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinExceptionWithAttachments.kt @@ -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() ?: "")) return this } + + fun withPsiAttachment(name: String, element: PsiElement?): KotlinExceptionWithAttachments { + kotlin.runCatching { ApplicationManager.getApplication().runReadAction { 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 } -} +} \ No newline at end of file diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/psiUtils.kt b/compiler/util/src/org/jetbrains/kotlin/utils/psiUtils.kt new file mode 100644 index 00000000000..7bf3e21ab2a --- /dev/null +++ b/compiler/util/src/org/jetbrains/kotlin/utils/psiUtils.kt @@ -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 "" + + 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, "") + .insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n") + .toString() +} \ No newline at end of file