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.ResolutionParameters
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.SingleCandidateResolutionMode
|
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.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.FirCallableDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
import org.jetbrains.kotlin.fir.declarations.FirVariable
|
||||||
@@ -90,7 +90,7 @@ internal class KtFirCompletionCandidateChecker(
|
|||||||
): Sequence<ImplicitReceiverValue<*>?> {
|
): Sequence<ImplicitReceiverValue<*>?> {
|
||||||
val towerDataContext = analysisSession.firResolveSession.getTowerContextProvider(originalFile)
|
val towerDataContext = analysisSession.firResolveSession.getTowerContextProvider(originalFile)
|
||||||
.getClosestAvailableParentContext(fakeNameExpression)
|
.getClosestAvailableParentContext(fakeNameExpression)
|
||||||
?: error("Cannot find enclosing declaration for ${fakeNameExpression.getElementTextInContext()}")
|
?: error("Cannot find enclosing declaration for ${fakeNameExpression.getElementTextWithContext()}")
|
||||||
|
|
||||||
return sequence {
|
return sequence {
|
||||||
yield(null) // otherwise explicit receiver won't be checked when there are no implicit receivers in completion position
|
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.LLFirResolveSession
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
|
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.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.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
@@ -194,7 +194,7 @@ internal class KtFirScopeProvider(
|
|||||||
): KtScopeContext {
|
): KtScopeContext {
|
||||||
val towerDataContext =
|
val towerDataContext =
|
||||||
analysisSession.firResolveSession.getTowerContextProvider(originalFile).getClosestAvailableParentContext(positionInFakeFile)
|
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 towerDataElementsIndexed = towerDataContext.towerDataElements.asReversed().withIndex()
|
||||||
|
|
||||||
val implicitReceivers = towerDataElementsIndexed.flatMap { (index, towerDataElement) ->
|
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.symbols.KtValueParameterSymbol
|
||||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
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.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.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
|
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression
|
||||||
@@ -39,7 +39,7 @@ internal fun FirCallableSymbol<*>.invalidModalityError(): Nothing {
|
|||||||
|
|
|
|
||||||
|$rendered
|
|$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.PsiElement
|
||||||
import com.intellij.psi.PsiInvalidElementAccessException
|
import com.intellij.psi.PsiInvalidElementAccessException
|
||||||
import org.jetbrains.kotlin.analysis.project.structure.KtModule
|
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.psi.KtElement
|
||||||
import org.jetbrains.kotlin.utils.exceptions.ExceptionAttachmentBuilder
|
import org.jetbrains.kotlin.utils.exceptions.ExceptionAttachmentBuilder
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ public fun ExceptionAttachmentBuilder.withPsiEntry(name: String, psi: PsiElement
|
|||||||
withEntry(name, psi) { psiElement ->
|
withEntry(name, psi) { psiElement ->
|
||||||
when {
|
when {
|
||||||
!psiElement.isValid -> "INVALID PSI ${PsiInvalidElementAccessException.findOutInvalidationReason(psiElement)}"
|
!psiElement.isValid -> "INVALID PSI ${PsiInvalidElementAccessException.findOutInvalidationReason(psiElement)}"
|
||||||
psiElement is KtElement -> psiElement.getElementTextInContext()
|
psiElement is KtElement -> psiElement.getElementTextWithContext()
|
||||||
else -> psiElement.text
|
else -> psiElement.text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
-26
@@ -6,11 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.analysis.utils.printer
|
package org.jetbrains.kotlin.analysis.utils.printer
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
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 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.parents
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
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)
|
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
|
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.FirElement
|
||||||
import org.jetbrains.kotlin.fir.render
|
import org.jetbrains.kotlin.fir.render
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
@@ -25,7 +25,7 @@ class DuplicatedFirSourceElementsException(
|
|||||||
| ${newFir.render().trim()}
|
| ${newFir.render().trim()}
|
||||||
|
|
|
|
||||||
|PSI element is $psi with text in context:
|
|PSI element is $psi with text in context:
|
||||||
|${psi.getElementTextInContext()}""".trimMargin()
|
|${psi.getElementTextWithContext()}""".trimMargin()
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
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.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.FileStructureElement
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.FirElementsRecorder
|
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.lazy.resolve.declarationCanBeLazilyResolved
|
||||||
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.findSourceNonLocalFirDeclaration
|
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.parentOfType
|
||||||
import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType
|
import org.jetbrains.kotlin.analysis.utils.printer.parentsOfType
|
||||||
import org.jetbrains.kotlin.fir.FirAnnotationContainer
|
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.psi
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
|
import org.jetbrains.kotlin.psi.psiUtil.isObjectLiteral
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
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
|
KtQualifiedExpression with KtCallExpression in selector transformed in FIR to FirFunctionCall expression
|
||||||
Which will have a receiver as qualifier
|
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 -> {
|
deparenthesized is KtValueArgument -> {
|
||||||
// null will be return in case of invalid 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.utils.exceptions.errorWithAttachment
|
||||||
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
|
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
|
||||||
import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry
|
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.FirElement
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
|
||||||
@@ -114,7 +114,7 @@ internal abstract class LLFirResolvableResolveSession(
|
|||||||
|
|
||||||
private fun findFirCompiledSymbol(ktDeclaration: KtDeclaration, module: KtModule): FirBasedSymbol<*> {
|
private fun findFirCompiledSymbol(ktDeclaration: KtDeclaration, module: KtModule): FirBasedSymbol<*> {
|
||||||
require(ktDeclaration.containingKtFile.isCompiled) {
|
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)
|
val session = getSessionFor(module)
|
||||||
|
|||||||
@@ -5,31 +5,51 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.utils
|
package org.jetbrains.kotlin.utils
|
||||||
|
|
||||||
import com.intellij.injected.editor.VirtualFileWindow
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.*
|
import com.intellij.psi.PsiElementVisitor
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.PsiFile
|
||||||
|
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||||
|
|
||||||
fun getElementTextWithContext(psiElement: PsiElement): String {
|
fun getElementTextWithContext(psiElement: PsiElement): String {
|
||||||
if (!psiElement.isValid) return "<invalid element $psiElement>"
|
if (!psiElement.isValid) return "<invalid element $psiElement>"
|
||||||
|
|
||||||
if (psiElement is PsiFile) {
|
@Suppress("LocalVariableName") val ELEMENT_TAG = "ELEMENT"
|
||||||
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 containingFile = psiElement.containingFile
|
||||||
val isInjected = containingFile is VirtualFileWindow
|
val context = psiElement.parentOfType("KtImportDirective")
|
||||||
return StringBuilder(topLevelElement.text)
|
?: psiElement.parentOfType("KtPackageDirective")
|
||||||
.insert(inFileParentOffset, "<caret>")
|
?: psiElement.parentOfType("KtDeclarationWithBody", "KtClassOrObject", "KtScript")
|
||||||
.insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n")
|
?: psiElement.parentOfType("KtProperty")
|
||||||
.toString()
|
?: 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