Analysis API: extract PrettyPrinter from DebugSymbolRenderer to utils

This commit is contained in:
Ilya Kirillov
2021-11-29 15:07:29 +01:00
parent 8cb5283a7d
commit 9cb950a2ae
3 changed files with 130 additions and 68 deletions
+1
View File
@@ -15,6 +15,7 @@ dependencies {
compileOnly(project(":core:compiler.common"))
compileOnly(project(":core:compiler.common.jvm"))
compileOnly(project(":analysis:low-level-api-fir"))
implementation(project(":analysis:analysis-internal-utils"))
implementation(project(":analysis:analysis-api-providers"))
api(intellijCoreDep()) { includeJars("intellij-core", "guava", rootProject = rootProject) }
@@ -16,9 +16,10 @@ import org.jetbrains.kotlin.analysis.api.components.KtSymbolInfoProviderMixIn
import org.jetbrains.kotlin.analysis.api.symbols.markers.*
import org.jetbrains.kotlin.analysis.api.types.KtClassErrorType
import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.name.*
import java.lang.Appendable
import java.lang.reflect.InvocationTargetException
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
@@ -26,14 +27,14 @@ import kotlin.reflect.full.declaredMemberExtensionProperties
import kotlin.reflect.full.extensionReceiverParameter
public object DebugSymbolRenderer {
public fun render(symbol: KtSymbol): String = Block().apply { renderSymbol(symbol) }.toString()
public fun render(symbol: KtSymbol): String = prettyPrint { renderSymbol(symbol) }
public fun renderAnnotationApplication(application: KtAnnotationApplication): String =
Block().apply { renderAnnotationApplication(application) }.toString()
prettyPrint { renderAnnotationApplication(application) }
public fun renderType(type: KtType): String = Block().apply { renderType(type) }.toString()
public fun renderType(type: KtType): String = prettyPrint { renderType(type) }
public fun KtAnalysisSession.renderExtra(symbol: KtSymbol): String = Block().apply {
public fun KtAnalysisSession.renderExtra(symbol: KtSymbol): String = prettyPrint {
renderSymbol(symbol)
withIndent {
@@ -48,10 +49,10 @@ public object DebugSymbolRenderer {
.filter { (it.extensionReceiverParameter?.type?.classifier as? KClass<*>)?.isInstance(symbol) == true }
.forEach { renderProperty(it, this@renderExtra, symbol) }
}
}.toString()
}
public fun KtAnalysisSession.renderForSubstitutionOverrideUnwrappingTest(symbol: KtSymbol): String = Block().apply {
if (symbol !is KtCallableSymbol) return@apply
public fun KtAnalysisSession.renderForSubstitutionOverrideUnwrappingTest(symbol: KtSymbol): String = prettyPrint {
if (symbol !is KtCallableSymbol) return@prettyPrint
renderSymbolHeader(symbol)
@@ -63,14 +64,14 @@ public object DebugSymbolRenderer {
renderProperty(KtCallableSymbol::origin, symbol)
@Suppress("DEPRECATION")
(symbol as? KtPossibleMemberSymbol)?.getDispatchReceiverType()?.let { dispatchType ->
(symbol as? KtCallableSymbol)?.getDispatchReceiverType()?.let { dispatchType ->
appendLine().append("getDispatchReceiver()").append(": ")
renderType(dispatchType)
}
}
}.toString()
private fun Block.renderProperty(property: KProperty<*>, vararg args: Any) {
private fun PrettyPrinter.renderProperty(property: KProperty<*>, vararg args: Any) {
try {
appendLine().append(property.name).append(": ")
renderValue(property.getter.call(*args))
@@ -79,9 +80,8 @@ public object DebugSymbolRenderer {
}
}
private fun Block.renderSymbol(symbol: KtSymbol) {
private fun PrettyPrinter.renderSymbol(symbol: KtSymbol) {
renderSymbolHeader(symbol)
val apiClass = getSymbolApiClass(symbol)
withIndent {
apiClass.members
@@ -93,28 +93,26 @@ public object DebugSymbolRenderer {
}
}
private fun Block.renderSymbolHeader(symbol: KtSymbol) {
private fun PrettyPrinter.renderSymbolHeader(symbol: KtSymbol) {
val apiClass = getSymbolApiClass(symbol)
append(apiClass.simpleName).append(':')
}
private fun Block.renderList(values: List<*>) {
private fun PrettyPrinter.renderList(values: List<*>) {
if (values.isEmpty()) {
append("[]")
return
}
append('[')
withIndent {
withIndentInSquareBrackets {
for (value in values) {
appendLine()
renderValue(value)
}
}
appendLine().append(']')
}
private fun Block.renderSymbolTag(symbol: KtSymbol) {
private fun PrettyPrinter.renderSymbolTag(symbol: KtSymbol) {
fun renderId(id: Any?, symbol: KtSymbol) {
if (id != null) {
renderValue(id)
@@ -138,16 +136,16 @@ public object DebugSymbolRenderer {
append(")")
}
private fun Block.renderAnnotationValue(value: KtAnnotationValue) {
private fun PrettyPrinter.renderAnnotationValue(value: KtAnnotationValue) {
append(KtAnnotationValueRenderer.render(value))
}
private fun Block.renderNamedConstantValue(value: KtNamedAnnotationValue) {
private fun PrettyPrinter.renderNamedConstantValue(value: KtNamedAnnotationValue) {
append(value.name).append(" = ")
renderValue(value.expression)
}
private fun Block.renderType(type: KtType) {
private fun PrettyPrinter.renderType(type: KtType) {
if (type.annotations.isNotEmpty()) {
renderList(type.annotations)
append(' ')
@@ -158,7 +156,7 @@ public object DebugSymbolRenderer {
}
}
private fun Block.renderAnnotationApplication(call: KtAnnotationApplication) {
private fun PrettyPrinter.renderAnnotationApplication(call: KtAnnotationApplication) {
renderValue(call.classId)
append('(')
call.arguments.sortedBy { it.name }.forEachIndexed { index, value ->
@@ -175,7 +173,7 @@ public object DebugSymbolRenderer {
}
}
private fun Block.renderDeprecationInfo(info: DeprecationInfo) {
private fun PrettyPrinter.renderDeprecationInfo(info: DeprecationInfo) {
append("DeprecationInfo(")
append("deprecationLevel=${info.deprecationLevel}, ")
append("propagatesToOverrides=${info.propagatesToOverrides}, ")
@@ -183,7 +181,7 @@ public object DebugSymbolRenderer {
append(")")
}
private fun Block.renderValue(value: Any?) {
private fun PrettyPrinter.renderValue(value: Any?) {
when (value) {
// Symbol-related values
is KtSymbol -> renderSymbolTag(value)
@@ -211,7 +209,7 @@ public object DebugSymbolRenderer {
}
}
private fun Block.renderKtInitializerValue(value: KtInitializerValue) {
private fun PrettyPrinter.renderKtInitializerValue(value: KtInitializerValue) {
when (value) {
is KtConstantInitializerValue -> {
append("KtConstantInitializerValue(")
@@ -226,7 +224,7 @@ public object DebugSymbolRenderer {
}
}
private fun Block.renderAnnotationsList(value: KtAnnotationsList) {
private fun PrettyPrinter.renderAnnotationsList(value: KtAnnotationsList) {
renderList(value.annotations)
}
@@ -255,46 +253,4 @@ public object DebugSymbolRenderer {
"org.jetbrains.kotlin.analysis.api.fir",
"org.jetbrains.kotlin.analysis.api.descriptors",
)
}
private class Block : Appendable {
private val builder = StringBuilder()
private var indent = 0
override fun append(seq: CharSequence): Appendable = apply {
seq.split('\n').forEachIndexed { index, line ->
if (index > 0) {
builder.append('\n')
}
appendIndentIfNeeded()
builder.append(line)
}
}
override fun append(seq: CharSequence, start: Int, end: Int): Appendable = apply {
append(seq.subSequence(start, end))
}
override fun append(c: Char): Appendable = apply {
if (c != '\n') {
appendIndentIfNeeded()
}
builder.append(c)
}
private fun appendIndentIfNeeded() {
if (builder.isEmpty() || builder[builder.lastIndex] == '\n') {
builder.append(" ".repeat(2 * indent))
}
}
fun withIndent(block: Block.() -> Unit) {
indent += 1
block(this)
indent -= 1
}
override fun toString(): String {
return builder.toString()
}
}
@@ -0,0 +1,105 @@
/*
* Copyright 2010-2021 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.analysis.utils.printer
import java.lang.Appendable
public class PrettyPrinter(private val indentSize: Int = 2) : Appendable {
private val builder = StringBuilder()
public var indent: Int = 0
override fun append(seq: CharSequence): Appendable = apply {
seq.split('\n').forEachIndexed { index, line ->
if (index > 0) {
builder.append('\n')
}
appendIndentIfNeeded()
builder.append(line)
}
}
override fun append(seq: CharSequence, start: Int, end: Int): Appendable = apply {
append(seq.subSequence(start, end))
}
override fun append(c: Char): Appendable = apply {
if (c != '\n') {
appendIndentIfNeeded()
}
builder.append(c)
}
public inline fun withIndent(block: PrettyPrinter.() -> Unit) {
indent += 1
block(this)
indent -= 1
}
public inline fun withIndentInBraces(block: PrettyPrinter.() -> Unit) {
withIndentWrapped(before = "{", after = "}", block)
}
public inline fun withIndentInSquareBrackets(block: PrettyPrinter.() -> Unit) {
withIndentWrapped(before = "[", after = "]", block)
}
public inline fun withIndentWrapped(before: String, after: String, block: PrettyPrinter.() -> Unit) {
append(before)
appendLine()
withIndent(block)
appendLine()
append(after)
}
public inline fun <T> printCollection(
collection: Iterable<T>,
separator: String = ", ",
prefix: String = "",
postfix: String = "",
renderItem: PrettyPrinter.(T) -> Unit
) {
append(prefix)
val iterator = collection.iterator()
while (iterator.hasNext()) {
renderItem(iterator.next())
if (iterator.hasNext()) {
append(separator)
}
}
append(postfix)
}
public inline fun <T> printCollectionIfNotEmpty(
collection: Iterable<T>,
separator: String = ", ",
prefix: String = "",
postfix: String = "",
renderItem: PrettyPrinter.(T) -> Unit
) {
if (!collection.iterator().hasNext()) return
printCollection(collection, separator, prefix, postfix, renderItem)
}
public fun printCharIfNotThere(char: Char) {
if (builder.lastOrNull() != char) {
append(char)
}
}
private fun appendIndentIfNeeded() {
if (builder.isEmpty() || builder[builder.lastIndex] == '\n') {
builder.append(" ".repeat(indentSize * indent))
}
}
override fun toString(): String {
return builder.toString()
}
}
public inline fun prettyPrint(body: PrettyPrinter.() -> Unit): String =
PrettyPrinter().apply(body).toString()