From e4cf09072009d598d7118a86c06e0b8c09e0823d Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Wed, 17 Feb 2016 16:40:55 +0300 Subject: [PATCH] Adjust diagnostics rendering so that short classifier names are rendered unless the name is ambiguous in corresponding RenderingContext --- .../kotlin/diagnostics/rendering/Renderers.kt | 6 +- .../rendering/adaptiveClassifierNamePolicy.kt | 105 ++++++++++++++++++ .../diagnostics/rendering/smartRenderers.kt | 40 +++++++ .../kotlin/renderer/DescriptorRenderer.kt | 2 +- .../kotlin/renderer/DescriptorRendererImpl.kt | 17 ++- .../HtmlTabledDescriptorRenderer.java | 9 +- .../kotlin/idea/highlighter/IdeRenderers.kt | 10 +- 7 files changed, 164 insertions(+), 25 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/adaptiveClassifierNamePolicy.kt create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/smartRenderers.kt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt index 8bfd10ad4e0..0f473086ecc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt @@ -109,7 +109,7 @@ object Renderers { @JvmField val RENDER_CLASS_OR_OBJECT_NAME = Renderer { it.renderKindWithName() } - @JvmField val RENDER_TYPE = Renderer { DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(it) } + @JvmField val RENDER_TYPE = SmartTypeRenderer(DescriptorRenderer.FQ_NAMES_IN_TYPES) @JvmField val RENDER_POSITION_VARIANCE = Renderer { variance: Variance -> @@ -442,6 +442,4 @@ object Renderers { }.asRenderer() } -fun DescriptorRenderer.asRenderer() = Renderer { - render(it) -} +fun DescriptorRenderer.asRenderer() = SmartDescriptorRenderer(this) \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/adaptiveClassifierNamePolicy.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/adaptiveClassifierNamePolicy.kt new file mode 100644 index 00000000000..eae180d4342 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/adaptiveClassifierNamePolicy.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.diagnostics.rendering + +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ClassifierDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.renderer.ClassifierNamePolicy +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe +import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.typeUtil.contains +import java.util.* + +val RenderingContext.adaptiveClassifierPolicy: ClassifierNamePolicy + get() = this[ADAPTIVE_CLASSIFIER_POLICY_KEY] + +private class AdaptiveClassifierNamePolicy(private val ambiguousNames: List) : ClassifierNamePolicy { + private val renderedParameters = mutableMapOf>() + + override fun renderClassifier(classifier: ClassifierDescriptor, renderer: DescriptorRenderer): String { + return when { + hasUniqueName(classifier) -> ClassifierNamePolicy.SHORT.renderClassifier(classifier, renderer) + classifier is ClassDescriptor -> ClassifierNamePolicy.FULLY_QUALIFIED.renderClassifier(classifier, renderer) + classifier is TypeParameterDescriptor -> { + val name = classifier.name + val typeParametersWithSameName = renderedParameters.getOrPut(name) { LinkedHashSet() } + val isFirstOccurence = typeParametersWithSameName.add(classifier) + val index = typeParametersWithSameName.indexOf(classifier) + renderer.renderAmbiguousTypeParameter(classifier, index + 1, isFirstOccurence) + } + else -> error("Unexpected classifier: ${classifier.javaClass}") + } + } + + private fun hasUniqueName(classifier: ClassifierDescriptor): Boolean { + return classifier.name !in ambiguousNames + } + + private fun DescriptorRenderer.renderAmbiguousTypeParameter( + typeParameter: TypeParameterDescriptor, index: Int, firstOccurence: Boolean + ) = buildString { + append(typeParameter.name) + append("#$index") + if (firstOccurence) { + append(renderMessage(" (type parameter of ${renderFqName(typeParameter.containingDeclaration.fqNameUnsafe)})")) + } + } +} + +private val ADAPTIVE_CLASSIFIER_POLICY_KEY = object : RenderingContext.Key("ADAPTIVE_CLASSIFIER_POLICY") { + override fun compute(objectsToRender: Collection): ClassifierNamePolicy { + val ambiguousNames = collectClassifiers(objectsToRender).groupBy { it.name }.filter { it.value.size > 1 }.map { it.key } + return AdaptiveClassifierNamePolicy(ambiguousNames) + } +} + +private fun collectClassifiers(objectsToRender: Collection): Set = LinkedHashSet().apply { + collectMentionedClassifiers(objectsToRender, this) +} + +private fun collectMentionedClassifiers(contextObjects: Collection, result: MutableSet) { + contextObjects.filterIsInstance().forEach { diagnosticType -> + diagnosticType.contains { + innerType -> + innerType.constructor.declarationDescriptor?.let { result.add(it) } + false + } + } + + contextObjects.filterIsInstance>().forEach { + collectMentionedClassifiers(it, result) + } + contextObjects.filterIsInstance().forEach { + result.add(it) + } + contextObjects.filterIsInstance().forEach { + collectMentionedClassifiers(it.upperBounds, result) + } + contextObjects.filterIsInstance().forEach { + collectMentionedClassifiers(listOf( + it.typeParameters, + it.returnType, + it.valueParameters, + it.dispatchReceiverParameter?.type, + it.extensionReceiverParameter?.type + ), result) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/smartRenderers.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/smartRenderers.kt new file mode 100644 index 00000000000..51725ee6261 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/smartRenderers.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.diagnostics.rendering + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.types.KotlinType + +class SmartTypeRenderer(private val baseRenderer: DescriptorRenderer) : DiagnosticParameterRenderer { + override fun render(obj: KotlinType, renderingContext: RenderingContext): String { + val adaptiveRenderer = baseRenderer.withOptions { + classifierNamePolicy = renderingContext.adaptiveClassifierPolicy + } + return adaptiveRenderer.renderType(obj) + } +} + +class SmartDescriptorRenderer(private val baseRenderer: DescriptorRenderer) : DiagnosticParameterRenderer { + override fun render(obj: DeclarationDescriptor, renderingContext: RenderingContext): String { + val adaptiveRenderer = baseRenderer.withOptions { + classifierNamePolicy = renderingContext.adaptiveClassifierPolicy + } + return adaptiveRenderer.render(obj) + } +} + diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt index efd6003055a..8be076a2ef4 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRenderer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt index f53acfbc9d8..2b781987177 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/renderer/DescriptorRendererImpl.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,7 +41,6 @@ import java.util.* internal class DescriptorRendererImpl( val options: DescriptorRendererOptionsImpl ) : DescriptorRenderer(), DescriptorRendererOptions by options/* this gives access to options without qualifier */ { - init { assert(options.isLocked) } @@ -604,7 +603,7 @@ internal class DescriptorRendererImpl( val returnType = function.returnType if (!withoutReturnType && (unitReturnType || (returnType == null || !KotlinBuiltIns.isUnit(returnType)))) { - builder.append(": ").append(if (returnType == null) "[NULL]" else escape(renderType(returnType))) + builder.append(": ").append(if (returnType == null) "[NULL]" else renderType(returnType)) } renderWhereSuffix(function.typeParameters, builder) @@ -615,7 +614,7 @@ internal class DescriptorRendererImpl( val receiver = callableDescriptor.extensionReceiverParameter if (receiver != null) { - builder.append(" on ").append(escape(renderType(receiver.type))) + builder.append(" on ").append(renderType(receiver.type)) } } @@ -623,7 +622,7 @@ internal class DescriptorRendererImpl( val receiver = callableDescriptor.extensionReceiverParameter if (receiver != null) { val type = receiver.type - var result = escape(renderType(type)) + var result = renderType(type) if (shouldRenderAsPrettyFunctionType(type) && !TypeUtils.isNullableType(type)) { result = "($result)" } @@ -659,7 +658,7 @@ internal class DescriptorRendererImpl( for (typeParameter in typeParameters) { typeParameter.upperBounds .drop(1) // first parameter is rendered by renderTypeParameter - .mapTo(upperBoundStrings) { renderName(typeParameter.name) + " : " + escape(renderType(it)) } + .mapTo(upperBoundStrings) { renderName(typeParameter.name) + " : " + renderType(it) } } if (!upperBoundStrings.isEmpty()) { @@ -743,12 +742,12 @@ internal class DescriptorRendererImpl( builder.append(": ") } - builder.append(escape(renderType(typeToRender))) + builder.append(renderType(typeToRender)) renderInitializer(variable, builder) if (verbose && varargElementType != null) { - builder.append(" /*").append(escape(renderType(realType))).append("*/") + builder.append(" /*").append(renderType(realType)).append("*/") } } @@ -771,7 +770,7 @@ internal class DescriptorRendererImpl( } renderName(property, builder) - builder.append(": ").append(escape(renderType(property.type))) + builder.append(": ").append(renderType(property.type)) renderReceiverAfterName(property, builder) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/HtmlTabledDescriptorRenderer.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/HtmlTabledDescriptorRenderer.java index 737fb172390..722c38afeb8 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/HtmlTabledDescriptorRenderer.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/HtmlTabledDescriptorRenderer.java @@ -21,9 +21,11 @@ import kotlin.Unit; import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor; import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticParameterRenderer; import org.jetbrains.kotlin.diagnostics.rendering.RenderingContext; +import org.jetbrains.kotlin.diagnostics.rendering.SmartDescriptorRenderer; import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer; import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.DescriptorRow; import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.FunctionArgumentsRow; @@ -109,7 +111,7 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer { } if (row instanceof DescriptorRow) { tdSpace(result); - tdRightBoldColspan(result, 2, DESCRIPTOR_IN_TABLE.render(((DescriptorRow) row).descriptor)); + tdRightBoldColspan(result, 2, DESCRIPTOR_IN_TABLE.render(((DescriptorRow) row).descriptor, context)); } if (row instanceof FunctionArgumentsRow) { FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row; @@ -209,7 +211,8 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer { } }; - public static final DescriptorRenderer DESCRIPTOR_IN_TABLE = DescriptorRenderer.Companion.withOptions( + private static final DiagnosticParameterRenderer + DESCRIPTOR_IN_TABLE = new SmartDescriptorRenderer(DescriptorRenderer.Companion.withOptions( new Function1() { @Override public Unit invoke(DescriptorRendererOptions options) { @@ -219,7 +222,7 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer { options.setTextFormat(RenderingFormat.HTML); return Unit.INSTANCE; } - }); + })); private static void td(StringBuilder builder, String text) { builder.append("").append(text).append(""); diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/IdeRenderers.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/IdeRenderers.kt index 38d14e74907..e5f2e5444f2 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/IdeRenderers.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/IdeRenderers.kt @@ -17,17 +17,13 @@ package org.jetbrains.kotlin.idea.highlighter import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.diagnostics.rendering.ContextDependentRenderer -import org.jetbrains.kotlin.diagnostics.rendering.Renderer -import org.jetbrains.kotlin.diagnostics.rendering.Renderers -import org.jetbrains.kotlin.diagnostics.rendering.asRenderer +import org.jetbrains.kotlin.diagnostics.rendering.* import org.jetbrains.kotlin.idea.highlighter.renderersUtil.renderResolvedCall import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.MemberComparator import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.jvm.diagnostics.ConflictingJvmDeclarationsData -import org.jetbrains.kotlin.types.KotlinType import kotlin.comparisons.compareBy object IdeRenderers { @@ -40,9 +36,7 @@ object IdeRenderers { .joinToString("") { "
  • ${DescriptorRenderer.HTML.render(it)}
  • " } } - @JvmField val HTML_RENDER_TYPE = Renderer { - DescriptorRenderer.HTML.renderType(it) - } + @JvmField val HTML_RENDER_TYPE = SmartTypeRenderer(DescriptorRenderer.HTML) @JvmField val HTML_NONE_APPLICABLE_CALLS= Renderer { calls: Collection> ->