Adjust diagnostics rendering so that short classifier names are rendered unless the name is ambiguous in corresponding RenderingContext

This commit is contained in:
Pavel V. Talanov
2016-02-17 16:40:55 +03:00
parent c7cb596f74
commit e4cf090720
7 changed files with 164 additions and 25 deletions
@@ -109,7 +109,7 @@ object Renderers {
@JvmField val RENDER_CLASS_OR_OBJECT_NAME = Renderer<ClassDescriptor> { it.renderKindWithName() }
@JvmField val RENDER_TYPE = Renderer<KotlinType> { 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<DeclarationDescriptor> {
render(it)
}
fun DescriptorRenderer.asRenderer() = SmartDescriptorRenderer(this)
@@ -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<Name>) : ClassifierNamePolicy {
private val renderedParameters = mutableMapOf<Name, LinkedHashSet<TypeParameterDescriptor>>()
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<ClassifierNamePolicy>("ADAPTIVE_CLASSIFIER_POLICY") {
override fun compute(objectsToRender: Collection<Any?>): ClassifierNamePolicy {
val ambiguousNames = collectClassifiers(objectsToRender).groupBy { it.name }.filter { it.value.size > 1 }.map { it.key }
return AdaptiveClassifierNamePolicy(ambiguousNames)
}
}
private fun collectClassifiers(objectsToRender: Collection<Any?>): Set<ClassifierDescriptor> = LinkedHashSet<ClassifierDescriptor>().apply {
collectMentionedClassifiers(objectsToRender, this)
}
private fun collectMentionedClassifiers(contextObjects: Collection<Any?>, result: MutableSet<ClassifierDescriptor>) {
contextObjects.filterIsInstance<KotlinType>().forEach { diagnosticType ->
diagnosticType.contains {
innerType ->
innerType.constructor.declarationDescriptor?.let { result.add(it) }
false
}
}
contextObjects.filterIsInstance<Collection<*>>().forEach {
collectMentionedClassifiers(it, result)
}
contextObjects.filterIsInstance<ClassifierDescriptor>().forEach {
result.add(it)
}
contextObjects.filterIsInstance<TypeParameterDescriptor>().forEach {
collectMentionedClassifiers(it.upperBounds, result)
}
contextObjects.filterIsInstance<CallableDescriptor>().forEach {
collectMentionedClassifiers(listOf(
it.typeParameters,
it.returnType,
it.valueParameters,
it.dispatchReceiverParameter?.type,
it.extensionReceiverParameter?.type
), result)
}
}
@@ -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<KotlinType> {
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<DeclarationDescriptor> {
override fun render(obj: DeclarationDescriptor, renderingContext: RenderingContext): String {
val adaptiveRenderer = baseRenderer.withOptions {
classifierNamePolicy = renderingContext.adaptiveClassifierPolicy
}
return adaptiveRenderer.render(obj)
}
}
@@ -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.
@@ -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)
@@ -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<DeclarationDescriptor>
DESCRIPTOR_IN_TABLE = new SmartDescriptorRenderer(DescriptorRenderer.Companion.withOptions(
new Function1<DescriptorRendererOptions, Unit>() {
@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("<td style=\"white-space:nowrap;\">").append(text).append("</td>");
@@ -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("") { "<li>${DescriptorRenderer.HTML.render(it)}</li>" }
}
@JvmField val HTML_RENDER_TYPE = Renderer<KotlinType> {
DescriptorRenderer.HTML.renderType(it)
}
@JvmField val HTML_RENDER_TYPE = SmartTypeRenderer(DescriptorRenderer.HTML)
@JvmField val HTML_NONE_APPLICABLE_CALLS= Renderer {
calls: Collection<ResolvedCall<*>> ->