Analysis API: rework declaration renderer
- refactor code to use PrettyPrinter instead of ad-hoc one - do not print nested local declarations as this does not seem to have use-cases
This commit is contained in:
@@ -8,6 +8,7 @@ dependencies {
|
||||
implementation(project(":compiler:frontend"))
|
||||
implementation(project(":compiler:frontend.java"))
|
||||
implementation(project(":analysis:analysis-api-impl-base"))
|
||||
implementation(project(":analysis:analysis-internal-utils"))
|
||||
|
||||
implementation(project(":compiler:backend"))
|
||||
implementation(project(":compiler:backend.jvm"))
|
||||
|
||||
+4
-4
@@ -15,8 +15,10 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.bas
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.types.base.KtFe10Type
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.utils.KtFe10TypeRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint
|
||||
|
||||
internal class KtFe10SymbolDeclarationRendererProvider(
|
||||
override val analysisSession: KtFe10AnalysisSession
|
||||
@@ -24,7 +26,7 @@ internal class KtFe10SymbolDeclarationRendererProvider(
|
||||
override val token: ValidityToken
|
||||
get() = analysisSession.token
|
||||
|
||||
override fun render(symbol: KtSymbol, options: KtDeclarationRendererOptions): String {
|
||||
override fun renderMember(symbol: KtPossibleMemberSymbol, options: KtDeclarationRendererOptions): String {
|
||||
val descriptor = getSymbolDescriptor(symbol)
|
||||
if (descriptor != null) {
|
||||
return descriptor.render(analysisContext, options)
|
||||
@@ -36,8 +38,6 @@ internal class KtFe10SymbolDeclarationRendererProvider(
|
||||
|
||||
override fun render(type: KtType, options: KtTypeRendererOptions): String {
|
||||
require(type is KtFe10Type)
|
||||
val consumer = StringBuilder()
|
||||
KtFe10TypeRenderer(options).render(type.type, consumer)
|
||||
return consumer.toString()
|
||||
return prettyPrint { KtFe10TypeRenderer(options).render(type.type, this) }
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -15,10 +15,12 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.*
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.psiBased.base.KtFe10PsiSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.types.*
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.utils.KtFe10Renderer
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.utils.KtFe10TypeRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.*
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.*
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtTypeNullability
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
@@ -308,7 +310,7 @@ internal fun ConstantValue<*>.toKtAnnotationValue(): KtAnnotationValue {
|
||||
value.annotationClass?.classId,
|
||||
psi = null,
|
||||
useSiteTarget = null,
|
||||
arguments = arguments,
|
||||
arguments = value.getKtNamedAnnotationArguments(),
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -413,9 +415,7 @@ internal fun ClassDescriptor.getSupertypesWithAny(): Collection<KotlinType> {
|
||||
|
||||
internal fun DeclarationDescriptor.render(analysisContext: Fe10AnalysisContext, options: KtDeclarationRendererOptions): String {
|
||||
val renderer = KtFe10Renderer(analysisContext, options)
|
||||
val consumer = StringBuilder()
|
||||
renderer.render(this, consumer)
|
||||
return consumer.toString().trim()
|
||||
return prettyPrint { renderer.render(this@render, this) }.trim()
|
||||
}
|
||||
|
||||
internal fun CallableMemberDescriptor.getSymbolPointerSignature(analysisContext: Fe10AnalysisContext): String {
|
||||
|
||||
+3
-3
@@ -11,9 +11,11 @@ import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationsList
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtTypeRendererOptions
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.Fe10AnalysisContext
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.annotations.KtFe10AnnotationsList
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.render
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.utils.KtFe10TypeRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
|
||||
import org.jetbrains.kotlin.analysis.api.withValidityAssertion
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
|
||||
@@ -32,8 +34,6 @@ interface KtFe10Type : ValidityTokenOwner, KtAnnotated {
|
||||
}
|
||||
|
||||
internal fun KotlinType.asStringForDebugging(): String {
|
||||
val builder = StringBuilder()
|
||||
val renderer = KtFe10TypeRenderer(KtTypeRendererOptions.DEFAULT, isDebugText = true)
|
||||
renderer.render(this, builder)
|
||||
return builder.toString()
|
||||
return prettyPrint { renderer.render(this@asStringForDebugging, this) }
|
||||
}
|
||||
+63
-156
@@ -12,32 +12,31 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.bas
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.isExplicitOverride
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.ktModality
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.ktVisibility
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.components.hasDefaultValue
|
||||
import org.jetbrains.kotlin.resolve.calls.components.isVararg
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeApproximator
|
||||
import org.jetbrains.kotlin.types.typeUtil.isNullableAny
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
|
||||
internal typealias KtFe10RendererConsumer = StringBuilder
|
||||
internal typealias KtFe10RendererConsumer = PrettyPrinter
|
||||
|
||||
internal class KtFe10Renderer(
|
||||
private val analysisContext: Fe10AnalysisContext,
|
||||
@@ -45,8 +44,6 @@ internal class KtFe10Renderer(
|
||||
isDebugText: Boolean = false
|
||||
) {
|
||||
private companion object {
|
||||
private val INDENTATION = " ".repeat(4)
|
||||
|
||||
val IGNORED_VISIBILITIES: Set<Visibility> = setOf(
|
||||
Visibilities.Local,
|
||||
Visibilities.PrivateToThis,
|
||||
@@ -69,22 +66,6 @@ internal class KtFe10Renderer(
|
||||
analysisContext.resolveSession.languageVersionSettings
|
||||
)
|
||||
|
||||
private var indentation = 0
|
||||
|
||||
private fun KtFe10RendererConsumer.curlyBlock(body: KtFe10RendererConsumer.() -> Unit) {
|
||||
append(" {")
|
||||
indentedBlock(body)
|
||||
appendLine()
|
||||
renderIndentation()
|
||||
append('}')
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.indentedBlock(body: KtFe10RendererConsumer.() -> Unit) {
|
||||
indentation += 1
|
||||
body()
|
||||
indentation -= 1
|
||||
}
|
||||
|
||||
fun render(descriptor: DeclarationDescriptor, consumer: KtFe10RendererConsumer) {
|
||||
consumer.renderDeclaration(descriptor)
|
||||
}
|
||||
@@ -138,7 +119,7 @@ internal class KtFe10Renderer(
|
||||
|
||||
private fun KtFe10RendererConsumer.renderTypeAlias(descriptor: TypeAliasDescriptor) {
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(descriptor.annotations)
|
||||
renderAnnotations(descriptor)
|
||||
renderModifiers(descriptor)
|
||||
append("typealias ")
|
||||
}
|
||||
@@ -149,7 +130,9 @@ internal class KtFe10Renderer(
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderTypeParameters(typeParameters: List<TypeParameterDescriptor>) {
|
||||
renderList(typeParameters, separator = ", ", prefix = "<", postfix = ">", renderWhenEmpty = false) { renderTypeParameter(it) }
|
||||
if (typeParameters.isNotEmpty()) append('<')
|
||||
printCollection(typeParameters, separator = ", ") { renderTypeParameter(it) }
|
||||
if (typeParameters.isNotEmpty()) append('>')
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderTypeParameter(descriptor: TypeParameterDescriptor) {
|
||||
@@ -158,19 +141,16 @@ internal class KtFe10Renderer(
|
||||
val variance = descriptor.variance.label
|
||||
renderModifier(variance, variance.isNotEmpty())
|
||||
|
||||
renderAnnotations(descriptor.annotations)
|
||||
renderAnnotations(descriptor)
|
||||
renderName(descriptor)
|
||||
|
||||
val upperBounds = descriptor.upperBounds.filterNot { it.isNullableAny() }
|
||||
renderList(upperBounds, separator = " & ", prefix = " : ", postfix = "", renderWhenEmpty = false) { renderType(it) }
|
||||
printCollectionIfNotEmpty(upperBounds, separator = " & ", prefix = " : ") { renderType(it) }
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderClass(descriptor: ClassDescriptor) {
|
||||
appendLine()
|
||||
renderIndentation()
|
||||
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(descriptor.annotations)
|
||||
renderAnnotations(descriptor)
|
||||
renderModifiers(descriptor)
|
||||
|
||||
|
||||
@@ -200,7 +180,7 @@ internal class KtFe10Renderer(
|
||||
renderTypeParameters(descriptor.declaredTypeParameters)
|
||||
renderSupertypes(descriptor)
|
||||
|
||||
if (options.renderContainingDeclarations) {
|
||||
if (options.renderClassMembers) {
|
||||
val (enumEntries, otherDeclarations) = descriptor.unsubstitutedMemberScope.getContributedDescriptors()
|
||||
.filter { shouldRenderNestedDeclaration(descriptor, it) }
|
||||
.partition { it is ClassDescriptor && it.kind == ClassKind.ENUM_ENTRY }
|
||||
@@ -209,10 +189,19 @@ internal class KtFe10Renderer(
|
||||
.filter { shouldRenderNestedDeclaration(descriptor, it) }
|
||||
|
||||
if (enumEntries.isNotEmpty() || otherDeclarations.isNotEmpty() || constructors.isNotEmpty()) {
|
||||
curlyBlock {
|
||||
enumEntries.forEach { renderEnumEntry(it as ClassDescriptor) }
|
||||
sortDeclarations(constructors).forEach { renderConstructor(it) }
|
||||
sortDeclarations(otherDeclarations).forEach { renderDeclaration(it) }
|
||||
append(' ')
|
||||
withIndentInBraces {
|
||||
printCollection(sortDeclarations(enumEntries), separator = ",\n") {
|
||||
renderEnumEntry(it as ClassDescriptor)
|
||||
}
|
||||
|
||||
if (enumEntries.isNotEmpty() && (constructors.isNotEmpty() || otherDeclarations.isNotEmpty())) {
|
||||
appendLine(";\n")
|
||||
}
|
||||
|
||||
printCollection(sortDeclarations(constructors + otherDeclarations), separator = "\n\n") {
|
||||
renderDeclaration(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -268,8 +257,8 @@ internal class KtFe10Renderer(
|
||||
return@Comparator nameResult
|
||||
}
|
||||
|
||||
val leftString = buildString { renderDeclaration(left) }
|
||||
val rightString = buildString { renderDeclaration(right) }
|
||||
val leftString = prettyPrint { renderDeclaration(left) }
|
||||
val rightString = prettyPrint { renderDeclaration(right) }
|
||||
return@Comparator leftString.compareTo(rightString)
|
||||
})
|
||||
}
|
||||
@@ -279,7 +268,7 @@ internal class KtFe10Renderer(
|
||||
.filterTo(HashSet()) { it.classId !in IGNORED_SUPERTYPES }
|
||||
|
||||
val supertypes = descriptor.typeConstructor.supertypes.filter { it.constructor.declarationDescriptor in allowedSuperClasses }
|
||||
renderList(supertypes, separator = ", ", prefix = " : ", postfix = "", renderWhenEmpty = false) { renderType(it) }
|
||||
printCollectionIfNotEmpty(supertypes, separator = ", ", prefix = " : ") { renderType(it) }
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderCallable(descriptor: CallableDescriptor) {
|
||||
@@ -296,47 +285,35 @@ internal class KtFe10Renderer(
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderPropertyAccessor(descriptor: PropertyAccessorDescriptor) {
|
||||
appendLine()
|
||||
indentedBlock {
|
||||
renderIndentation()
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(descriptor.annotations)
|
||||
renderModifiers(descriptor)
|
||||
}
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(descriptor)
|
||||
renderModifiers(descriptor)
|
||||
}
|
||||
|
||||
when (descriptor) {
|
||||
is PropertyGetterDescriptor -> {
|
||||
append("get()")
|
||||
}
|
||||
is PropertySetterDescriptor -> {
|
||||
append("set(")
|
||||
val valueParameter = descriptor.valueParameters.singleOrNull()
|
||||
if (valueParameter != null) {
|
||||
val name = valueParameter.name.takeIf { !it.isSpecial } ?: Name.identifier("value")
|
||||
renderValueParameter(valueParameter, name)
|
||||
}
|
||||
append(")")
|
||||
when (descriptor) {
|
||||
is PropertyGetterDescriptor -> {
|
||||
append("get()")
|
||||
}
|
||||
is PropertySetterDescriptor -> {
|
||||
append("set(")
|
||||
val valueParameter = descriptor.valueParameters.singleOrNull()
|
||||
if (valueParameter != null) {
|
||||
val name = valueParameter.name.takeIf { !it.isSpecial } ?: Name.identifier("value")
|
||||
renderValueParameter(valueParameter, name)
|
||||
}
|
||||
append(")")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderEnumEntry(descriptor: ClassDescriptor) {
|
||||
assert(descriptor.kind == ClassKind.ENUM_ENTRY)
|
||||
|
||||
appendLine()
|
||||
renderIndentation()
|
||||
|
||||
renderName(descriptor)
|
||||
append(',')
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderLocalVariable(descriptor: LocalVariableDescriptor) {
|
||||
appendLine()
|
||||
renderIndentation()
|
||||
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(descriptor.annotations)
|
||||
renderAnnotations(descriptor)
|
||||
append(if (descriptor.isVar) "var" else "val").append(' ')
|
||||
}
|
||||
|
||||
@@ -346,11 +323,8 @@ internal class KtFe10Renderer(
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderProperty(descriptor: PropertyDescriptor) {
|
||||
appendLine()
|
||||
renderIndentation()
|
||||
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(descriptor.annotations)
|
||||
renderAnnotations(descriptor)
|
||||
renderModifiers(descriptor)
|
||||
append(if (descriptor.isVar) "var" else "val").append(' ')
|
||||
renderTypeParameters(descriptor.typeParameters)
|
||||
@@ -364,11 +338,9 @@ internal class KtFe10Renderer(
|
||||
append(": ")
|
||||
renderType(descriptor.type, shouldApproximate = options.approximateTypes)
|
||||
|
||||
if (options.renderContainingDeclarations) {
|
||||
if (options.renderClassMembers) {
|
||||
fun shouldRenderAccessor(accessor: PropertyAccessorDescriptor): Boolean {
|
||||
return descriptor.isDelegated
|
||||
|| accessor.hasBody()
|
||||
|| !accessor.annotations.isEmpty()
|
||||
return !accessor.annotations.isEmpty()
|
||||
|| accessor.visibility != descriptor.visibility
|
||||
}
|
||||
|
||||
@@ -377,11 +349,15 @@ internal class KtFe10Renderer(
|
||||
|
||||
val shouldRenderAccessors = (getter != null && shouldRenderAccessor(getter)) || (setter != null && shouldRenderAccessor(setter))
|
||||
if (shouldRenderAccessors) {
|
||||
if (getter != null) {
|
||||
renderPropertyAccessor(getter)
|
||||
}
|
||||
if (setter != null) {
|
||||
renderPropertyAccessor(setter)
|
||||
withIndent {
|
||||
if (getter != null) {
|
||||
appendLine()
|
||||
renderPropertyAccessor(getter)
|
||||
}
|
||||
if (setter != null) {
|
||||
appendLine()
|
||||
renderPropertyAccessor(setter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,23 +377,16 @@ internal class KtFe10Renderer(
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderConstructor(descriptor: ConstructorDescriptor) {
|
||||
appendLine()
|
||||
renderIndentation()
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(descriptor.annotations)
|
||||
renderAnnotations(descriptor)
|
||||
}
|
||||
append("constructor")
|
||||
renderValueParameters(descriptor.valueParameters)
|
||||
|
||||
renderLocalDeclarations(descriptor)
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderFunction(descriptor: FunctionDescriptor) {
|
||||
appendLine()
|
||||
renderIndentation()
|
||||
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(descriptor.annotations)
|
||||
renderAnnotations(descriptor)
|
||||
renderModifiers(descriptor)
|
||||
append("fun ")
|
||||
renderTypeParameters(descriptor.typeParameters)
|
||||
@@ -435,17 +404,15 @@ internal class KtFe10Renderer(
|
||||
append(": ")
|
||||
renderType(returnType, shouldApproximate = options.approximateTypes)
|
||||
}
|
||||
|
||||
renderLocalDeclarations(descriptor)
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderValueParameters(valueParameters: List<ValueParameterDescriptor>) {
|
||||
renderList(valueParameters, separator = ", ", prefix = "(", postfix = ")", renderWhenEmpty = true) { renderValueParameter(it) }
|
||||
printCollection(valueParameters, separator = ", ", prefix = "(", postfix = ")") { renderValueParameter(it) }
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderValueParameter(descriptor: ValueParameterDescriptor, name: Name = descriptor.name) {
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(descriptor.annotations)
|
||||
renderAnnotations(descriptor)
|
||||
}
|
||||
|
||||
renderModifiers(descriptor)
|
||||
@@ -458,50 +425,16 @@ internal class KtFe10Renderer(
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderLocalDeclarations(descriptor: CallableMemberDescriptor) {
|
||||
if (!options.renderContainingDeclarations) {
|
||||
return
|
||||
}
|
||||
|
||||
val body = when (val declaration = descriptor.source.getPsi()) {
|
||||
is KtFunction -> declaration.bodyExpression
|
||||
is KtPropertyAccessor -> declaration.bodyExpression
|
||||
else -> null
|
||||
}
|
||||
|
||||
val collectedChildren = mutableListOf<DeclarationDescriptor>()
|
||||
|
||||
body?.accept(object : KtTreeVisitorVoid() {
|
||||
override fun visitDeclaration(declaration: KtDeclaration) {
|
||||
if (declaration is KtFunction || declaration is KtVariableDeclaration || declaration is KtClassOrObject) {
|
||||
val bindingContext = analysisContext.analyze(declaration)
|
||||
val childDescriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration]
|
||||
if (childDescriptor != null) {
|
||||
collectedChildren += childDescriptor
|
||||
}
|
||||
} else {
|
||||
super.visitDeclaration(declaration)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (collectedChildren.isNotEmpty()) {
|
||||
curlyBlock {
|
||||
collectedChildren.forEach { renderDeclaration(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderName(descriptor: DeclarationDescriptor) {
|
||||
append(descriptor.name.render())
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderAnnotations(annotations: Annotations, predicate: (ClassId) -> Boolean = { true }) {
|
||||
private fun KtFe10RendererConsumer.renderAnnotations(declaration: Annotated, predicate: (ClassId) -> Boolean = { true }) {
|
||||
if (RendererModifier.ANNOTATIONS !in options.modifiers) {
|
||||
return
|
||||
}
|
||||
|
||||
renderFe10Annotations(annotations, predicate)
|
||||
val isSingleLineAnnotations = declaration is ValueParameterDescriptor || declaration is TypeParameterDescriptor
|
||||
renderFe10Annotations(declaration.annotations, isSingleLineAnnotations, predicate)
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderModifiers(descriptor: DeclarationDescriptor) {
|
||||
@@ -595,30 +528,4 @@ internal class KtFe10Renderer(
|
||||
append(text).append(' ')
|
||||
}
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderIndentation() {
|
||||
append(INDENTATION.repeat(indentation))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <T> KtFe10RendererConsumer.renderList(
|
||||
list: Collection<T>,
|
||||
separator: String,
|
||||
prefix: String = "",
|
||||
postfix: String = "",
|
||||
renderWhenEmpty: Boolean = true,
|
||||
renderItem: KtFe10RendererConsumer.(T) -> Unit
|
||||
) {
|
||||
if (!renderWhenEmpty && list.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
append(prefix)
|
||||
list.forEachIndexed { index, item ->
|
||||
if (index > 0) {
|
||||
append(separator)
|
||||
}
|
||||
renderItem(item)
|
||||
}
|
||||
append(postfix)
|
||||
}
|
||||
+13
-12
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.bas
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.getKtNamedAnnotationArguments
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.maybeLocalClassId
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
|
||||
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
|
||||
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
|
||||
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
|
||||
@@ -38,7 +39,7 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
const val ERROR_TYPE_TEXT = "ERROR_TYPE"
|
||||
}
|
||||
|
||||
fun render(type: KotlinType, consumer: KtFe10RendererConsumer) {
|
||||
fun render(type: KotlinType, consumer: PrettyPrinter) {
|
||||
consumer.renderType(type)
|
||||
}
|
||||
|
||||
@@ -46,7 +47,7 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
if (isDebugText) {
|
||||
renderTypeAnnotationsDebug(type)
|
||||
} else {
|
||||
renderFe10Annotations(type.annotations) { classId ->
|
||||
renderFe10Annotations(type.annotations, isSingleLineAnnotations = true) { classId ->
|
||||
classId != StandardClassIds.Annotations.ExtensionFunctionType
|
||||
}
|
||||
}
|
||||
@@ -86,7 +87,7 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
val annotations = type.annotations
|
||||
.filter { it.annotationClass?.classId != StandardClassIds.Annotations.ExtensionFunctionType }
|
||||
|
||||
renderList(annotations, separator = " ", postfix = " ", renderWhenEmpty = false) { renderTypeAnnotationDebug(it) }
|
||||
printCollectionIfNotEmpty(annotations, separator = " ", postfix = " ") { renderTypeAnnotationDebug(it) }
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderTypeAnnotationDebug(annotation: AnnotationDescriptor) {
|
||||
@@ -105,7 +106,7 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
print("<ERROR TYPE REF>")
|
||||
}
|
||||
|
||||
renderList(namedValues, separator = ", ", prefix = "(", postfix = ")") { (name, value) ->
|
||||
printCollection(namedValues, separator = ", ", prefix = "(", postfix = ")") { (name, value) ->
|
||||
append(name).append(" = ")
|
||||
renderConstantValueDebug(value)
|
||||
}
|
||||
@@ -115,9 +116,9 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
when (value) {
|
||||
is KtAnnotationApplicationValue -> renderAnnotationDebug(value.annotationValue.classId, value.annotationValue.arguments)
|
||||
is KtArrayAnnotationValue ->
|
||||
renderList(value.values, separator = ", ", prefix = "[", postfix = "]") { renderConstantValueDebug(it) }
|
||||
is KtEnumEntryAnnotationValue -> append(value.callableId)
|
||||
is KtConstantAnnotationValue -> append(value.constantValue.constantValueKind.asString).append("(").append(value.constantValue.value).append(")")
|
||||
printCollection(value.values, separator = ", ", prefix = "[", postfix = "]") { renderConstantValueDebug(it) }
|
||||
is KtEnumEntryAnnotationValue -> append(value.callableId?.asSingleFqName()?.render())
|
||||
is KtConstantAnnotationValue -> append(value.constantValue.constantValueKind.asString).append("(").append(value.constantValue.value.toString()).append(")")
|
||||
KtUnsupportedAnnotationValue -> append(KtUnsupportedAnnotationValue::class.java.simpleName)
|
||||
is KtKClassAnnotationValue -> append(value.render())
|
||||
}
|
||||
@@ -168,7 +169,7 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
if (isDebugText) {
|
||||
append("it")
|
||||
}
|
||||
renderList(typeConstructor.supertypes, separator = " & ", prefix = "(", postfix = ")") { renderType(it) }
|
||||
printCollection(typeConstructor.supertypes, separator = " & ", prefix = "(", postfix = ")") { renderType(it) }
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderFunctionType(type: SimpleType) {
|
||||
@@ -180,7 +181,7 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
renderType(receiverType)
|
||||
append(".")
|
||||
}
|
||||
renderList(valueParameters, separator = ", ", prefix = "(", postfix = ")") { renderTypeProjection(it) }
|
||||
printCollection(valueParameters, separator = ", ", prefix = "(", postfix = ")") { renderTypeProjection(it) }
|
||||
append(" -> ")
|
||||
renderType(returnType)
|
||||
}
|
||||
@@ -192,7 +193,7 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
private fun KtFe10RendererConsumer.renderOrdinaryType(type: SimpleType) {
|
||||
val nestedType = KtFe10JvmTypeMapperContext.getNestedType(type)
|
||||
renderTypeSegment(nestedType.root, isRoot = true)
|
||||
renderList(nestedType.nested, separator = ".", prefix = ".", postfix = "", renderWhenEmpty = false) { renderTypeSegment(it) }
|
||||
printCollectionIfNotEmpty(nestedType.nested, separator = ".", prefix = ".", postfix = "") { renderTypeSegment(it) }
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderTypeSegment(typeSegment: PossiblyInnerType, isRoot: Boolean = false) {
|
||||
@@ -212,11 +213,11 @@ internal class KtFe10TypeRenderer(private val options: KtTypeRendererOptions, pr
|
||||
}
|
||||
|
||||
val arguments = typeSegment.arguments
|
||||
renderList(arguments, separator = ", ", prefix = "<", postfix = ">", renderWhenEmpty = false) { renderTypeProjection(it) }
|
||||
printCollectionIfNotEmpty(arguments, separator = ", ", prefix = "<", postfix = ">") { renderTypeProjection(it) }
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderFqName(fqName: FqName) {
|
||||
renderList(fqName.pathSegments(), separator = ".") { append(it.render()) }
|
||||
printCollection(fqName.pathSegments(), separator = ".") { append(it.render()) }
|
||||
}
|
||||
|
||||
private fun KtFe10RendererConsumer.renderTypeProjection(projection: TypeProjection) {
|
||||
|
||||
+9
-3
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.bas
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationValueRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.descriptors.symbols.descriptorBased.base.toKtAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -16,7 +17,12 @@ import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
|
||||
internal fun KtFe10RendererConsumer.renderFe10Annotations(annotations: Annotations, predicate: (ClassId) -> Boolean = { true }) {
|
||||
internal fun PrettyPrinter.renderFe10Annotations(
|
||||
annotations: Annotations,
|
||||
isSingleLineAnnotations: Boolean,
|
||||
predicate: (ClassId) -> Boolean = { true }
|
||||
) {
|
||||
val separator = if (isSingleLineAnnotations) " " else "\n"
|
||||
for (annotation in annotations) {
|
||||
val annotationClass = annotation.annotationClass ?: continue
|
||||
val classId = annotationClass.classId
|
||||
@@ -29,13 +35,13 @@ internal fun KtFe10RendererConsumer.renderFe10Annotations(annotations: Annotatio
|
||||
append(annotation.fqName?.shortName()?.asString() ?: "ERROR")
|
||||
|
||||
val valueArguments = annotation.allValueArguments.entries.sortedBy { it.key.asString() }
|
||||
renderList(valueArguments, separator = ", ", prefix = "(", postfix = ")", renderWhenEmpty = false) { (name, value) ->
|
||||
printCollectionIfNotEmpty(valueArguments, separator = ", ", prefix = "(", postfix = ")") { (name, value) ->
|
||||
append(name.render())
|
||||
append(" = ")
|
||||
append(KtAnnotationValueRenderer.render(value.toKtAnnotationValue()))
|
||||
}
|
||||
|
||||
append(' ')
|
||||
append(separator)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ dependencies {
|
||||
api(project(":compiler:light-classes"))
|
||||
api(intellijCoreDep())
|
||||
implementation(project(":analysis:analysis-api-providers"))
|
||||
implementation(project(":analysis:analysis-internal-utils"))
|
||||
|
||||
testApi(projectTests(":analysis:low-level-api-fir"))
|
||||
testApi(projectTests(":compiler:tests-common"))
|
||||
|
||||
+6
-27
@@ -16,9 +16,11 @@ import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.fir.types.KtFirType
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPackageSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtSymbolWithKind
|
||||
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
|
||||
internal class KtFirSymbolDeclarationRendererProvider(
|
||||
@@ -31,33 +33,10 @@ internal class KtFirSymbolDeclarationRendererProvider(
|
||||
return ConeTypeIdeRenderer(analysisSession.firResolveState.rootModuleSession, options).renderType(type.coneType)
|
||||
}
|
||||
|
||||
override fun render(symbol: KtSymbol, options: KtDeclarationRendererOptions): String {
|
||||
return when (symbol) {
|
||||
is KtPackageSymbol -> {
|
||||
"package ${symbol.fqName.asString()}"
|
||||
}
|
||||
is KtFirSymbol<*> -> {
|
||||
val containingSymbol = with(analysisSession) {
|
||||
(symbol as? KtSymbolWithKind)?.getContainingSymbol()
|
||||
}
|
||||
check(containingSymbol is KtFirSymbol<*>?)
|
||||
|
||||
symbol.firRef.withFir(FirResolvePhase.BODY_RESOLVE) { fir ->
|
||||
val containingFir = containingSymbol?.firRef?.withFirUnsafe { it }
|
||||
FirIdeRenderer.render(fir, containingFir, options, fir.moduleData.session)
|
||||
}
|
||||
}
|
||||
is KtFirReceiverParameterSymbol -> {
|
||||
val containingDeclaration = with(analysisSession) {
|
||||
symbol.getContainingSymbol() ?: error("expects receiver parameter symbol to return the containing declaration")
|
||||
}
|
||||
|
||||
"extension receiver of " + render(containingDeclaration, options)
|
||||
}
|
||||
else -> {
|
||||
error("Unexpected Fir Symbol ${symbol::class.simpleName}")
|
||||
}
|
||||
override fun renderMember(symbol: KtPossibleMemberSymbol, options: KtDeclarationRendererOptions): String {
|
||||
require(symbol is KtFirSymbol<*>)
|
||||
return symbol.firRef.withFir(FirResolvePhase.BODY_RESOLVE) { fir ->
|
||||
FirIdeRenderer.render(fir as FirMemberDeclaration, options, fir.moduleData.session)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ internal class ConeTypeIdeRenderer(
|
||||
|
||||
private fun StringBuilder.renderAnnotationList(type: ConeKotlinType) {
|
||||
if (options.renderTypeAnnotations) {
|
||||
renderAnnotations(this@ConeTypeIdeRenderer, type.customAnnotations, session)
|
||||
renderAnnotations(this@ConeTypeIdeRenderer, type.customAnnotations, session, isSingleLineAnnotations = true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-3
@@ -10,26 +10,31 @@ import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirCompileTimeConstantEval
|
||||
import org.jetbrains.kotlin.analysis.api.fir.evaluate.FirAnnotationValueConverter
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtAnnotationValueRenderer
|
||||
import org.jetbrains.kotlin.analysis.api.annotations.KtUnsupportedAnnotationValue
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.toAnnotationClassId
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import kotlin.text.Appendable
|
||||
|
||||
internal fun StringBuilder.renderAnnotations(
|
||||
internal fun Appendable.renderAnnotations(
|
||||
coneTypeIdeRenderer: ConeTypeIdeRenderer,
|
||||
annotations: List<FirAnnotation>,
|
||||
session: FirSession
|
||||
session: FirSession,
|
||||
isSingleLineAnnotations: Boolean,
|
||||
) {
|
||||
val separator = if (isSingleLineAnnotations) " " else "\n"
|
||||
for (annotation in annotations) {
|
||||
if (!annotation.isParameterName()) {
|
||||
append(renderAnnotation(annotation, coneTypeIdeRenderer, session))
|
||||
append(" ")
|
||||
append(separator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun FirAnnotation.isParameterName(): Boolean {
|
||||
return toAnnotationClassId()?.asSingleFqName() == StandardNames.FqNames.parameterName
|
||||
}
|
||||
|
||||
+220
-586
@@ -6,575 +6,225 @@
|
||||
package org.jetbrains.kotlin.analysis.api.fir.renderer
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
|
||||
import org.jetbrains.kotlin.analysis.api.components.RendererModifier
|
||||
import org.jetbrains.kotlin.analysis.api.fir.types.PublicTypeApproximator
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.prettyPrint
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.PsiSourceNavigator.getRawName
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirBlock
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.hasBody
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.extensions.generatedMembers
|
||||
import org.jetbrains.kotlin.fir.extensions.generatedNestedClassifiers
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.fir.visitors.FirVisitor
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
|
||||
|
||||
internal class FirIdeRenderer private constructor(
|
||||
private var containingDeclaration: FirDeclaration?,
|
||||
private val options: KtDeclarationRendererOptions,
|
||||
private val session: FirSession
|
||||
) : FirVisitor<Unit, StringBuilder>() {
|
||||
|
||||
private val typeIdeRenderer: ConeTypeIdeRenderer = ConeTypeIdeRenderer(session, options.typeRendererOptions)
|
||||
|
||||
private fun StringBuilder.renderAnnotations(annotated: FirDeclaration) {
|
||||
if (RendererModifier.ANNOTATIONS in options.modifiers) {
|
||||
renderAnnotations(typeIdeRenderer, annotated.annotations, session)
|
||||
options: KtDeclarationRendererOptions,
|
||||
session: FirSession,
|
||||
) : FirIdeRendererBase(options, session) {
|
||||
fun PrettyPrinter.renderMemberDeclaration(declaration: FirMemberDeclaration) {
|
||||
when (declaration) {
|
||||
is FirAnonymousObject -> renderAnonymousObject(declaration)
|
||||
is FirRegularClass -> renderRegularClass(declaration)
|
||||
is FirTypeAlias -> renderTypeAlias(declaration)
|
||||
is FirConstructor -> renderConstructor(declaration)
|
||||
is FirPropertyAccessor -> renderPropertyAccessor(declaration)
|
||||
is FirSimpleFunction -> renderSimpleFunction(declaration)
|
||||
is FirEnumEntry -> renderEnumEntry(declaration)
|
||||
is FirProperty -> renderProperty(declaration)
|
||||
is FirValueParameter -> renderValueParameter(declaration)
|
||||
is FirField -> TODO()
|
||||
is FirAnonymousFunction -> TODO()
|
||||
is FirErrorFunction -> Unit
|
||||
is FirErrorProperty -> Unit
|
||||
is FirBackingField -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderType(type: ConeTypeProjection): String =
|
||||
typeIdeRenderer.renderType(type)
|
||||
|
||||
private fun renderType(firRef: FirTypeRef, approximate: Boolean = false): String {
|
||||
require(firRef is FirResolvedTypeRef)
|
||||
|
||||
val approximatedIfNeeded = approximate.ifTrue {
|
||||
PublicTypeApproximator.approximateTypeToPublicDenotable(firRef.coneType, session, approximateLocalTypes = true)
|
||||
} ?: firRef.coneType
|
||||
return renderType(approximatedIfNeeded)
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderName(declaration: FirDeclaration) {
|
||||
if (declaration is FirAnonymousObject) {
|
||||
append("<no name provided>")
|
||||
return
|
||||
}
|
||||
|
||||
val name = when (declaration) {
|
||||
is FirRegularClass -> declaration.name
|
||||
is FirSimpleFunction -> declaration.name
|
||||
is FirProperty -> declaration.name
|
||||
is FirValueParameter -> declaration.name
|
||||
is FirTypeParameter -> declaration.name
|
||||
is FirTypeAlias -> declaration.name
|
||||
is FirEnumEntry -> declaration.name
|
||||
else -> TODO("Unexpected declaration ${declaration::class.qualifiedName}")
|
||||
}
|
||||
append(name.render())
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderCompanionObjectName(firClass: FirRegularClass) {
|
||||
if (firClass.name != SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT) {
|
||||
tabRightBySpace()
|
||||
append(firClass.name.render())
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderVisibility(visibility: Visibility) {
|
||||
if (RendererModifier.VISIBILITY !in options.modifiers) return
|
||||
|
||||
val currentVisibility = when (visibility) {
|
||||
Visibilities.Local -> Visibilities.Public
|
||||
Visibilities.PrivateToThis -> Visibilities.Public
|
||||
Visibilities.InvisibleFake -> Visibilities.Public
|
||||
Visibilities.Inherited -> Visibilities.Public
|
||||
Visibilities.Unknown -> Visibilities.Public
|
||||
else -> visibility
|
||||
}.applyIf(options.normalizedVisibilities) {
|
||||
normalize()
|
||||
}
|
||||
|
||||
if (currentVisibility == Visibilities.DEFAULT_VISIBILITY) return
|
||||
|
||||
append(currentVisibility.internalDisplayName)
|
||||
append(" ")
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderModality(modality: Modality, defaultModality: Modality) {
|
||||
if (modality == defaultModality) return
|
||||
renderModifier(RendererModifier.MODALITY in options.modifiers, modality.name.toLowerCaseAsciiOnly())
|
||||
}
|
||||
|
||||
private fun FirMemberDeclaration.implicitModalityWithoutExtensions(containingDeclaration: FirDeclaration?): Modality {
|
||||
if (this is FirRegularClass) {
|
||||
return if (classKind == ClassKind.INTERFACE) Modality.ABSTRACT else Modality.FINAL
|
||||
}
|
||||
val containingFirClass = containingDeclaration as? FirRegularClass ?: return Modality.FINAL
|
||||
if (this !is FirCallableDeclaration) return Modality.FINAL
|
||||
if (isOverride) {
|
||||
if (containingFirClass.modality != Modality.FINAL) return Modality.OPEN
|
||||
}
|
||||
return if (containingFirClass.classKind == ClassKind.INTERFACE && this.visibility != Visibilities.Private) {
|
||||
if (this.modality == Modality.ABSTRACT) Modality.ABSTRACT else Modality.OPEN
|
||||
} else
|
||||
Modality.FINAL
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderModalityForCallable(
|
||||
callable: FirCallableDeclaration,
|
||||
containingDeclaration: FirDeclaration?
|
||||
) {
|
||||
val modality = callable.modality ?: return
|
||||
val isTopLevel = containingDeclaration == null
|
||||
if (!isTopLevel || modality != Modality.FINAL) {
|
||||
if (callable.isOverride) return
|
||||
renderModality(modality, callable.implicitModalityWithoutExtensions(containingDeclaration))
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderOverride(callableMember: FirCallableDeclaration) {
|
||||
if (RendererModifier.OVERRIDE !in options.modifiers) return
|
||||
renderModifier(callableMember.isOverride || options.forceRenderingOverrideModifier, "override")
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderModifier(value: Boolean, modifier: String) {
|
||||
if (value) {
|
||||
append(modifier)
|
||||
append(" ")
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderMemberModifiers(declaration: FirMemberDeclaration) {
|
||||
renderModifier(declaration.isExternal, "external")
|
||||
renderModifier(RendererModifier.EXPECT in options.modifiers && declaration.isExpect, "expect")
|
||||
renderModifier(RendererModifier.ACTUAL in options.modifiers && declaration.isActual, "actual")
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderAdditionalModifiers(firMember: FirMemberDeclaration) {
|
||||
val isOperator =
|
||||
firMember.isOperator//TODO make similar to functionDescriptor.overriddenDescriptors.none { it.isOperator }
|
||||
val isInfix =
|
||||
firMember.isInfix//TODO make similar to functionDescriptor.overriddenDescriptors.none { it.isInfix }
|
||||
|
||||
renderModifier(firMember.isTailRec, "tailrec")
|
||||
renderSuspendModifier(firMember)
|
||||
renderModifier(firMember.isInline, "inline")
|
||||
renderModifier(isInfix, "infix")
|
||||
renderModifier(RendererModifier.OPERATOR in options.modifiers && isOperator, "operator")
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderSuspendModifier(functionDescriptor: FirMemberDeclaration) {
|
||||
renderModifier(functionDescriptor.isSuspend, "suspend")
|
||||
}
|
||||
|
||||
override fun visitValueParameter(valueParameter: FirValueParameter, data: StringBuilder) {
|
||||
with(data) {
|
||||
appendLine()
|
||||
appendTabs()
|
||||
append("value-parameter").append(" ")
|
||||
renderValueParameter(valueParameter)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitProperty(property: FirProperty, data: StringBuilder) = with(data) {
|
||||
appendLine()
|
||||
appendTabs()
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(property)
|
||||
renderVisibility(property.visibility)
|
||||
renderModifier(RendererModifier.CONST in options.modifiers && property.isConst, "const")
|
||||
renderMemberModifiers(property)
|
||||
renderModalityForCallable(property, containingDeclaration)
|
||||
renderOverride(property)
|
||||
renderModifier(RendererModifier.LATEINIT in options.modifiers && property.isLateInit, "lateinit")
|
||||
renderValVarPrefix(property)
|
||||
renderTypeParameters(property.typeParameters, true)
|
||||
}
|
||||
private fun PrettyPrinter.renderProperty(property: FirProperty) {
|
||||
renderAnnotationsAndModifiers(property)
|
||||
renderValVarPrefix(property)
|
||||
renderTypeParameters(property)
|
||||
renderReceiver(property)
|
||||
|
||||
renderName(property)
|
||||
append(": ").append(renderType(property.returnTypeRef, approximate = options.approximateTypes))
|
||||
append(": ")
|
||||
renderType(property.returnTypeRef, approximate = options.approximateTypes)
|
||||
|
||||
renderWhereSuffix(property.typeParameters)
|
||||
renderWhereSuffix(property)
|
||||
|
||||
fun FirPropertyAccessor?.needToRender() = this != null && (hasBody || visibility != property.visibility)
|
||||
val needToRenderAccessors = options.renderContainingDeclarations &&
|
||||
fun FirPropertyAccessor?.needToRender() = this != null && (annotations.isNotEmpty() || visibility != property.visibility)
|
||||
val needToRenderAccessors = options.renderClassMembers &&
|
||||
(property.getter.needToRender() || (property.isVar && property.setter.needToRender()))
|
||||
|
||||
fun FirPropertyAccessor?.render(isGetterByDefault: Boolean) {
|
||||
if (this == null) {
|
||||
appendLine()
|
||||
appendTabs()
|
||||
append(if (isGetterByDefault) "get" else "set")
|
||||
} else {
|
||||
visitPropertyAccessor(this, data)
|
||||
}
|
||||
}
|
||||
|
||||
if (needToRenderAccessors) {
|
||||
underBlockDeclaration(property, withBrackets = false) {
|
||||
property.getter.render(isGetterByDefault = true)
|
||||
if (property.isVar) property.setter.render(isGetterByDefault = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: StringBuilder) {
|
||||
require(containingDeclaration is FirProperty) { "Invalid containing declaration" }
|
||||
with(data) {
|
||||
appendLine()
|
||||
appendTabs()
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(propertyAccessor)
|
||||
renderVisibility(propertyAccessor.visibility)
|
||||
renderModalityForCallable(propertyAccessor, containingDeclaration)
|
||||
renderMemberModifiers(propertyAccessor)
|
||||
renderAdditionalModifiers(propertyAccessor)
|
||||
}
|
||||
append(if (propertyAccessor.isGetter) "get" else "set")
|
||||
if (propertyAccessor.isSetter) {
|
||||
append("(value: ")
|
||||
val renderedType = propertyAccessor.valueParameters.singleOrNull()?.returnTypeRef?.let { renderType(it) }
|
||||
if (renderedType != null) append(renderedType) else append(ConeTypeIdeRenderer.ERROR_TYPE_TEXT)
|
||||
append(")")
|
||||
} else {
|
||||
append("()")
|
||||
}
|
||||
}
|
||||
|
||||
if (options.renderContainingDeclarations) {
|
||||
propertyAccessor.body?.let {
|
||||
underBlockDeclaration(propertyAccessor, it, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: StringBuilder) {
|
||||
with(data) {
|
||||
appendLine()
|
||||
appendTabs()
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(simpleFunction)
|
||||
renderVisibility(simpleFunction.visibility)
|
||||
|
||||
renderModalityForCallable(simpleFunction, containingDeclaration)
|
||||
renderMemberModifiers(simpleFunction)
|
||||
renderOverride(simpleFunction)
|
||||
renderAdditionalModifiers(simpleFunction)
|
||||
append("fun ")
|
||||
renderTypeParameters(simpleFunction.typeParameters, true)
|
||||
}
|
||||
renderReceiver(simpleFunction)
|
||||
renderName(simpleFunction)
|
||||
renderValueParameters(simpleFunction.valueParameters)
|
||||
|
||||
val returnType = simpleFunction.returnTypeRef
|
||||
if (options.renderUnitReturnType || (!returnType.isUnit)) {
|
||||
append(": ")
|
||||
append(renderType(returnType, approximate = options.approximateTypes))
|
||||
}
|
||||
|
||||
renderWhereSuffix(simpleFunction.typeParameters)
|
||||
}
|
||||
|
||||
if (options.renderContainingDeclarations) {
|
||||
simpleFunction.body?.let {
|
||||
underBlockDeclaration(simpleFunction, it, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: StringBuilder) {
|
||||
with(data) {
|
||||
appendLine()
|
||||
appendTabs()
|
||||
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(anonymousObject)
|
||||
}
|
||||
append(getClassifierKindPrefix(anonymousObject))
|
||||
renderSuperTypes(anonymousObject)
|
||||
}
|
||||
|
||||
if (options.renderContainingDeclarations) {
|
||||
data.underBlockDeclaration(anonymousObject) {
|
||||
anonymousObject.declarations.forEach {
|
||||
it.accept(this, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitConstructor(constructor: FirConstructor, data: StringBuilder) {
|
||||
with(data) {
|
||||
appendLine()
|
||||
appendTabs()
|
||||
val containingClass = containingDeclaration
|
||||
check(containingClass is FirDeclaration && (containingClass is FirClass || containingClass is FirEnumEntry)) {
|
||||
"Invalid renderer containing declaration for constructor"
|
||||
}
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(constructor)
|
||||
}
|
||||
append("constructor")
|
||||
renderValueParameters(constructor.valueParameters)
|
||||
}
|
||||
|
||||
if (options.renderContainingDeclarations) {
|
||||
constructor.body?.let {
|
||||
underBlockDeclaration(constructor, it, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitTypeParameter(typeParameter: FirTypeParameter, data: StringBuilder) {
|
||||
data.renderTypeParameter(typeParameter, true)
|
||||
}
|
||||
|
||||
override fun visitRegularClass(regularClass: FirRegularClass, data: StringBuilder) {
|
||||
with(data) {
|
||||
appendLine()
|
||||
appendTabs()
|
||||
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(regularClass)
|
||||
if (regularClass.classKind != ClassKind.ENUM_ENTRY) {
|
||||
renderVisibility(regularClass.visibility)
|
||||
}
|
||||
|
||||
val haveNotModality = regularClass.classKind == ClassKind.INTERFACE && regularClass.modality == Modality.ABSTRACT ||
|
||||
regularClass.classKind.isSingleton && regularClass.modality == Modality.FINAL
|
||||
if (!haveNotModality) {
|
||||
regularClass.modality?.let {
|
||||
renderModality(it, regularClass.implicitModalityWithoutExtensions(containingDeclaration))
|
||||
withIndent {
|
||||
property.getter?.let { getter ->
|
||||
if (getter.needToRender()) {
|
||||
appendLine()
|
||||
renderPropertyAccessor(getter)
|
||||
}
|
||||
}
|
||||
renderMemberModifiers(regularClass)
|
||||
renderModifier(RendererModifier.INNER in options.modifiers && regularClass.isInner, "inner")
|
||||
renderModifier(RendererModifier.DATA in options.modifiers && regularClass.isData, "data")
|
||||
renderModifier(RendererModifier.INLINE in options.modifiers && regularClass.isInline, "inline")
|
||||
//TODO renderModifier(data, RendererModifier.VALUE in modifiers && regularClass.isValue, "value")
|
||||
renderModifier(RendererModifier.FUN in options.modifiers && regularClass.isFun, "fun")
|
||||
append(getClassifierKindPrefix(regularClass))
|
||||
}
|
||||
|
||||
if (!regularClass.isCompanion) {
|
||||
tabRightBySpace()
|
||||
renderName(regularClass)
|
||||
} else {
|
||||
renderCompanionObjectName(regularClass)
|
||||
}
|
||||
|
||||
if (regularClass.classKind == ClassKind.ENUM_ENTRY) return
|
||||
|
||||
val typeParameters = regularClass.typeParameters.filterIsInstance<FirTypeParameter>()
|
||||
renderTypeParameterRefs(typeParameters, false)
|
||||
renderSuperTypes(regularClass)
|
||||
renderWhereSuffix(typeParameters)
|
||||
}
|
||||
|
||||
fun FirDeclaration.isDefaultPrimaryConstructor() =
|
||||
this is FirConstructor &&
|
||||
isPrimary &&
|
||||
valueParameters.isEmpty() &&
|
||||
!hasBody &&
|
||||
(visibility == Visibilities.DEFAULT_VISIBILITY || regularClass.classKind == ClassKind.OBJECT)
|
||||
|
||||
fun FirDeclaration.skipDeclarationForEnumClass(): Boolean {
|
||||
if (this is FirConstructor) return isPrimary && valueParameters.isEmpty()
|
||||
if (this !is FirSimpleFunction) return false
|
||||
|
||||
if (name.asString() == "values" && valueParameters.isEmpty()) return true
|
||||
|
||||
if (name.asString() == "valueOf") {
|
||||
return valueParameters.count() == 1 && (valueParameters[0].returnTypeRef.coneType).classId == StandardClassIds.String
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun renderDeclarationForEnumClass() {
|
||||
check(regularClass.isEnumClass)
|
||||
val partitioned = regularClass.declarations.partition { it is FirEnumEntry }
|
||||
partitioned.first.forEach { enumEntry ->
|
||||
check(enumEntry is FirEnumEntry)
|
||||
visitEnumEntry(enumEntry, data)
|
||||
data.append(",")
|
||||
}
|
||||
sortDeclarations(partitioned.second).forEach {
|
||||
if (!it.skipDeclarationForEnumClass()) {
|
||||
it.accept(this, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun renderDeclarationForNotEnumClass() {
|
||||
check(!regularClass.isEnumClass)
|
||||
sortDeclarations(regularClass.declarations).forEach {
|
||||
if (!it.isDefaultPrimaryConstructor()) {
|
||||
it.accept(this, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.renderContainingDeclarations) {
|
||||
data.underBlockDeclaration(regularClass) {
|
||||
if (regularClass.isEnumClass) {
|
||||
renderDeclarationForEnumClass()
|
||||
} else {
|
||||
renderDeclarationForNotEnumClass()
|
||||
property.setter?.let { setter ->
|
||||
if (setter.needToRender()) {
|
||||
appendLine()
|
||||
renderPropertyAccessor(setter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var tabbedString = ""
|
||||
|
||||
private inline fun underTabbedBlock(body: () -> Unit) {
|
||||
val oldTabbedString = tabbedString
|
||||
tabbedString = " ".repeat(tabbedString.length + 4)
|
||||
body()
|
||||
tabbedString = oldTabbedString
|
||||
}
|
||||
|
||||
private inline fun underContainingDeclaration(firDeclaration: FirDeclaration, body: () -> Unit) {
|
||||
val oldContainingDeclaration = containingDeclaration
|
||||
containingDeclaration = firDeclaration
|
||||
body()
|
||||
containingDeclaration = oldContainingDeclaration
|
||||
}
|
||||
|
||||
private inline fun StringBuilder.underBlockDeclaration(firDeclaration: FirDeclaration, withBrackets: Boolean = true, body: () -> Unit) {
|
||||
val oldLength = length
|
||||
if (withBrackets) append(" {")
|
||||
val unchangedLength = length
|
||||
|
||||
underContainingDeclaration(firDeclaration) {
|
||||
underTabbedBlock(body)
|
||||
}
|
||||
|
||||
if (unchangedLength != length) {
|
||||
if (withBrackets) {
|
||||
appendLine()
|
||||
appendTabs()
|
||||
append("}")
|
||||
}
|
||||
private fun PrettyPrinter.renderPropertyAccessor(propertyAccessor: FirPropertyAccessor) {
|
||||
renderAnnotationsAndModifiers(propertyAccessor)
|
||||
append(if (propertyAccessor.isGetter) "get" else "set")
|
||||
if (propertyAccessor.isSetter) {
|
||||
append("(value: ")
|
||||
renderType(propertyAccessor.valueParameters.first().returnTypeRef)
|
||||
append(")")
|
||||
} else {
|
||||
delete(oldLength, unchangedLength)
|
||||
append("()")
|
||||
}
|
||||
renderFunctionBody(propertyAccessor)
|
||||
}
|
||||
|
||||
@Suppress("unused", "UNUSED_PARAMETER")
|
||||
private fun PrettyPrinter.renderFunctionBody(function: FirFunction) {
|
||||
// TODO implement with some settings
|
||||
}
|
||||
|
||||
private fun PrettyPrinter.renderSimpleFunction(simpleFunction: FirSimpleFunction) {
|
||||
renderAnnotationsAndModifiers(simpleFunction)
|
||||
append("fun ")
|
||||
renderTypeParameters(simpleFunction)
|
||||
renderReceiver(simpleFunction)
|
||||
renderName(simpleFunction)
|
||||
renderValueParameters(simpleFunction)
|
||||
|
||||
val returnType = simpleFunction.returnTypeRef
|
||||
if (options.renderUnitReturnType || !returnType.isUnit) {
|
||||
append(": ")
|
||||
renderType(returnType, approximate = options.approximateTypes)
|
||||
append(' ')
|
||||
}
|
||||
|
||||
renderWhereSuffix(simpleFunction)
|
||||
renderFunctionBody(simpleFunction)
|
||||
}
|
||||
|
||||
private fun PrettyPrinter.renderAnonymousObject(anonymousObject: FirAnonymousObject) {
|
||||
renderAnnotationsAndModifiers(anonymousObject)
|
||||
append("object ")
|
||||
renderSuperTypes(anonymousObject)
|
||||
renderClassBody(anonymousObject)
|
||||
}
|
||||
|
||||
private fun PrettyPrinter.renderClassBody(firClass: FirClass) {
|
||||
if (!options.renderClassMembers) return
|
||||
if (firClass.declarations.isEmpty()) return
|
||||
|
||||
val allDeclarations = buildList {
|
||||
firClass.declarations.filterNotTo(this) { member ->
|
||||
member.isDefaultPrimaryConstructor()
|
||||
|| member.isDefaultEnumEntryMember(firClass)
|
||||
|| member is FirConstructor && firClass.classKind == ClassKind.OBJECT
|
||||
}
|
||||
addAll(firClass.generatedNestedClassifiers(useSiteSession))
|
||||
addAll(firClass.generatedMembers(useSiteSession))
|
||||
}.filterIsInstance<FirMemberDeclaration>()
|
||||
if (allDeclarations.isEmpty()) return
|
||||
|
||||
val (enumEntries, nonEnumEntries) = allDeclarations.partition { it is FirEnumEntry }
|
||||
withIndentInBraces {
|
||||
printCollection(sortDeclarations(enumEntries), separator = ",\n") { declaration ->
|
||||
renderMemberDeclaration(declaration)
|
||||
}
|
||||
|
||||
if (enumEntries.isNotEmpty() && nonEnumEntries.isNotEmpty()) {
|
||||
appendLine(";\n")
|
||||
}
|
||||
|
||||
printCollection(sortDeclarations(nonEnumEntries), separator = "\n\n") { declaration ->
|
||||
renderMemberDeclaration(declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.appendTabs() = append(tabbedString)
|
||||
private fun PrettyPrinter.renderConstructor(constructor: FirConstructor) {
|
||||
renderAnnotationsAndModifiers(constructor)
|
||||
append("constructor")
|
||||
renderValueParameters(constructor)
|
||||
renderFunctionBody(constructor)
|
||||
}
|
||||
|
||||
private fun underBlockDeclaration(firDeclaration: FirDeclaration, firBlock: FirBlock, data: StringBuilder) {
|
||||
data.underBlockDeclaration(firDeclaration) {
|
||||
firBlock.accept(this, data)
|
||||
private fun PrettyPrinter.renderRegularClass(regularClass: FirRegularClass) {
|
||||
renderAnnotationsAndModifiers(regularClass)
|
||||
renderClassifierKind(regularClass)
|
||||
renderClassName(regularClass)
|
||||
renderTypeParameters(regularClass)
|
||||
printCharIfNotThere(' ')
|
||||
renderSuperTypes(regularClass)
|
||||
renderWhereSuffix(regularClass)
|
||||
renderClassBody(regularClass)
|
||||
}
|
||||
|
||||
private fun PrettyPrinter.renderClassName(regularClass: FirRegularClass) {
|
||||
if (!regularClass.isCompanion) {
|
||||
renderName(regularClass)
|
||||
} else {
|
||||
if (regularClass.name != SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT) {
|
||||
append(regularClass.name.render())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitTypeAlias(typeAlias: FirTypeAlias, data: StringBuilder) = with(data) {
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(typeAlias)
|
||||
renderVisibility(typeAlias.visibility)
|
||||
renderMemberModifiers(typeAlias)
|
||||
append("typealias").append(" ")
|
||||
}
|
||||
private fun PrettyPrinter.renderTypeAlias(typeAlias: FirTypeAlias) {
|
||||
renderAnnotationsAndModifiers(typeAlias)
|
||||
append("typealias ")
|
||||
renderName(typeAlias)
|
||||
renderTypeParameters(typeAlias.typeParameters, false)
|
||||
append(" = ").append(renderType(typeAlias.expandedTypeRef))
|
||||
Unit
|
||||
renderTypeParameters(typeAlias)
|
||||
printCharIfNotThere(' ')
|
||||
append("= ")
|
||||
renderType(typeAlias.expandedTypeRef)
|
||||
}
|
||||
|
||||
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: StringBuilder) {
|
||||
with(data) {
|
||||
appendLine()
|
||||
appendTabs()
|
||||
renderName(enumEntry)
|
||||
}
|
||||
private fun PrettyPrinter.renderEnumEntry(enumEntry: FirEnumEntry) {
|
||||
renderName(enumEntry)
|
||||
}
|
||||
|
||||
override fun visitElement(element: FirElement, data: StringBuilder) {
|
||||
element.acceptChildren(this, data)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun render(
|
||||
firDeclaration: FirDeclaration,
|
||||
containingDeclaration: FirDeclaration?,
|
||||
options: KtDeclarationRendererOptions,
|
||||
session: FirSession
|
||||
): String {
|
||||
val renderer = FirIdeRenderer(
|
||||
containingDeclaration,
|
||||
options,
|
||||
session,
|
||||
)
|
||||
return buildString {
|
||||
firDeclaration.accept(renderer, this)
|
||||
}.trim(' ', '\n', '\t')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* TYPE PARAMETERS */
|
||||
private fun StringBuilder.renderTypeParameter(typeParameter: FirTypeParameter, topLevel: Boolean) {
|
||||
if (topLevel) {
|
||||
append("<")
|
||||
}
|
||||
|
||||
renderModifier(typeParameter.isReified, "reified")
|
||||
private fun PrettyPrinter.renderTypeParameter(typeParameter: FirTypeParameter) {
|
||||
renderIf(typeParameter.isReified, "reified")
|
||||
val variance = typeParameter.variance.label
|
||||
renderModifier(variance.isNotEmpty(), variance)
|
||||
renderIf(variance.isNotEmpty(), variance)
|
||||
renderAnnotations(typeParameter)
|
||||
renderName(typeParameter)
|
||||
|
||||
val upperBoundsCount = typeParameter.bounds.size
|
||||
if ((upperBoundsCount > 1 && !topLevel) || upperBoundsCount == 1) {
|
||||
if (upperBoundsCount >= 1) {
|
||||
val upperBound = typeParameter.bounds.first()
|
||||
if (!upperBound.isNullableAny) {
|
||||
append(" : ").append(renderType(upperBound))
|
||||
append(" : ")
|
||||
renderType(upperBound)
|
||||
}
|
||||
} else if (topLevel) {
|
||||
typeParameter.bounds.filterNot { it.isNullableAny }.forEachIndexed { index, upperBound ->
|
||||
val separator = if (index == 0) " : " else " & "
|
||||
append(separator)
|
||||
append(renderType(upperBound))
|
||||
}
|
||||
} else {
|
||||
// rendered with "where"
|
||||
}
|
||||
|
||||
if (topLevel) {
|
||||
append(">")
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderTypeParameterRefs(typeParameters: List<FirTypeParameterRef>, withSpace: Boolean) =
|
||||
renderTypeParameters(typeParameters.map { it.symbol.fir }, withSpace)
|
||||
|
||||
private fun StringBuilder.renderTypeParameters(typeParameters: List<FirTypeParameter>, withSpace: Boolean) {
|
||||
private fun PrettyPrinter.renderTypeParameters(declaration: FirMemberDeclaration) {
|
||||
val typeParameters = declaration.typeParameters.filterIsInstance<FirTypeParameter>()
|
||||
if (typeParameters.isNotEmpty()) {
|
||||
append("<")
|
||||
renderTypeParameterList(typeParameters)
|
||||
append(">")
|
||||
if (withSpace) {
|
||||
append(" ")
|
||||
printCollection(typeParameters) {
|
||||
renderTypeParameter(it)
|
||||
}
|
||||
append("> ")
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderTypeParameterList(typeParameters: List<FirTypeParameter>) {
|
||||
val iterator = typeParameters.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val firTypeParameter = iterator.next()
|
||||
renderTypeParameter(firTypeParameter, false)
|
||||
if (iterator.hasNext()) {
|
||||
append(", ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderReceiver(firCallableDeclaration: FirCallableDeclaration) {
|
||||
private fun PrettyPrinter.renderReceiver(firCallableDeclaration: FirCallableDeclaration) {
|
||||
val receiverType = firCallableDeclaration.receiverTypeRef
|
||||
if (receiverType != null) {
|
||||
if (options.renderDeclarationHeader) {
|
||||
@@ -584,46 +234,42 @@ internal class FirIdeRenderer private constructor(
|
||||
val needBrackets =
|
||||
typeIdeRenderer.shouldRenderAsPrettyFunctionType(receiverType.coneType) && receiverType.isMarkedNullable == true
|
||||
|
||||
val result = renderType(receiverType).applyIf(needBrackets) { "($this)" }
|
||||
|
||||
append(result)
|
||||
if (needBrackets) append('(')
|
||||
renderType(receiverType)
|
||||
if (needBrackets) append(')')
|
||||
append(".")
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderWhereSuffix(typeParameters: List<FirTypeParameterRef>) {
|
||||
|
||||
private fun PrettyPrinter.renderWhereSuffix(declaration: FirTypeParameterRefsOwner) {
|
||||
val upperBoundStrings = ArrayList<String>(0)
|
||||
|
||||
for (typeParameter in typeParameters) {
|
||||
val typeParameterFir = typeParameter.symbol.fir
|
||||
typeParameterFir.bounds
|
||||
for (typeParameter in declaration.typeParameters) {
|
||||
if (typeParameter !is FirTypeParameter) continue
|
||||
typeParameter.bounds
|
||||
.drop(1) // first parameter is rendered by renderTypeParameter
|
||||
.mapTo(upperBoundStrings) { typeParameterFir.name.render() + " : " + renderType(it) }
|
||||
.mapTo(upperBoundStrings) { typeParameter.name.render() + " : " + renderTypeToString(it.coneType) }
|
||||
}
|
||||
|
||||
if (upperBoundStrings.isNotEmpty()) {
|
||||
append(" where ")
|
||||
append("where ")
|
||||
upperBoundStrings.joinTo(this, ", ")
|
||||
append(' ')
|
||||
}
|
||||
}
|
||||
|
||||
/* VARIABLES */
|
||||
private fun StringBuilder.renderValueParameters(valueParameters: List<FirValueParameter>) {
|
||||
append("(")
|
||||
valueParameters.forEachIndexed { index, valueParameter ->
|
||||
if (index != 0) append(", ")
|
||||
renderValueParameter(valueParameter)
|
||||
private fun PrettyPrinter.renderValueParameters(function: FirFunction) {
|
||||
printCollection(function.valueParameters, prefix = "(", postfix = ")") {
|
||||
renderValueParameter(it)
|
||||
}
|
||||
append(")")
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderValueParameter(valueParameter: FirValueParameter) {
|
||||
private fun PrettyPrinter.renderValueParameter(valueParameter: FirValueParameter) {
|
||||
if (options.renderDeclarationHeader) {
|
||||
renderAnnotations(valueParameter)
|
||||
}
|
||||
renderModifier(valueParameter.isCrossinline, "crossinline")
|
||||
renderModifier(valueParameter.isNoinline, "noinline")
|
||||
renderIf(valueParameter.isCrossinline, "crossinline")
|
||||
renderIf(valueParameter.isNoinline, "noinline")
|
||||
renderVariable(valueParameter)
|
||||
|
||||
if (options.renderDefaultParameterValue) {
|
||||
@@ -634,48 +280,27 @@ internal class FirIdeRenderer private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderValVarPrefix(variable: FirVariable, isInPrimaryConstructor: Boolean = false) {
|
||||
private fun PrettyPrinter.renderValVarPrefix(variable: FirVariable, isInPrimaryConstructor: Boolean = false) {
|
||||
if (!isInPrimaryConstructor || variable !is FirValueParameter) {
|
||||
append(if (variable.isVar) "var" else "val").append(" ")
|
||||
append(if (variable.isVar) "var" else "val")
|
||||
append(' ')
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderVariable(variable: FirVariable) {
|
||||
val typeToRender = variable.returnTypeRef
|
||||
private fun PrettyPrinter.renderVariable(variable: FirVariable) {
|
||||
val typeToRender = variable.returnTypeRef.coneType
|
||||
val isVarArg = (variable as? FirValueParameter)?.isVararg ?: false
|
||||
renderModifier(isVarArg, "vararg")
|
||||
renderIf(isVarArg, "vararg")
|
||||
renderName(variable)
|
||||
append(": ")
|
||||
val parameterType = typeToRender.coneType
|
||||
if (isVarArg) {
|
||||
append(renderType(parameterType.arrayElementType() ?: parameterType))
|
||||
renderType(typeToRender.arrayElementType() ?: typeToRender)
|
||||
} else {
|
||||
append(renderType(typeToRender))
|
||||
renderType(typeToRender)
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderSuperTypes(klass: FirClass) {
|
||||
|
||||
if (klass.defaultType().isNothing) return
|
||||
|
||||
val supertypes = klass.superTypeRefs.applyIf(klass.classKind == ClassKind.ENUM_CLASS) {
|
||||
filterNot {
|
||||
(it as? FirResolvedTypeRef)?.coneType?.classId == StandardClassIds.Enum
|
||||
}
|
||||
}.applyIf(klass.classKind == ClassKind.ANNOTATION_CLASS) {
|
||||
filterNot {
|
||||
(it as? FirResolvedTypeRef)?.coneType?.classId == StandardClassIds.Annotation
|
||||
}
|
||||
}
|
||||
|
||||
if (supertypes.isEmpty() || klass.superTypeRefs.singleOrNull()?.let { it.isAny || it.isNullableAny } == true) return
|
||||
|
||||
tabRightBySpace()
|
||||
append(": ")
|
||||
supertypes.joinTo(this, ", ") { renderType(it) }
|
||||
}
|
||||
|
||||
fun sortDeclarations(declarations: List<FirDeclaration>): List<FirDeclaration> {
|
||||
fun sortDeclarations(declarations: List<FirMemberDeclaration>): List<FirMemberDeclaration> {
|
||||
if (!options.sortNestedDeclarations) return declarations
|
||||
|
||||
fun getDeclarationKind(declaration: FirDeclaration): Int = when (declaration) {
|
||||
@@ -697,34 +322,43 @@ internal class FirIdeRenderer private constructor(
|
||||
return@Comparator nameResult
|
||||
}
|
||||
|
||||
val leftString = StringBuilder().also { builder -> left.accept(this, builder) }.toString()
|
||||
val rightString = StringBuilder().also { builder -> right.accept(this, builder) }.toString()
|
||||
val leftString = prettyPrint { renderMemberDeclaration(left) }
|
||||
val rightString = prettyPrint { renderMemberDeclaration(right) }
|
||||
return@Comparator leftString.compareTo(rightString)
|
||||
})
|
||||
}
|
||||
|
||||
private fun getClassifierKindPrefix(classifier: FirDeclaration): String = when (classifier) {
|
||||
is FirTypeAlias -> "typealias"
|
||||
is FirRegularClass ->
|
||||
if (classifier.isCompanion) {
|
||||
"companion object"
|
||||
} else {
|
||||
when (classifier.classKind) {
|
||||
ClassKind.CLASS -> "class"
|
||||
ClassKind.INTERFACE -> "interface"
|
||||
ClassKind.ENUM_CLASS -> "enum class"
|
||||
ClassKind.OBJECT -> "object"
|
||||
ClassKind.ANNOTATION_CLASS -> "annotation class"
|
||||
ClassKind.ENUM_ENTRY -> "enum entry"
|
||||
}
|
||||
}
|
||||
is FirAnonymousObject -> "object"
|
||||
is FirEnumEntry -> "enum entry"
|
||||
else ->
|
||||
throw AssertionError("Unexpected classifier: $classifier")
|
||||
}
|
||||
|
||||
private fun StringBuilder.tabRightBySpace() {
|
||||
if (length == 0 || last() != ' ') append(' ')
|
||||
companion object {
|
||||
fun render(
|
||||
firDeclaration: FirMemberDeclaration,
|
||||
options: KtDeclarationRendererOptions,
|
||||
session: FirSession
|
||||
): String {
|
||||
val renderer = FirIdeRenderer(options, session)
|
||||
return prettyPrint {
|
||||
with(renderer) { renderMemberDeclaration(firDeclaration) }
|
||||
}.trim { it.isWhitespace() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun FirDeclaration.isDefaultEnumEntryMember(firClass: FirClass): Boolean {
|
||||
if (firClass.classKind != ClassKind.ENUM_CLASS) return false
|
||||
if (this is FirConstructor) return isPrimary && valueParameters.isEmpty()
|
||||
if (this !is FirSimpleFunction) return false
|
||||
|
||||
if (name == StandardNames.ENUM_VALUES && valueParameters.isEmpty()) return true
|
||||
|
||||
if (name == StandardNames.ENUM_VALUE_OF) {
|
||||
return valueParameters.singleOrNull()?.returnTypeRef?.isString == true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun FirDeclaration.isDefaultPrimaryConstructor() =
|
||||
this is FirConstructor &&
|
||||
isPrimary &&
|
||||
valueParameters.isEmpty() &&
|
||||
!hasBody &&
|
||||
visibility == Visibilities.DEFAULT_VISIBILITY
|
||||
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.api.fir.renderer
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
|
||||
import org.jetbrains.kotlin.analysis.api.components.RendererModifier
|
||||
import org.jetbrains.kotlin.analysis.api.fir.types.PublicTypeApproximator
|
||||
import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
||||
import org.jetbrains.kotlin.fir.containingClass
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.*
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.resolve.toFirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.applyIf
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
|
||||
|
||||
internal abstract class FirIdeRendererBase(
|
||||
protected val options: KtDeclarationRendererOptions,
|
||||
protected val useSiteSession: FirSession,
|
||||
) {
|
||||
protected val typeIdeRenderer: ConeTypeIdeRenderer = ConeTypeIdeRenderer(useSiteSession, options.typeRendererOptions)
|
||||
|
||||
protected fun PrettyPrinter.renderAnnotations(declaration: FirDeclaration) {
|
||||
if (RendererModifier.ANNOTATIONS in options.modifiers) {
|
||||
val isSingleLineAnnotations = declaration is FirValueParameter || declaration is FirTypeParameter
|
||||
renderAnnotations(typeIdeRenderer, declaration.annotations, useSiteSession, isSingleLineAnnotations)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun renderTypeToString(type: ConeTypeProjection): String {
|
||||
return typeIdeRenderer.renderType(type)
|
||||
}
|
||||
|
||||
protected fun PrettyPrinter.renderType(type: ConeTypeProjection) {
|
||||
append(renderTypeToString(type))
|
||||
}
|
||||
|
||||
protected fun PrettyPrinter.renderType(firRef: FirTypeRef, approximate: Boolean = false) {
|
||||
val coneType = firRef.coneType
|
||||
val approximatedIfNeeded = approximate.ifTrue {
|
||||
PublicTypeApproximator.approximateTypeToPublicDenotable(coneType, useSiteSession, approximateLocalTypes = true)
|
||||
} ?: coneType
|
||||
renderType(approximatedIfNeeded)
|
||||
}
|
||||
|
||||
protected fun PrettyPrinter.renderName(declaration: FirDeclaration) {
|
||||
if (declaration is FirAnonymousObject) {
|
||||
append("<no name provided>")
|
||||
return
|
||||
}
|
||||
val name = when (declaration) {
|
||||
is FirRegularClass -> declaration.name
|
||||
is FirSimpleFunction -> declaration.name
|
||||
is FirProperty -> declaration.name
|
||||
is FirValueParameter -> declaration.name
|
||||
is FirTypeParameter -> declaration.name
|
||||
is FirTypeAlias -> declaration.name
|
||||
is FirEnumEntry -> declaration.name
|
||||
else -> TODO("Unexpected declaration ${declaration::class.qualifiedName}")
|
||||
}
|
||||
append(name.render())
|
||||
}
|
||||
|
||||
private fun PrettyPrinter.renderVisibility(declaration: FirMemberDeclaration) {
|
||||
if (declaration is FirConstructor && declaration.containingClass()?.toFirRegularClassSymbol(useSiteSession)?.isEnumClass == true) {
|
||||
return
|
||||
}
|
||||
val visibility = declaration.visibility
|
||||
if (RendererModifier.VISIBILITY !in options.modifiers) return
|
||||
|
||||
val currentVisibility = when (visibility) {
|
||||
Visibilities.Local -> Visibilities.Public
|
||||
Visibilities.PrivateToThis -> Visibilities.Public
|
||||
Visibilities.InvisibleFake -> Visibilities.Public
|
||||
Visibilities.Inherited -> Visibilities.Public
|
||||
Visibilities.Unknown -> Visibilities.Public
|
||||
else -> visibility
|
||||
}.applyIf(options.normalizedVisibilities) {
|
||||
normalize()
|
||||
}
|
||||
|
||||
if (currentVisibility == Visibilities.DEFAULT_VISIBILITY) return
|
||||
append(currentVisibility.internalDisplayName)
|
||||
append(' ')
|
||||
}
|
||||
|
||||
private fun PrettyPrinter.renderModality(memberDeclaration: FirMemberDeclaration) {
|
||||
val modality = memberDeclaration.modality ?: return
|
||||
if ((memberDeclaration as? FirRegularClass)?.isInterface == true) return
|
||||
if (modality == Modality.FINAL) return
|
||||
if (memberDeclaration.getContainingClassSymbol(useSiteSession)?.classKind == ClassKind.INTERFACE) return
|
||||
if (memberDeclaration.isOverride) return
|
||||
renderIf(RendererModifier.MODALITY in options.modifiers, modality.name.toLowerCaseAsciiOnly())
|
||||
}
|
||||
|
||||
|
||||
private fun PrettyPrinter.renderOverride(callableMember: FirMemberDeclaration) {
|
||||
if (RendererModifier.OVERRIDE !in options.modifiers) return
|
||||
renderIf(callableMember.isOverride || options.forceRenderingOverrideModifier, "override")
|
||||
}
|
||||
|
||||
protected fun PrettyPrinter.renderIf(value: Boolean, text: String) {
|
||||
if (value) {
|
||||
append(text)
|
||||
append(" ")
|
||||
}
|
||||
}
|
||||
|
||||
protected fun PrettyPrinter.renderAnnotationsAndModifiers(declaration: FirMemberDeclaration) {
|
||||
if (!options.renderDeclarationHeader) return
|
||||
renderAnnotations(declaration)
|
||||
renderVisibility(declaration)
|
||||
renderOverride(declaration)
|
||||
renderModality(declaration)
|
||||
renderIf(declaration.isExternal, "external")
|
||||
renderIf(RendererModifier.EXPECT in options.modifiers && declaration.isExpect, "expect")
|
||||
renderIf(RendererModifier.ACTUAL in options.modifiers && declaration.isActual, "actual")
|
||||
renderIf(declaration.isTailRec, "tailrec")
|
||||
renderIf(declaration.isConst, "const")
|
||||
renderIf(declaration.isInner, "inner")
|
||||
renderIf(declaration.isLateInit, "lateinit")
|
||||
renderIf(declaration.isSuspend, "suspend")
|
||||
renderIf(declaration.isInline, "inline")
|
||||
renderIf(declaration.isInfix, "infix")
|
||||
renderIf(RendererModifier.OPERATOR in options.modifiers && declaration.isOperator, "operator")
|
||||
}
|
||||
|
||||
protected fun PrettyPrinter.renderClassifierKind(classifier: FirDeclaration) {
|
||||
when (classifier) {
|
||||
is FirTypeAlias -> append("typealias")
|
||||
is FirRegularClass ->
|
||||
append(if (classifier.isCompanion) "companion object" else classifier.classKind.codeRepresentation)
|
||||
is FirAnonymousObject -> append("object")
|
||||
is FirEnumEntry -> append("enum entry")
|
||||
else ->
|
||||
throw AssertionError("Unexpected classifier: $classifier")
|
||||
}
|
||||
append(' ')
|
||||
}
|
||||
|
||||
|
||||
protected fun PrettyPrinter.renderSuperTypes(klass: FirClass) {
|
||||
if (klass.defaultType().isNothing) return
|
||||
|
||||
val supertypes = klass.superTypeRefs.asSequence()
|
||||
.applyIf(klass.classKind == ClassKind.ENUM_CLASS) {
|
||||
filterNot {
|
||||
it.coneType.classId == StandardClassIds.Enum
|
||||
}
|
||||
}.applyIf(klass.classKind == ClassKind.ANNOTATION_CLASS) {
|
||||
filterNot {
|
||||
it.coneType.classId == StandardClassIds.Annotation
|
||||
}
|
||||
}.toList()
|
||||
|
||||
if (supertypes.isEmpty() || klass.superTypeRefs.singleOrNull()?.isAny == true) return
|
||||
|
||||
append(": ")
|
||||
printCollection(supertypes) {
|
||||
renderType(it)
|
||||
}
|
||||
append(' ')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ dependencies {
|
||||
api(project(":analysis:analysis-api"))
|
||||
api(project(":analysis:analysis-api-impl-barebone"))
|
||||
api(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) }
|
||||
implementation(project(":analysis:analysis-internal-utils"))
|
||||
|
||||
testApiJUnit5()
|
||||
testApi(project(":kotlin-test:kotlin-test-junit"))
|
||||
|
||||
+7
-4
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.analysis.api.components.KtDeclarationRendererOptions
|
||||
import org.jetbrains.kotlin.analysis.api.components.KtTypeRendererOptions
|
||||
import org.jetbrains.kotlin.analysis.api.impl.barebone.test.FrontendApiTestConfiguratorService
|
||||
import org.jetbrains.kotlin.analysis.api.impl.base.test.test.framework.AbstractHLApiSingleFileTest
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.test.model.TestModule
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
@@ -18,16 +19,18 @@ abstract class AbstractRendererTest(configurator: FrontendApiTestConfiguratorSer
|
||||
override fun doTestByFileStructure(ktFile: KtFile, module: TestModule, testServices: TestServices) {
|
||||
val options = KtDeclarationRendererOptions.DEFAULT.copy(
|
||||
approximateTypes = true,
|
||||
renderContainingDeclarations = true,
|
||||
renderClassMembers = true,
|
||||
typeRendererOptions = KtTypeRendererOptions.SHORT_NAMES,
|
||||
sortNestedDeclarations = true
|
||||
)
|
||||
|
||||
val actual = executeOnPooledThreadInReadAction {
|
||||
buildString {
|
||||
ktFile.declarations.forEach {
|
||||
analyseForTest(it) {
|
||||
append(it.getSymbol().render(options))
|
||||
ktFile.declarations.forEach { declaration ->
|
||||
analyseForTest(declaration) {
|
||||
val symbol = declaration.getSymbol() as? KtPossibleMemberSymbol ?: return@analyseForTest
|
||||
append(symbol.render(options))
|
||||
appendLine()
|
||||
appendLine()
|
||||
}
|
||||
}
|
||||
|
||||
+6
-5
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.analysis.api.components
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.markers.KtPossibleMemberSymbol
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtType
|
||||
|
||||
/**
|
||||
@@ -68,9 +69,9 @@ public data class KtDeclarationRendererOptions(
|
||||
*/
|
||||
val normalizedVisibilities: Boolean = false,
|
||||
/**
|
||||
* Render containing declarations
|
||||
* Render members of a classes and objects if any
|
||||
*/
|
||||
val renderContainingDeclarations: Boolean = false,
|
||||
val renderClassMembers: Boolean = false,
|
||||
/**
|
||||
* Approximate Kotlin not-denotable types into denotable for declarations return type
|
||||
*/
|
||||
@@ -124,7 +125,7 @@ public enum class RendererModifier(public val includeByDefault: Boolean) {
|
||||
}
|
||||
|
||||
public abstract class KtSymbolDeclarationRendererProvider : KtAnalysisSessionComponent() {
|
||||
public abstract fun render(symbol: KtSymbol, options: KtDeclarationRendererOptions): String
|
||||
public abstract fun renderMember(symbol: KtPossibleMemberSymbol, options: KtDeclarationRendererOptions): String
|
||||
public abstract fun render(type: KtType, options: KtTypeRendererOptions): String
|
||||
}
|
||||
|
||||
@@ -135,8 +136,8 @@ public interface KtSymbolDeclarationRendererMixIn : KtAnalysisSessionMixIn {
|
||||
/**
|
||||
* Render symbol into the representable Kotlin string
|
||||
*/
|
||||
public fun KtSymbol.render(options: KtDeclarationRendererOptions = KtDeclarationRendererOptions.DEFAULT): String =
|
||||
analysisSession.symbolDeclarationRendererProvider.render(this, options)
|
||||
public fun KtPossibleMemberSymbol.render(options: KtDeclarationRendererOptions = KtDeclarationRendererOptions.DEFAULT): String =
|
||||
analysisSession.symbolDeclarationRendererProvider.renderMember(this, options)
|
||||
|
||||
/**
|
||||
* Render kotlin type into the representable Kotlin type string
|
||||
|
||||
@@ -42,6 +42,7 @@ val FirTypeRef.isNullableNothing: Boolean get() = isBuiltinType(StandardClassIds
|
||||
val FirTypeRef.isUnit: Boolean get() = isBuiltinType(StandardClassIds.Unit, false)
|
||||
val FirTypeRef.isBoolean: Boolean get() = isBuiltinType(StandardClassIds.Boolean, false)
|
||||
val FirTypeRef.isInt: Boolean get() = isBuiltinType(StandardClassIds.Int, false)
|
||||
val FirTypeRef.isString: Boolean get() = isBuiltinType(StandardClassIds.String, false)
|
||||
val FirTypeRef.isEnum: Boolean get() = isBuiltinType(StandardClassIds.Enum, false)
|
||||
val FirTypeRef.isArrayType: Boolean
|
||||
get() =
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package org.jetbrains.kotlin.descriptors
|
||||
|
||||
enum class ClassKind {
|
||||
CLASS,
|
||||
INTERFACE,
|
||||
ENUM_CLASS,
|
||||
ENUM_ENTRY,
|
||||
ANNOTATION_CLASS,
|
||||
OBJECT;
|
||||
enum class ClassKind(val codeRepresentation: String?) {
|
||||
CLASS( "class"),
|
||||
INTERFACE("interface"),
|
||||
ENUM_CLASS( "enum class"),
|
||||
ENUM_ENTRY( null),
|
||||
ANNOTATION_CLASS( "annotation class"),
|
||||
OBJECT("object");
|
||||
|
||||
val isSingleton: Boolean
|
||||
get() = this == OBJECT || this == ENUM_ENTRY
|
||||
|
||||
Reference in New Issue
Block a user