org.jetbrains.kotlin.psi.debugText.DebugTextUtil.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of kotlin-compiler-embeddable Show documentation
Show all versions of kotlin-compiler-embeddable Show documentation
the Kotlin compiler embeddable
/*
* 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.psi.debugText
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
// invoke this instead of getText() when you need debug text to identify some place in PSI without storing the element itself
// this is need to avoid unnecessary file parses
// this defaults to get text if the element is not stubbed
fun KtElement.getDebugText(): String {
if (this !is KtElementImplStub<*> || this.stub == null) {
return text
}
if (this is KtPackageDirective) {
val fqName = fqName
if (fqName.isRoot) {
return ""
}
return "package " + fqName.asString()
}
return accept(DebugTextBuildingVisitor, Unit)
}
private object DebugTextBuildingVisitor : KtVisitor() {
private val LOG = Logger.getInstance(this::class.java)
override fun visitKtFile(file: KtFile, data: Unit?): String? {
return "STUB file: ${file.name}"
}
override fun visitKtElement(element: KtElement, data: Unit?): String? {
if (element is KtElementImplStub<*>) {
LOG.error("getDebugText() is not defined for ${element::class.java}")
}
return element.text
}
override fun visitImportDirective(importDirective: KtImportDirective, data: Unit?): String? {
val importPath = importDirective.importPath ?: return "import "
val aliasStr = if (importPath.hasAlias()) " as " + importPath.alias!!.asString() else ""
return "import ${importPath.pathStr}" + aliasStr
}
override fun visitImportList(importList: KtImportList, data: Unit?): String? {
return renderChildren(importList, separator = "\n")
}
override fun visitAnnotationEntry(annotationEntry: KtAnnotationEntry, data: Unit?): String? {
return render(annotationEntry, annotationEntry.calleeExpression, annotationEntry.typeArgumentList)
}
override fun visitTypeReference(typeReference: KtTypeReference, data: Unit?): String? {
return renderChildren(typeReference, " ")
}
override fun visitTypeArgumentList(typeArgumentList: KtTypeArgumentList, data: Unit?): String? {
return renderChildren(typeArgumentList, ", ", "<", ">")
}
override fun visitTypeConstraintList(list: KtTypeConstraintList, data: Unit?): String? {
return renderChildren(list, ", ", "where ", "")
}
override fun visitUserType(userType: KtUserType, data: Unit?): String? {
return render(userType, userType.qualifier, userType.referenceExpression, userType.typeArgumentList)
}
override fun visitDynamicType(type: KtDynamicType, data: Unit?): String? {
return "dynamic"
}
override fun visitAnnotation(annotation: KtAnnotation, data: Unit?): String? {
return renderChildren(annotation, " ", "[", "]")
}
override fun visitConstructorCalleeExpression(constructorCalleeExpression: KtConstructorCalleeExpression, data: Unit?): String? {
return render(constructorCalleeExpression, constructorCalleeExpression.constructorReferenceExpression)
}
override fun visitSuperTypeListEntry(specifier: KtSuperTypeListEntry, data: Unit?): String? {
return render(specifier, specifier.typeReference)
}
override fun visitSuperTypeList(list: KtSuperTypeList, data: Unit?): String? {
return renderChildren(list, ", ")
}
override fun visitTypeParameterList(list: KtTypeParameterList, data: Unit?): String? {
return renderChildren(list, ", ", "<", ">")
}
override fun visitDotQualifiedExpression(expression: KtDotQualifiedExpression, data: Unit?): String? {
return renderChildren(expression, ".")
}
override fun visitInitializerList(list: KtInitializerList, data: Unit?): String? {
return renderChildren(list, ", ")
}
override fun visitParameterList(list: KtParameterList, data: Unit?): String? {
return renderChildren(list, ", ", "(", ")")
}
override fun visitEnumEntry(enumEntry: KtEnumEntry, data: Unit?): String? {
return buildText {
append("STUB: ")
appendInn(enumEntry.modifierList, suffix = " ")
append("enum entry ")
appendInn(enumEntry.nameAsName)
appendInn(enumEntry.initializerList, prefix = " : ")
}
}
override fun visitFunctionType(functionType: KtFunctionType, data: Unit?): String? {
return buildText {
appendInn(functionType.receiverTypeReference, suffix = ".")
appendInn(functionType.parameterList)
appendInn(functionType.returnTypeReference, prefix = " -> ")
}
}
override fun visitTypeParameter(parameter: KtTypeParameter, data: Unit?): String? {
return buildText {
appendInn(parameter.modifierList, suffix = " ")
appendInn(parameter.nameAsName)
appendInn(parameter.extendsBound, prefix = " : ")
}
}
override fun visitTypeProjection(typeProjection: KtTypeProjection, data: Unit?): String? {
return buildText {
val token = typeProjection.projectionKind.token
appendInn(token?.value)
val typeReference = typeProjection.typeReference
if (token != null && typeReference != null) {
append(" ")
}
appendInn(typeReference)
}
}
override fun visitModifierList(list: KtModifierList, data: Unit?): String? {
return buildText {
var first = true
for (modifierKeywordToken in KtTokens.MODIFIER_KEYWORDS_ARRAY) {
if (list.hasModifier(modifierKeywordToken)) {
if (!first) {
append(" ")
}
append(modifierKeywordToken.value)
first = false
}
}
}
}
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression, data: Unit?): String? {
return expression.getReferencedName()
}
override fun visitNullableType(nullableType: KtNullableType, data: Unit?): String? {
return renderChildren(nullableType, "", "", "?")
}
override fun visitAnonymousInitializer(initializer: KtAnonymousInitializer, data: Unit?): String? {
val containingDeclaration = KtStubbedPsiUtil.getContainingDeclaration(initializer)
return "initializer in " + (containingDeclaration?.getDebugText() ?: "...")
}
override fun visitClassBody(classBody: KtClassBody, data: Unit?): String? {
val containingDeclaration = KtStubbedPsiUtil.getContainingDeclaration(classBody)
return "class body for " + (containingDeclaration?.getDebugText() ?: "...")
}
override fun visitPropertyAccessor(accessor: KtPropertyAccessor, data: Unit?): String? {
val containingProperty = KtStubbedPsiUtil.getContainingDeclaration(accessor, KtProperty::class.java)
val what = (if (accessor.isGetter) "getter" else "setter")
return what + " for " + (containingProperty?.getDebugText() ?: "...")
}
override fun visitClass(klass: KtClass, data: Unit?): String? {
return buildText {
append("STUB: ")
appendInn(klass.modifierList, suffix = " ")
append("class ")
appendInn(klass.nameAsName)
appendInn(klass.typeParameterList)
appendInn(klass.primaryConstructorModifierList, prefix = " ", suffix = " ")
appendInn(klass.getPrimaryConstructorParameterList())
appendInn(klass.getSuperTypeList(), prefix = " : ")
}
}
override fun visitNamedFunction(function: KtNamedFunction, data: Unit?): String? {
return buildText {
append("STUB: ")
appendInn(function.modifierList, suffix = " ")
append("fun ")
val typeParameterList = function.typeParameterList
if (function.hasTypeParameterListBeforeFunctionName()) {
appendInn(typeParameterList, suffix = " ")
}
appendInn(function.receiverTypeReference, suffix = ".")
appendInn(function.nameAsName)
if (!function.hasTypeParameterListBeforeFunctionName()) {
appendInn(typeParameterList)
}
appendInn(function.valueParameterList)
appendInn(function.typeReference, prefix = ": ")
appendInn(function.typeConstraintList, prefix = " ")
}
}
override fun visitObjectDeclaration(declaration: KtObjectDeclaration, data: Unit?): String? {
return buildText {
append("STUB: ")
appendInn(declaration.modifierList, suffix = " ")
append("object ")
appendInn(declaration.nameAsName)
appendInn(declaration.getSuperTypeList(), prefix = " : ")
}
}
override fun visitParameter(parameter: KtParameter, data: Unit?): String? {
return buildText {
if (parameter.hasValOrVar()) {
if (parameter.isMutable) append("var ") else append("val ")
}
val name = parameter.nameAsName
appendInn(name)
val typeReference = parameter.typeReference
if (typeReference != null && name != null) {
append(": ")
}
appendInn(typeReference)
}
}
override fun visitProperty(property: KtProperty, data: Unit?): String? {
return buildText {
append("STUB: ")
appendInn(property.modifierList, suffix = " ")
append(if (property.isVar) "var " else "val ")
appendInn(property.nameAsName)
appendInn(property.typeReference, prefix = ": ")
}
}
override fun visitTypeConstraint(constraint: KtTypeConstraint, data: Unit?): String? {
return buildText {
appendInn(constraint.subjectTypeParameterName)
appendInn(constraint.boundTypeReference, prefix = " : ")
}
}
fun buildText(body: StringBuilder.() -> Unit): String? {
val sb = StringBuilder()
sb.body()
return sb.toString()
}
fun renderChildren(element: KtElementImplStub<*>, separator: String, prefix: String = "", postfix: String = ""): String? {
val childrenTexts = element.stub?.childrenStubs?.mapNotNull { (it?.psi as? KtElement)?.getDebugText() }
return childrenTexts?.joinToString(separator, prefix, postfix) ?: element.text
}
fun render(element: KtElementImplStub<*>, vararg relevantChildren: KtElement?): String? {
if (element.stub == null) return element.text
return relevantChildren.filterNotNull().joinToString("", "", "") { it.getDebugText() }
}
}
private fun StringBuilder.appendInn(target: Any?, prefix: String = "", suffix: String = "") {
if (target == null) return
append(prefix)
append(
when (target) {
is KtElement -> target.getDebugText()
else -> target.toString()
}
)
append(suffix)
}