Move PsiElement.getElementTextWithContext to psi module with small adjustments
* replace existing function (the new one makes it more clear which element was printed) * prints position for element * handles invalid psi element
This commit is contained in:
committed by
Space Team
parent
4b3bff3344
commit
c5014d4765
+2
-2
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirOfType
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.ResolutionParameters
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.SingleCandidateResolutionMode
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.SingleCandidateResolver
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||
@@ -90,7 +90,7 @@ internal class KtFirCompletionCandidateChecker(
|
||||
): Sequence<ImplicitReceiverValue<*>?> {
|
||||
val towerDataContext = analysisSession.firResolveSession.getTowerContextProvider(originalFile)
|
||||
.getClosestAvailableParentContext(fakeNameExpression)
|
||||
?: error("Cannot find enclosing declaration for ${fakeNameExpression.getElementTextInContext()}")
|
||||
?: error("Cannot find enclosing declaration for ${fakeNameExpression.getElementTextWithContext()}")
|
||||
|
||||
return sequence {
|
||||
yield(null) // otherwise explicit receiver won't be checked when there are no implicit receivers in completion position
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
|
||||
import org.jetbrains.kotlin.analysis.utils.errors.unexpectedElementError
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
@@ -194,7 +194,7 @@ internal class KtFirScopeProvider(
|
||||
): KtScopeContext {
|
||||
val towerDataContext =
|
||||
analysisSession.firResolveSession.getTowerContextProvider(originalFile).getClosestAvailableParentContext(positionInFakeFile)
|
||||
?: error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextInContext()}")
|
||||
?: error("Cannot find enclosing declaration for ${positionInFakeFile.getElementTextWithContext()}")
|
||||
val towerDataElementsIndexed = towerDataContext.towerDataElements.asReversed().withIndex()
|
||||
|
||||
val implicitReceivers = towerDataElementsIndexed.flatMap { (index, towerDataElement) ->
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.analysis.api.impl.base.KtContextReceiverImpl
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
|
||||
@@ -39,7 +39,7 @@ internal fun FirCallableSymbol<*>.invalidModalityError(): Nothing {
|
||||
|
|
||||
|$rendered
|
||||
|
|
||||
|${(fir.psi as? KtDeclaration)?.getElementTextInContext()}""".trimMargin()
|
||||
|${(fir.psi as? KtDeclaration)?.getElementTextWithContext()}""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.analysis.utils.errors
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiInvalidElementAccessException
|
||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.utils.exceptions.ExceptionAttachmentBuilder
|
||||
|
||||
@@ -20,7 +20,7 @@ public fun ExceptionAttachmentBuilder.withPsiEntry(name: String, psi: PsiElement
|
||||
withEntry(name, psi) { psiElement ->
|
||||
when {
|
||||
!psiElement.isValid -> "INVALID PSI ${PsiInvalidElementAccessException.findOutInvalidationReason(psiElement)}"
|
||||
psiElement is KtElement -> psiElement.getElementTextInContext()
|
||||
psiElement is KtElement -> psiElement.getElementTextWithContext()
|
||||
else -> psiElement.text
|
||||
}
|
||||
}
|
||||
|
||||
-26
@@ -6,11 +6,7 @@
|
||||
package org.jetbrains.kotlin.analysis.utils.printer
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
|
||||
@@ -26,25 +22,3 @@ public inline fun <reified T : PsiElement> PsiElement.parentsOfType(withSelf: Bo
|
||||
parentsOfType(T::class.java, withSelf)
|
||||
|
||||
|
||||
public fun KtElement.getElementTextInContext(): String {
|
||||
@Suppress("LocalVariableName") val ELEMENT_TAG = "ELEMENT"
|
||||
val context = parentOfType<KtImportDirective>()
|
||||
?: parentOfType<KtPackageDirective>()
|
||||
?: PsiTreeUtil.getParentOfType(this, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtScript::class.java)
|
||||
?: getNonStrictParentOfType<KtProperty>()
|
||||
?: 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("</$ELEMENT_TAG>")
|
||||
}
|
||||
})
|
||||
return builder.toString().trimIndent().trim()
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder
|
||||
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.render
|
||||
import org.jetbrains.kotlin.psi.KtElement
|
||||
@@ -25,7 +25,7 @@ class DuplicatedFirSourceElementsException(
|
||||
| ${newFir.render().trim()}
|
||||
|
|
||||
|PSI element is $psi with text in context:
|
||||
|${psi.getElementTextInContext()}""".trimMargin()
|
||||
|${psi.getElementTextWithContext()}""".trimMargin()
|
||||
|
||||
|
||||
companion object {
|
||||
|
||||
+2
-4
@@ -12,10 +12,9 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirModuleResolveCompone
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FileStructureElement
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FirElementsRecorder
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.lazy.resolve.declarationCanBeLazilyResolved
|
||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.parentOfType
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType
|
||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
||||
@@ -34,7 +33,6 @@ import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.psi
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
@@ -53,7 +51,7 @@ internal class FirElementBuilder(
|
||||
KtQualifiedExpression with KtCallExpression in selector transformed in FIR to FirFunctionCall expression
|
||||
Which will have a receiver as qualifier
|
||||
*/
|
||||
deparenthesized.selectorExpression ?: error("Incomplete code:\n${element.getElementTextInContext()}")
|
||||
deparenthesized.selectorExpression ?: error("Incomplete code:\n${element.getElementTextWithContext()}")
|
||||
}
|
||||
deparenthesized is KtValueArgument -> {
|
||||
// null will be return in case of invalid KtValueArgument
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
||||
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
|
||||
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
|
||||
import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.getElementTextInContext
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||
@@ -114,7 +114,7 @@ internal abstract class LLFirResolvableResolveSession(
|
||||
|
||||
private fun findFirCompiledSymbol(ktDeclaration: KtDeclaration, module: KtModule): FirBasedSymbol<*> {
|
||||
require(ktDeclaration.containingKtFile.isCompiled) {
|
||||
"This method will only work on compiled declarations, but this declaration is not compiled: ${ktDeclaration.getElementTextInContext()}"
|
||||
"This method will only work on compiled declarations, but this declaration is not compiled: ${ktDeclaration.getElementTextWithContext()}"
|
||||
}
|
||||
|
||||
val session = getSessionFor(module)
|
||||
|
||||
@@ -5,31 +5,51 @@
|
||||
|
||||
package org.jetbrains.kotlin.utils
|
||||
|
||||
import com.intellij.injected.editor.VirtualFileWindow
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
|
||||
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
|
||||
|
||||
|
||||
@Suppress("LocalVariableName") val ELEMENT_TAG = "ELEMENT"
|
||||
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()
|
||||
val context = psiElement.parentOfType("KtImportDirective")
|
||||
?: psiElement.parentOfType("KtPackageDirective")
|
||||
?: psiElement.parentOfType("KtDeclarationWithBody", "KtClassOrObject", "KtScript")
|
||||
?: psiElement.parentOfType("KtProperty")
|
||||
?: containingFile
|
||||
val elementTextInContext = buildString {
|
||||
context.accept(object : PsiElementVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
if (element === psiElement) append("<$ELEMENT_TAG>")
|
||||
if (element is LeafPsiElement) {
|
||||
append(element.text)
|
||||
} else {
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
if (element === psiElement) append("</$ELEMENT_TAG>")
|
||||
}
|
||||
})
|
||||
}.trimIndent().trim()
|
||||
|
||||
return buildString {
|
||||
appendLine("<File name: ${containingFile.name}, Physical: ${containingFile.isPhysical}>")
|
||||
append(elementTextInContext)
|
||||
}
|
||||
}
|
||||
|
||||
private fun PsiElement.parentOfType(vararg psiClassNames: String): PsiElement? {
|
||||
fun acceptsClass(javaClass: Class<*>): Boolean {
|
||||
if (javaClass.simpleName in psiClassNames) return true
|
||||
javaClass.superclass?.let { if (acceptsClass(it)) return true }
|
||||
for (superInterface in javaClass.interfaces) {
|
||||
if (acceptsClass(superInterface)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
return generateSequence(this) { it.parent }
|
||||
.filter { it !is PsiFile }
|
||||
.firstOrNull { acceptsClass(it::class.java) }
|
||||
}
|
||||
Reference in New Issue
Block a user