From 9cf4fdfb71c05bc5c7c16a009387d9a29e8559b8 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Mon, 6 Jul 2020 23:40:28 +0300 Subject: [PATCH] FIR IDE: add reference info on reference resolve --- .../low/level/api/FirModuleResolveState.kt | 21 +---------- .../idea/references/KtFirReferenceResolver.kt | 18 +++++++-- .../org/jetbrains/kotlin/idea/util/utils.kt | 37 +++++++++++++++++++ 3 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/utils.kt diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveState.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveState.kt index 81211db1331..63fe005029f 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveState.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/FirModuleResolveState.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.project.LibrarySourceInfo import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo import org.jetbrains.kotlin.idea.caches.project.getModuleInfo +import org.jetbrains.kotlin.idea.util.getElementTextInContext import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtTypeReference @@ -166,28 +167,10 @@ class DuplicatedFirSourceElementsException( | ${newFir.render().trim()} | |PSI element is $psi with text in context: - |${getElementInContext(psi)}""".trimMargin() + |${psi.getElementTextInContext()}""".trimMargin() - private fun getElementInContext(neededElement: KtElement): String { - val context = neededElement.containingDeclarationForPseudocode ?: neededElement.containingKtFile - val builder = StringBuilder() - context.accept(object : PsiElementVisitor() { - override fun visitElement(element: PsiElement) { - if (element === neededElement) builder.append("<$ELEMENT_TAG>") - if (element is LeafPsiElement) { - builder.append(element.text) - } else { - element.acceptChildren(this) - } - if (element === neededElement) builder.append("") - } - }) - return builder.toString().trimIndent().trim() - } companion object { - private const val ELEMENT_TAG = "ELEMENT" - // The are some cases which are still generates FIR elements with duplicated source elements // Then such case is met, it's better to be fixed // but exception reporting can be easily disabled by setting this to false diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/KtFirReferenceResolver.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/KtFirReferenceResolver.kt index 5479f32c156..259d136adae 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/KtFirReferenceResolver.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/references/KtFirReferenceResolver.kt @@ -6,14 +6,14 @@ package org.jetbrains.kotlin.idea.references import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.diagnostic.ControlFlowException import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.psi.PsiElement import com.intellij.psi.PsiElementResolveResult import com.intellij.psi.ResolveResult import com.intellij.psi.impl.source.resolve.ResolveCache import org.jetbrains.kotlin.idea.frontend.api.analyze -import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession -import org.jetbrains.kotlin.idea.frontend.api.getAnalysisSessionFor +import org.jetbrains.kotlin.idea.util.getElementTextInContext object KtFirReferenceResolver : ResolveCache.PolyVariantResolver { class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element) @@ -24,7 +24,17 @@ object KtFirReferenceResolver : ResolveCache.PolyVariantResolver { if (ApplicationManager.getApplication().isDispatchThread) { throw ProcessCanceledException() } - val resolveToPsiElements = analyze(ref.expression) { ref.getResolvedToPsi(this) } + val resolveToPsiElements = try { + analyze(ref.expression) { ref.getResolvedToPsi(this) } + } catch (e: Throwable) { + if (e is ControlFlowException) throw e + throw KtReferenceResolveException(ref, e) + } return resolveToPsiElements.map { KotlinResolveResult(it) }.toTypedArray() } -} \ No newline at end of file +} + +class KtReferenceResolveException( + reference: KtReference, + cause: Throwable +) : RuntimeException("Reference is:\n${reference.element.getElementTextInContext()}", cause) \ No newline at end of file diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/utils.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/utils.kt new file mode 100644 index 00000000000..a8dcb6d678e --- /dev/null +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/util/utils.kt @@ -0,0 +1,37 @@ +/* + * 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.idea.util + +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.impl.source.tree.LeafPsiElement +import com.intellij.psi.util.parentOfType +import org.jetbrains.kotlin.cfg.pseudocode.containingDeclarationForPseudocode +import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtImportDirective +import org.jetbrains.kotlin.psi.KtPackageDirective + +fun KtElement.getElementTextInContext(): String { + val context = parentOfType() + ?: parentOfType() + ?: containingDeclarationForPseudocode + ?: containingKtFile + val builder = StringBuilder() + context.accept(object : PsiElementVisitor() { + override fun visitElement(element: PsiElement) { + if (element === this@getElementTextInContext) builder.append("<$ELEMENT_TAG>") + if (element is LeafPsiElement) { + builder.append(element.text) + } else { + element.acceptChildren(this) + } + if (element === this@getElementTextInContext) builder.append("") + } + }) + return builder.toString().trimIndent().trim() +} +private const val ELEMENT_TAG = "ELEMENT" +