Micro optimizations to type rendering in DescriptorRendererImpl
Do not create StringBuilder instances when the resulting String will be appended to some other StringBuilder anyway. This, and a couple of micro FqNameUnsafe-related optimizations, helps reduce memory traffic in Kotlin reflection when rendering is involved (toString() is called on reflective objects)
This commit is contained in:
@@ -65,11 +65,11 @@ private val KotlinType.isTypeAnnotatedWithExtensionFunctionType: Boolean
|
|||||||
* e.g. kotlin.Function1 (but NOT kotlin.reflect.KFunction1)
|
* e.g. kotlin.Function1 (but NOT kotlin.reflect.KFunction1)
|
||||||
*/
|
*/
|
||||||
fun isNumberedFunctionClassFqName(fqName: FqNameUnsafe): Boolean {
|
fun isNumberedFunctionClassFqName(fqName: FqNameUnsafe): Boolean {
|
||||||
|
if (!fqName.startsWith(KotlinBuiltIns.BUILT_INS_PACKAGE_NAME)) return false
|
||||||
|
|
||||||
val segments = fqName.pathSegments()
|
val segments = fqName.pathSegments()
|
||||||
if (segments.size != 2) return false
|
if (segments.size != 2) return false
|
||||||
|
|
||||||
if (KotlinBuiltIns.BUILT_INS_PACKAGE_NAME != segments.first()) return false
|
|
||||||
|
|
||||||
val shortName = segments.last().asString()
|
val shortName = segments.last().asString()
|
||||||
return BuiltInFictitiousFunctionClassFactory.isFunctionClassName(shortName, KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
|
return BuiltInFictitiousFunctionClassFactory.isFunctionClassName(shortName, KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,13 +23,21 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like {@link FqName} but allows '<' and '>' characters in name.
|
* Like {@link FqName} but allows '<' and '>' characters in name.
|
||||||
*/
|
*/
|
||||||
public final class FqNameUnsafe {
|
public final class FqNameUnsafe {
|
||||||
|
private static final Name ROOT_NAME = Name.special("<root>");
|
||||||
|
private static final Pattern SPLIT_BY_DOTS = Pattern.compile("\\.");
|
||||||
|
|
||||||
public static final Name ROOT_NAME = Name.special("<root>");
|
private static final Function1<String, Name> STRING_TO_NAME = new Function1<String, Name>() {
|
||||||
|
@Override
|
||||||
|
public Name invoke(String name) {
|
||||||
|
return Name.guessByFirstCharacter(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final String fqName;
|
private final String fqName;
|
||||||
@@ -147,17 +155,12 @@ public final class FqNameUnsafe {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<Name> pathSegments() {
|
public List<Name> pathSegments() {
|
||||||
return isRoot() ? Collections.<Name>emptyList() :
|
return isRoot() ? Collections.<Name>emptyList() : ArraysKt.map(SPLIT_BY_DOTS.split(fqName), STRING_TO_NAME);
|
||||||
ArraysKt.map(fqName.split("\\."), new Function1<String, Name>() {
|
|
||||||
@Override
|
|
||||||
public Name invoke(String name) {
|
|
||||||
return Name.guessByFirstCharacter(name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean startsWith(@NotNull Name segment) {
|
public boolean startsWith(@NotNull Name segment) {
|
||||||
return !isRoot() && pathSegments().get(0).equals(segment);
|
int firstDot = fqName.indexOf('.');
|
||||||
|
return !isRoot() && fqName.regionMatches(0, segment.asString(), 0, firstDot == -1 ? fqName.length() : firstDot);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -118,52 +118,62 @@ internal class DescriptorRendererImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* TYPES RENDERING */
|
/* TYPES RENDERING */
|
||||||
override fun renderType(type: KotlinType): String {
|
override fun renderType(type: KotlinType): String = buildString {
|
||||||
return renderNormalizedType(typeNormalizer(type))
|
renderNormalizedType(typeNormalizer(type))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderNormalizedType(type: KotlinType): String {
|
private fun StringBuilder.renderNormalizedType(type: KotlinType) {
|
||||||
val abbreviated = (type.unwrap() as? AbbreviatedType)
|
val abbreviated = type.unwrap() as? AbbreviatedType
|
||||||
|
|
||||||
if (abbreviated != null) {
|
if (abbreviated != null) {
|
||||||
// TODO nullability is lost for abbreviated type?
|
// TODO nullability is lost for abbreviated type?
|
||||||
val abbreviatedRendered = renderNormalizedTypeAsIs(abbreviated.abbreviation)
|
renderNormalizedTypeAsIs(abbreviated.abbreviation)
|
||||||
if (!renderUnabbreviatedType) return abbreviatedRendered
|
if (renderUnabbreviatedType) {
|
||||||
val unabbreviatedRendered = renderNormalizedTypeAsIs(abbreviated.expandedType)
|
append(" /* = ")
|
||||||
return "$abbreviatedRendered /* = $unabbreviatedRendered */"
|
renderNormalizedTypeAsIs(abbreviated.expandedType)
|
||||||
|
append(" */")
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderNormalizedTypeAsIs(type)
|
renderNormalizedTypeAsIs(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderNormalizedTypeAsIs(type: KotlinType): String {
|
private fun StringBuilder.renderNormalizedTypeAsIs(type: KotlinType) {
|
||||||
if (type is WrappedType && debugMode && !type.isComputed()) {
|
if (type is WrappedType && debugMode && !type.isComputed()) {
|
||||||
return "<Not computed yet>"
|
append("<Not computed yet>")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
val unwrappedType = type.unwrap()
|
val unwrappedType = type.unwrap()
|
||||||
return when (unwrappedType) {
|
when (unwrappedType) {
|
||||||
is FlexibleType -> unwrappedType.render(this, this)
|
is FlexibleType -> append(unwrappedType.render(this@DescriptorRendererImpl, this@DescriptorRendererImpl))
|
||||||
is SimpleType -> renderSimpleType(unwrappedType)
|
is SimpleType -> renderSimpleType(unwrappedType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderSimpleType(type: SimpleType): String {
|
private fun StringBuilder.renderSimpleType(type: SimpleType) {
|
||||||
if (type == CANT_INFER_FUNCTION_PARAM_TYPE || TypeUtils.isDontCarePlaceholder(type)) {
|
if (type == CANT_INFER_FUNCTION_PARAM_TYPE || TypeUtils.isDontCarePlaceholder(type)) {
|
||||||
return "???"
|
append("???")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (ErrorUtils.isUninferredParameter(type)) {
|
if (ErrorUtils.isUninferredParameter(type)) {
|
||||||
if (uninferredTypeParameterAsName) {
|
if (uninferredTypeParameterAsName) {
|
||||||
return renderError((type.constructor as UninferredParameterTypeConstructor).typeParameterDescriptor.name.toString())
|
append(renderError((type.constructor as UninferredParameterTypeConstructor).typeParameterDescriptor.name.toString()))
|
||||||
}
|
}
|
||||||
return "???"
|
else {
|
||||||
|
append("???")
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (type.isError) {
|
if (type.isError) {
|
||||||
return renderDefaultType(type)
|
renderDefaultType(type)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
if (shouldRenderAsPrettyFunctionType(type)) {
|
if (shouldRenderAsPrettyFunctionType(type)) {
|
||||||
return renderFunctionType(type)
|
renderFunctionType(type)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
renderDefaultType(type)
|
||||||
}
|
}
|
||||||
return renderDefaultType(type)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldRenderAsPrettyFunctionType(type: KotlinType): Boolean {
|
private fun shouldRenderAsPrettyFunctionType(type: KotlinType): Boolean {
|
||||||
@@ -200,58 +210,50 @@ internal class DescriptorRendererImpl(
|
|||||||
if (typeArguments.isEmpty()) return ""
|
if (typeArguments.isEmpty()) return ""
|
||||||
return buildString {
|
return buildString {
|
||||||
append(lt())
|
append(lt())
|
||||||
appendTypeProjections(typeArguments, this)
|
this.appendTypeProjections(typeArguments)
|
||||||
append(gt())
|
append(gt())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderDefaultType(type: KotlinType): String {
|
private fun StringBuilder.renderDefaultType(type: KotlinType) {
|
||||||
val sb = StringBuilder()
|
renderAnnotations(type, this)
|
||||||
|
|
||||||
renderAnnotations(type, sb)
|
|
||||||
|
|
||||||
if (type.isError) {
|
if (type.isError) {
|
||||||
sb.append(type.constructor.toString()) // Debug name of an error type is more informative
|
append(type.constructor.toString()) // Debug name of an error type is more informative
|
||||||
sb.append(renderTypeArguments(type.arguments))
|
append(renderTypeArguments(type.arguments))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sb.append(renderTypeConstructorAndArguments(type))
|
renderTypeConstructorAndArguments(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type.isMarkedNullable) {
|
if (type.isMarkedNullable) {
|
||||||
sb.append("?")
|
append("?")
|
||||||
}
|
}
|
||||||
return sb.toString()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderTypeConstructorAndArguments(
|
private fun StringBuilder.renderTypeConstructorAndArguments(
|
||||||
type: KotlinType,
|
type: KotlinType,
|
||||||
typeConstructor: TypeConstructor = type.constructor
|
typeConstructor: TypeConstructor = type.constructor
|
||||||
): String =
|
) {
|
||||||
buildString {
|
val possiblyInnerType = type.buildPossiblyInnerType()
|
||||||
|
if (possiblyInnerType == null) {
|
||||||
val possiblyInnerType = type.buildPossiblyInnerType()
|
append(renderTypeConstructor(typeConstructor))
|
||||||
if (possiblyInnerType == null) {
|
append(renderTypeArguments(type.arguments))
|
||||||
append(renderTypeConstructor(typeConstructor))
|
return
|
||||||
append(renderTypeArguments(type.arguments))
|
|
||||||
return@buildString
|
|
||||||
}
|
|
||||||
|
|
||||||
append(renderPossiblyInnerType(possiblyInnerType))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderPossiblyInnerType(possiblyInnerType: PossiblyInnerType): String =
|
renderPossiblyInnerType(possiblyInnerType)
|
||||||
buildString {
|
}
|
||||||
possiblyInnerType.outerType?.let {
|
|
||||||
append(renderPossiblyInnerType(it))
|
|
||||||
append('.')
|
|
||||||
append(renderName(possiblyInnerType.classifierDescriptor.name))
|
|
||||||
} ?: append(renderTypeConstructor(possiblyInnerType.classifierDescriptor.typeConstructor))
|
|
||||||
|
|
||||||
append(renderTypeArguments(possiblyInnerType.arguments))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private fun StringBuilder.renderPossiblyInnerType(possiblyInnerType: PossiblyInnerType) {
|
||||||
|
possiblyInnerType.outerType?.let {
|
||||||
|
renderPossiblyInnerType(it)
|
||||||
|
append('.')
|
||||||
|
append(renderName(possiblyInnerType.classifierDescriptor.name))
|
||||||
|
} ?: append(renderTypeConstructor(possiblyInnerType.classifierDescriptor.typeConstructor))
|
||||||
|
|
||||||
|
append(renderTypeArguments(possiblyInnerType.arguments))
|
||||||
|
}
|
||||||
|
|
||||||
override fun renderTypeConstructor(typeConstructor: TypeConstructor): String {
|
override fun renderTypeConstructor(typeConstructor: TypeConstructor): String {
|
||||||
val cd = typeConstructor.declarationDescriptor
|
val cd = typeConstructor.declarationDescriptor
|
||||||
@@ -263,10 +265,10 @@ internal class DescriptorRendererImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun renderTypeProjection(typeProjection: TypeProjection) = buildString {
|
override fun renderTypeProjection(typeProjection: TypeProjection) = buildString {
|
||||||
appendTypeProjections(listOf(typeProjection), this)
|
appendTypeProjections(listOf(typeProjection))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun appendTypeProjections(typeProjections: List<TypeProjection>, builder: StringBuilder) {
|
private fun StringBuilder.appendTypeProjections(typeProjections: List<TypeProjection>) {
|
||||||
typeProjections.map {
|
typeProjections.map {
|
||||||
if (it.isStarProjection) {
|
if (it.isStarProjection) {
|
||||||
"*"
|
"*"
|
||||||
@@ -275,52 +277,50 @@ internal class DescriptorRendererImpl(
|
|||||||
val type = renderType(it.type)
|
val type = renderType(it.type)
|
||||||
if (it.projectionKind == Variance.INVARIANT) type else "${it.projectionKind} $type"
|
if (it.projectionKind == Variance.INVARIANT) type else "${it.projectionKind} $type"
|
||||||
}
|
}
|
||||||
}.joinTo(builder, ", ")
|
}.joinTo(this, ", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderFunctionType(type: KotlinType): String {
|
private fun StringBuilder.renderFunctionType(type: KotlinType) {
|
||||||
return buildString {
|
val isNullable = type.isMarkedNullable
|
||||||
val isNullable = type.isMarkedNullable
|
if (isNullable) append("(")
|
||||||
if (isNullable) append("(")
|
|
||||||
|
|
||||||
val receiverType = getReceiverTypeFromFunctionType(type)
|
val receiverType = getReceiverTypeFromFunctionType(type)
|
||||||
if (receiverType != null) {
|
if (receiverType != null) {
|
||||||
val surroundReceiver = shouldRenderAsPrettyFunctionType(receiverType) && !receiverType.isMarkedNullable
|
val surroundReceiver = shouldRenderAsPrettyFunctionType(receiverType) && !receiverType.isMarkedNullable
|
||||||
if (surroundReceiver) {
|
if (surroundReceiver) {
|
||||||
append("(")
|
append("(")
|
||||||
}
|
|
||||||
append(renderNormalizedType(receiverType))
|
|
||||||
if (surroundReceiver) {
|
|
||||||
append(")")
|
|
||||||
}
|
|
||||||
append(".")
|
|
||||||
}
|
}
|
||||||
|
renderNormalizedType(receiverType)
|
||||||
append("(")
|
if (surroundReceiver) {
|
||||||
appendTypeProjections(getValueParameterTypesFromFunctionType(type), this)
|
append(")")
|
||||||
append(") ").append(arrow()).append(" ")
|
}
|
||||||
append(renderNormalizedType(getReturnTypeFromFunctionType(type)))
|
append(".")
|
||||||
|
|
||||||
if (isNullable) append(")?")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
append("(")
|
||||||
|
appendTypeProjections(getValueParameterTypesFromFunctionType(type))
|
||||||
|
append(") ").append(arrow()).append(" ")
|
||||||
|
renderNormalizedType(getReturnTypeFromFunctionType(type))
|
||||||
|
|
||||||
|
if (isNullable) append(")?")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* METHODS FOR ALL KINDS OF DESCRIPTORS */
|
/* METHODS FOR ALL KINDS OF DESCRIPTORS */
|
||||||
private fun appendDefinedIn(descriptor: DeclarationDescriptor, builder: StringBuilder) {
|
private fun StringBuilder.appendDefinedIn(descriptor: DeclarationDescriptor) {
|
||||||
if (descriptor is PackageFragmentDescriptor || descriptor is PackageViewDescriptor) {
|
if (descriptor is PackageFragmentDescriptor || descriptor is PackageViewDescriptor) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (descriptor is ModuleDescriptor) {
|
if (descriptor is ModuleDescriptor) {
|
||||||
builder.append(" is a module")
|
append(" is a module")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val containingDeclaration = descriptor.containingDeclaration
|
val containingDeclaration = descriptor.containingDeclaration
|
||||||
if (containingDeclaration != null && containingDeclaration !is ModuleDescriptor) {
|
if (containingDeclaration != null && containingDeclaration !is ModuleDescriptor) {
|
||||||
builder.append(" ").append(renderMessage("defined in")).append(" ")
|
append(" ").append(renderMessage("defined in")).append(" ")
|
||||||
val fqName = DescriptorUtils.getFqName(containingDeclaration)
|
val fqName = DescriptorUtils.getFqName(containingDeclaration)
|
||||||
builder.append(if (fqName.isRoot) "root package" else renderFqName(fqName))
|
append(if (fqName.isRoot) "root package" else renderFqName(fqName))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private fun renderAnnotations(annotated: Annotated, builder: StringBuilder) {
|
private fun renderAnnotations(annotated: Annotated, builder: StringBuilder) {
|
||||||
@@ -479,7 +479,7 @@ internal class DescriptorRendererImpl(
|
|||||||
declarationDescriptor.accept(RenderDeclarationDescriptorVisitor(), this)
|
declarationDescriptor.accept(RenderDeclarationDescriptorVisitor(), this)
|
||||||
|
|
||||||
if (withDefinedIn) {
|
if (withDefinedIn) {
|
||||||
appendDefinedIn(declarationDescriptor, this)
|
appendDefinedIn(declarationDescriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user