From 6fa7435cd438e06fd2c0cb0a65d660e3d5c2cbb6 Mon Sep 17 00:00:00 2001 From: Ivan Cilcic Date: Sun, 11 Aug 2019 17:28:08 +0300 Subject: [PATCH] Add additional options to DescriptorRender 1) renderContextNearLocalVariable - if true renderer add fq name for local variables after "@" symbol 2) fullContextForLocalVariable - if true then renderer add all fq names for local variables, else only last one 3) useBaseClassAsReceiver - if true then renderer uses dispatch receiver as extension receiver if the last is null --- .../kotlin/compiler/visualizer/PsiRenderer.kt | 97 +++++++++++++++---- .../kotlin/renderer/DescriptorRenderer.kt | 4 + .../kotlin/renderer/DescriptorRendererImpl.kt | 23 ++++- .../renderer/DescriptorRendererOptionsImpl.kt | 4 + 4 files changed, 108 insertions(+), 20 deletions(-) diff --git a/compiler/visualizer/render-psi/src/org/jetbrains/kotlin/compiler/visualizer/PsiRenderer.kt b/compiler/visualizer/render-psi/src/org/jetbrains/kotlin/compiler/visualizer/PsiRenderer.kt index 54862f82ea0..730987204e3 100644 --- a/compiler/visualizer/render-psi/src/org/jetbrains/kotlin/compiler/visualizer/PsiRenderer.kt +++ b/compiler/visualizer/render-psi/src/org/jetbrains/kotlin/compiler/visualizer/PsiRenderer.kt @@ -5,21 +5,22 @@ package org.jetbrains.kotlin.compiler.visualizer +import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import org.jetbrains.kotlin.analyzer.AnalysisResult +import org.jetbrains.kotlin.builtins.* import org.jetbrains.kotlin.compiler.visualizer.Annotator.annotate -import org.jetbrains.kotlin.descriptors.VariableDescriptor +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.renderer.ClassifierNamePolicy import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.render -import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext.* -import org.jetbrains.kotlin.resolve.DescriptorUtils -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe +import org.jetbrains.kotlin.resolve.calls.callUtil.getCall +import org.jetbrains.kotlin.types.* -class PsiRenderer(private val file: KtFile, analysisResult: AnalysisResult): BaseRenderer { +class PsiRenderer(private val file: KtFile, analysisResult: AnalysisResult) : BaseRenderer { val bindingContext = analysisResult.bindingContext private val annotations = mutableListOf() @@ -31,6 +32,14 @@ class PsiRenderer(private val file: KtFile, analysisResult: AnalysisResult): Bas withSourceFileForTopLevel = false renderConstructorKeyword = false classifierNamePolicy = ClassifierNamePolicy.SOURCE_CODE_QUALIFIED + includeAdditionalModifiers = false + renderContextNearLocalVariable = true + fullContextForLocalVariable = false + useBaseClassAsReceiver = true + } + + private fun addAnnotation(text: String, range: TextRange) { + annotations.add(Annotator.AnnotationInfo(text, range)) } override fun render(): String { @@ -39,6 +48,18 @@ class PsiRenderer(private val file: KtFile, analysisResult: AnalysisResult): Bas } inner class Renderer : KtVisitorVoid() { + private fun renderType(type: KotlinType?): String { + return type?.let { descriptorRenderer.renderType(it) } ?: "[ERROR: unknown type]" + } + + private fun renderType(descriptor: CallableDescriptor?): String { + return renderType(descriptor?.returnType) + } + + private fun renderType(expression: KtExpression?): String { + return renderType(expression?.let { bindingContext.getType(it) }) + } + override fun visitElement(element: PsiElement) { element.acceptChildren(this) } @@ -47,27 +68,67 @@ class PsiRenderer(private val file: KtFile, analysisResult: AnalysisResult): Bas element.acceptChildren(this) } - override fun visitProperty(property: KtProperty) { - val descriptor = bindingContext[VARIABLE, property] - annotations.add(Annotator.AnnotationInfo(descriptor?.returnType.toString(), property.nameIdentifier!!.textRange)) - super.visitProperty(property) + private fun renderVariableType(variable: KtVariableDeclaration) { + val descriptor = bindingContext[VARIABLE, variable] + addAnnotation(renderType(descriptor), variable.nameIdentifier!!.textRange) + variable.acceptChildren(this) + } + + override fun visitProperty(property: KtProperty) = + renderVariableType(property) + + override fun visitDestructuringDeclarationEntry(multiDeclarationEntry: KtDestructuringDeclarationEntry) = + renderVariableType(multiDeclarationEntry) + + override fun visitTypeReference(typeReference: KtTypeReference) { + val type = bindingContext[TYPE, typeReference] + addAnnotation(renderType(type), typeReference.textRange) } override fun visitConstantExpression(expression: KtConstantExpression) { - val type = bindingContext.getType(expression) - annotations.add(Annotator.AnnotationInfo(type.toString(), expression.textRange)) + addAnnotation(renderType(expression), expression.textRange) + } + + private fun renderCall(call: Call): String { + val resolvedCall = bindingContext[RESOLVED_CALL, call] ?: return "[ERROR: not resolved]" + + val descriptor = resolvedCall.resultingDescriptor + var annotation = descriptorRenderer.render(descriptor) + if (descriptor.name.asString() == "") annotation = annotation.replace("(", "(") + resolvedCall.typeArguments.forEach { (type, value) -> + annotation = annotation.replaceFirst(type.name.toString(), "$value") + } + return annotation } override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { - val resolvedCall = bindingContext[RESOLVED_CALL, bindingContext[CALL, expression]] - if (resolvedCall == null || resolvedCall.resultingDescriptor == null) { + val call = expression.getCall(bindingContext) + if (call != null) { + addAnnotation(renderCall(call), expression.textRange) super.visitSimpleNameExpression(expression) - return + } else { + val qualifierDescriptor = bindingContext[QUALIFIER, expression]?.descriptor + if (qualifierDescriptor != null) { + addAnnotation(descriptorRenderer.render(qualifierDescriptor), expression.textRange) + } } + } - val annotation = descriptorRenderer.render(resolvedCall.resultingDescriptor) - val fqName = DescriptorUtils.getFqName(resolvedCall.resultingDescriptor.containingDeclaration) - annotations.add(Annotator.AnnotationInfo("$fqName.$annotation", expression.textRange)) + override fun visitIfExpression(expression: KtIfExpression) { + addAnnotation(renderType(expression), expression.ifKeyword.textRange) + super.visitIfExpression(expression) + } + + override fun visitWhenExpression(expression: KtWhenExpression) { + addAnnotation(renderType(expression), expression.whenKeyword.textRange) + super.visitWhenExpression(expression) + } + + override fun visitWhenEntry(jetWhenEntry: KtWhenEntry) { + val arrowTextRange = jetWhenEntry.expression?.textRange?.shiftLeft(3) + ?: jetWhenEntry.conditions.last().textRange.shiftRight(3) + addAnnotation(renderType(jetWhenEntry.expression), arrowTextRange) + super.visitWhenEntry(jetWhenEntry) } } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt index ee78e44e10f..3d34192839f 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt @@ -246,6 +246,10 @@ interface DescriptorRendererOptions { var parameterNamesInFunctionalTypes: Boolean var renderFunctionContracts: Boolean var presentableUnresolvedTypes: Boolean + + var renderContextNearLocalVariable: Boolean + var fullContextForLocalVariable: Boolean + var useBaseClassAsReceiver: Boolean } object ExcludedTypeAnnotations { diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt index 9aff880f081..884f12d48b3 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt @@ -106,6 +106,17 @@ internal class DescriptorRendererImpl( private fun renderFqName(pathSegments: List) = escape(org.jetbrains.kotlin.renderer.renderFqName(pathSegments)) + private fun renderFqNameForLocalVariables(fqName: FqNameUnsafe): String = + if (fqName.isRoot) { + "" + } else { + if (fullContextForLocalVariable) { + renderFqName(fqName) + } else { + renderFqName(fqName).substringAfterLast(".") + } + }.replace(".", "/") + override fun renderClassifierName(klass: ClassifierDescriptor): String = if (ErrorUtils.isError(klass)) { klass.typeConstructor.toString() } else @@ -709,6 +720,8 @@ internal class DescriptorRendererImpl( private fun renderReceiver(callableDescriptor: CallableDescriptor, builder: StringBuilder) { val receiver = callableDescriptor.extensionReceiverParameter + ?: (if (useBaseClassAsReceiver) callableDescriptor.dispatchReceiverParameter else null) + val extensionIsNull = callableDescriptor.extensionReceiverParameter == null if (receiver != null) { builder.renderAnnotations(receiver, AnnotationUseSiteTarget.RECEIVER) @@ -717,7 +730,8 @@ internal class DescriptorRendererImpl( if (shouldRenderAsPrettyFunctionType(type) && !TypeUtils.isNullableType(type)) { result = "($result)" } - builder.append(result).append(".") + // @ symbol is used to distinguish extension receiver from dispatch + builder.append(result).append(if (extensionIsNull) "@" else ".") } } @@ -809,7 +823,7 @@ internal class DescriptorRendererImpl( builder: StringBuilder, topLevel: Boolean ) { - if (topLevel) { + if (topLevel && !renderContextNearLocalVariable) { builder.append(renderKeyword("value-parameter")).append(" ") } @@ -862,6 +876,11 @@ internal class DescriptorRendererImpl( if (includeName) { renderName(variable, builder, topLevel) + if (topLevel && renderContextNearLocalVariable) { + val containingDeclaration = variable.containingDeclaration + val fqName = DescriptorUtils.getFqName(containingDeclaration) + builder.append("@").append(renderFqNameForLocalVariables(fqName)) + } builder.append(": ") } diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt index 8268e8f4056..fbe102b33d9 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererOptionsImpl.kt @@ -127,4 +127,8 @@ internal class DescriptorRendererOptionsImpl : DescriptorRendererOptions { override var presentableUnresolvedTypes: Boolean by property(false) override var boldOnlyForNamesInHtml: Boolean by property(false) + + override var renderContextNearLocalVariable by property(false) + override var fullContextForLocalVariable by property(false) + override var useBaseClassAsReceiver by property(false) }