Introduce RenderingContext and add as parameter to DiagnosticParameterRenderer#render

RenderingContext holds data about the whole diagnostics allowing to adjust rendering of its parameters
This commit is contained in:
Pavel V. Talanov
2016-02-16 20:41:38 +03:00
parent 4f18b3da53
commit ced5a6c917
15 changed files with 228 additions and 112 deletions
@@ -18,10 +18,7 @@ package org.jetbrains.kotlin.resolve.jvm.diagnostics;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages; import org.jetbrains.kotlin.diagnostics.rendering.*;
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap;
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticParameterRenderer;
import org.jetbrains.kotlin.diagnostics.rendering.Renderers;
import org.jetbrains.kotlin.renderer.DescriptorRenderer; import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import java.util.ArrayList; import java.util.ArrayList;
@@ -33,7 +30,7 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension {
private static final DiagnosticParameterRenderer<ConflictingJvmDeclarationsData> CONFLICTING_JVM_DECLARATIONS_DATA = new DiagnosticParameterRenderer<ConflictingJvmDeclarationsData>() { private static final DiagnosticParameterRenderer<ConflictingJvmDeclarationsData> CONFLICTING_JVM_DECLARATIONS_DATA = new DiagnosticParameterRenderer<ConflictingJvmDeclarationsData>() {
@NotNull @NotNull
@Override @Override
public String render(@NotNull ConflictingJvmDeclarationsData data) { public String render(@NotNull ConflictingJvmDeclarationsData data, @NotNull RenderingContext context) {
List<String> renderedDescriptors = new ArrayList<String>(); List<String> renderedDescriptors = new ArrayList<String>();
for (JvmDeclarationOrigin origin : data.getSignatureOrigins()) { for (JvmDeclarationOrigin origin : data.getSignatureOrigins()) {
DeclarationDescriptor descriptor = origin.getDescriptor(); DeclarationDescriptor descriptor = origin.getDescriptor();
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@ import java.util.List;
import static org.jetbrains.kotlin.diagnostics.Errors.*; import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.diagnostics.rendering.Renderers.*; import static org.jetbrains.kotlin.diagnostics.rendering.Renderers.*;
import static org.jetbrains.kotlin.diagnostics.rendering.RenderingContext.*;
public class DefaultErrorMessages { public class DefaultErrorMessages {
@@ -118,11 +119,13 @@ public class DefaultErrorMessages {
@NotNull @NotNull
@Override @Override
public String[] render(@NotNull TypeMismatchDueToTypeProjectionsData object) { public String[] render(@NotNull TypeMismatchDueToTypeProjectionsData object) {
RenderingContext context =
of(object.getExpectedType(), object.getExpressionType(), object.getReceiverType(), object.getCallableDescriptor());
return new String[] { return new String[] {
RENDER_TYPE.render(object.getExpectedType()), RENDER_TYPE.render(object.getExpectedType(), context),
RENDER_TYPE.render(object.getExpressionType()), RENDER_TYPE.render(object.getExpressionType(), context),
RENDER_TYPE.render(object.getReceiverType()), RENDER_TYPE.render(object.getReceiverType(), context),
DescriptorRenderer.FQ_NAMES_IN_TYPES.render(object.getCallableDescriptor()) FQ_NAMES_IN_TYPES.render(object.getCallableDescriptor(), context)
}; };
} }
}); });
@@ -175,7 +178,7 @@ public class DefaultErrorMessages {
MAP.put(NAMED_ARGUMENTS_NOT_ALLOWED, "Named arguments are not allowed for {0}", new DiagnosticParameterRenderer<BadNamedArgumentsTarget>() { MAP.put(NAMED_ARGUMENTS_NOT_ALLOWED, "Named arguments are not allowed for {0}", new DiagnosticParameterRenderer<BadNamedArgumentsTarget>() {
@NotNull @NotNull
@Override @Override
public String render(@NotNull BadNamedArgumentsTarget target) { public String render(@NotNull BadNamedArgumentsTarget target, @NotNull RenderingContext context) {
switch (target) { switch (target) {
case NON_KOTLIN_FUNCTION: case NON_KOTLIN_FUNCTION:
return "non-Kotlin functions"; return "non-Kotlin functions";
@@ -391,7 +394,7 @@ public class DefaultErrorMessages {
MAP.put(EXPRESSION_EXPECTED, "{0} is not an expression, and only expressions are allowed here", new DiagnosticParameterRenderer<KtExpression>() { MAP.put(EXPRESSION_EXPECTED, "{0} is not an expression, and only expressions are allowed here", new DiagnosticParameterRenderer<KtExpression>() {
@NotNull @NotNull
@Override @Override
public String render(@NotNull KtExpression expression) { public String render(@NotNull KtExpression expression, @NotNull RenderingContext context) {
String expressionType = expression.toString(); String expressionType = expression.toString();
return expressionType.substring(0, 1) + return expressionType.substring(0, 1) +
expressionType.substring(1).toLowerCase(); expressionType.substring(1).toLowerCase();
@@ -487,7 +490,7 @@ public class DefaultErrorMessages {
MAP.put(NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER, "{0} does not refer to a type parameter of {1}", new DiagnosticParameterRenderer<KtTypeConstraint>() { MAP.put(NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER, "{0} does not refer to a type parameter of {1}", new DiagnosticParameterRenderer<KtTypeConstraint>() {
@NotNull @NotNull
@Override @Override
public String render(@NotNull KtTypeConstraint typeConstraint) { public String render(@NotNull KtTypeConstraint typeConstraint, @NotNull RenderingContext context) {
//noinspection ConstantConditions //noinspection ConstantConditions
return typeConstraint.getSubjectTypeParameterName().getReferencedName(); return typeConstraint.getSubjectTypeParameterName().getReferencedName();
} }
@@ -509,11 +512,13 @@ public class DefaultErrorMessages {
@NotNull @NotNull
@Override @Override
public String[] render(@NotNull VarianceConflictDiagnosticData data) { public String[] render(@NotNull VarianceConflictDiagnosticData data) {
RenderingContext context =
of(data.getTypeParameter(), data.getTypeParameter().getVariance(), data.getOccurrencePosition(), data.getContainingType());
return new String[] { return new String[] {
NAME.render(data.getTypeParameter()), NAME.render(data.getTypeParameter(), context),
RENDER_POSITION_VARIANCE.render(data.getTypeParameter().getVariance()), RENDER_POSITION_VARIANCE.render(data.getTypeParameter().getVariance(), context),
RENDER_POSITION_VARIANCE.render(data.getOccurrencePosition()), RENDER_POSITION_VARIANCE.render(data.getOccurrencePosition(), context),
RENDER_TYPE.render(data.getContainingType()) RENDER_TYPE.render(data.getContainingType(), context)
}; };
} }
}); });
@@ -548,7 +553,7 @@ public class DefaultErrorMessages {
MAP.put(EQUALITY_NOT_APPLICABLE, "Operator ''{0}'' cannot be applied to ''{1}'' and ''{2}''", new DiagnosticParameterRenderer<KtSimpleNameExpression>() { MAP.put(EQUALITY_NOT_APPLICABLE, "Operator ''{0}'' cannot be applied to ''{1}'' and ''{2}''", new DiagnosticParameterRenderer<KtSimpleNameExpression>() {
@NotNull @NotNull
@Override @Override
public String render(@NotNull KtSimpleNameExpression nameExpression) { public String render(@NotNull KtSimpleNameExpression nameExpression, @NotNull RenderingContext context) {
//noinspection ConstantConditions //noinspection ConstantConditions
return nameExpression.getReferencedName(); return nameExpression.getReferencedName();
} }
@@ -603,15 +608,15 @@ public class DefaultErrorMessages {
ELEMENT_TEXT, new DiagnosticParameterRenderer<KotlinType>() { ELEMENT_TEXT, new DiagnosticParameterRenderer<KotlinType>() {
@NotNull @NotNull
@Override @Override
public String render(@NotNull KotlinType type) { public String render(@NotNull KotlinType type, @NotNull RenderingContext context) {
if (type.isError()) return ""; if (type.isError()) return "";
return " of type '" + RENDER_TYPE.render(type) + "'"; return " of type '" + RENDER_TYPE.render(type, context) + "'";
} }
}); });
MAP.put(FUNCTION_CALL_EXPECTED, "Function invocation ''{0}({1})'' expected", ELEMENT_TEXT, new DiagnosticParameterRenderer<Boolean>() { MAP.put(FUNCTION_CALL_EXPECTED, "Function invocation ''{0}({1})'' expected", ELEMENT_TEXT, new DiagnosticParameterRenderer<Boolean>() {
@NotNull @NotNull
@Override @Override
public String render(@NotNull Boolean hasValueParameters) { public String render(@NotNull Boolean hasValueParameters, @NotNull RenderingContext context) {
return hasValueParameters ? "..." : ""; return hasValueParameters ? "..." : "";
} }
}); });
@@ -17,9 +17,13 @@
package org.jetbrains.kotlin.diagnostics.rendering package org.jetbrains.kotlin.diagnostics.rendering
interface DiagnosticParameterRenderer<in O> { interface DiagnosticParameterRenderer<in O> {
fun render(obj: O): String fun render(obj: O, renderingContext: RenderingContext): String
} }
fun <O> Renderer(block: (O) -> String) = object : DiagnosticParameterRenderer<O> { fun <O> Renderer(block: (O) -> String) = object : DiagnosticParameterRenderer<O> {
override fun render(obj: O) = block(obj) override fun render(obj: O, renderingContext: RenderingContext): String = block(obj)
}
fun <O> ContextDependentRenderer(block: (O, RenderingContext) -> String) = object : DiagnosticParameterRenderer<O> {
override fun render(obj: O, renderingContext: RenderingContext): String = block(obj, renderingContext)
} }
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -19,7 +19,8 @@ package org.jetbrains.kotlin.diagnostics.rendering
import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?): Any = renderer?.render(parameter) ?: parameter fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any
= renderer?.render(parameter, context) ?: parameter
fun ClassDescriptor.renderKindWithName(): String = DescriptorRenderer.getClassKindPrefix(this) + " '" + name + "'" fun ClassDescriptor.renderKindWithName(): String = DescriptorRenderer.getClassKindPrefix(this) + " '" + name + "'"
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -122,19 +122,20 @@ object Renderers {
@JvmField val AMBIGUOUS_CALLS = Renderer { @JvmField val AMBIGUOUS_CALLS = Renderer {
calls: Collection<ResolvedCall<*>> -> calls: Collection<ResolvedCall<*>> ->
calls val descriptors = calls.map { it.resultingDescriptor }
.map { it.resultingDescriptor } val context = RenderingContext.Impl(descriptors)
descriptors
.sortedWith(MemberComparator.INSTANCE) .sortedWith(MemberComparator.INSTANCE)
.joinToString(separator = "\n", prefix = "\n") { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) } .joinToString(separator = "\n", prefix = "\n") { FQ_NAMES_IN_TYPES.render(it, context) }
} }
@JvmStatic fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = Renderer<Collection<T>> { @JvmStatic fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = ContextDependentRenderer<Collection<T>> {
collection -> collection, context ->
buildString { buildString {
val iterator = collection.iterator() val iterator = collection.iterator()
while (iterator.hasNext()) { while (iterator.hasNext()) {
val next = iterator.next() val next = iterator.next()
append(itemRenderer.render(next)) append(itemRenderer.render(next, context))
if (iterator.hasNext()) { if (iterator.hasNext()) {
append(", ") append(", ")
} }
@@ -166,7 +167,7 @@ object Renderers {
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer { ): TabledDescriptorRenderer {
LOG.assertTrue(inferenceErrorData.constraintSystem.status.hasConflictingConstraints(), LOG.assertTrue(inferenceErrorData.constraintSystem.status.hasConflictingConstraints(),
renderDebugMessage("Conflicting substitutions inference error renderer is applied for incorrect status", inferenceErrorData)) debugMessage("Conflicting substitutions inference error renderer is applied for incorrect status", inferenceErrorData))
val substitutedDescriptors = Lists.newArrayList<CallableDescriptor>() val substitutedDescriptors = Lists.newArrayList<CallableDescriptor>()
val substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters(inferenceErrorData.constraintSystem) val substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters(inferenceErrorData.constraintSystem)
@@ -177,7 +178,7 @@ object Renderers {
val firstConflictingVariable = ConstraintsUtil.getFirstConflictingVariable(inferenceErrorData.constraintSystem) val firstConflictingVariable = ConstraintsUtil.getFirstConflictingVariable(inferenceErrorData.constraintSystem)
if (firstConflictingVariable == null) { if (firstConflictingVariable == null) {
LOG.error(renderDebugMessage("There is no conflicting parameter for 'conflicting constraints' error.", inferenceErrorData)) LOG.error(debugMessage("There is no conflicting parameter for 'conflicting constraints' error.", inferenceErrorData))
return result return result
} }
@@ -238,7 +239,7 @@ object Renderers {
val firstUnknownVariable = inferenceErrorData.constraintSystem.typeVariables.firstOrNull { variable -> val firstUnknownVariable = inferenceErrorData.constraintSystem.typeVariables.firstOrNull { variable ->
inferenceErrorData.constraintSystem.getTypeBounds(variable).values.isEmpty() inferenceErrorData.constraintSystem.getTypeBounds(variable).values.isEmpty()
} ?: return result.apply { } ?: return result.apply {
LOG.error(renderDebugMessage("There is no unknown parameter for 'no information for parameter error'.", inferenceErrorData)) LOG.error(debugMessage("There is no unknown parameter for 'no information for parameter error'.", inferenceErrorData))
} }
return result return result
@@ -256,7 +257,7 @@ object Renderers {
val constraintSystem = inferenceErrorData.constraintSystem val constraintSystem = inferenceErrorData.constraintSystem
val status = constraintSystem.status val status = constraintSystem.status
LOG.assertTrue(status.hasViolatedUpperBound(), LOG.assertTrue(status.hasViolatedUpperBound(),
renderDebugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData)) debugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData))
val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(ConstraintPositionKind.TYPE_BOUND_POSITION) val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(ConstraintPositionKind.TYPE_BOUND_POSITION)
val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull { val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull {
@@ -266,15 +267,15 @@ object Renderers {
return renderConflictingSubstitutionsInferenceError(inferenceErrorData, result) return renderConflictingSubstitutionsInferenceError(inferenceErrorData, result)
} }
if (typeParameterDescriptor == null) { if (typeParameterDescriptor == null) {
LOG.error(renderDebugMessage("There is no type parameter with violated upper bound for 'upper bound violated' error", inferenceErrorData)) LOG.error(debugMessage("There is no type parameter with violated upper bound for 'upper bound violated' error", inferenceErrorData))
return result return result
} }
val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor) val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor)
val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeVariable).value val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeVariable).value
if (inferredValueForTypeParameter == null) { if (inferredValueForTypeParameter == null) {
LOG.error(renderDebugMessage("System without weak constraints is not successful, there is no value for type parameter " + LOG.error(debugMessage("System without weak constraints is not successful, there is no value for type parameter " +
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData)) typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData))
return result return result
} }
@@ -295,17 +296,19 @@ object Renderers {
} }
} }
if (violatedUpperBound == null) { if (violatedUpperBound == null) {
LOG.error(renderDebugMessage("Type parameter (chosen as violating its upper bound)" + LOG.error(debugMessage("Type parameter (chosen as violating its upper bound)" +
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData)) typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData))
return result return result
} }
// TODO: context should be in fact shared for the table and these two types
val context = RenderingContext.of(inferredValueForTypeParameter, violatedUpperBound)
val typeRenderer = result.typeRenderer val typeRenderer = result.typeRenderer
result.text(newText() result.text(newText()
.normal(" is not satisfied: inferred type ") .normal(" is not satisfied: inferred type ")
.error(typeRenderer.render(inferredValueForTypeParameter)) .error(typeRenderer.render(inferredValueForTypeParameter, context))
.normal(" is not a subtype of ") .normal(" is not a subtype of ")
.strong(typeRenderer.render(violatedUpperBound))) .strong(typeRenderer.render(violatedUpperBound, context)))
return result return result
} }
@@ -316,7 +319,7 @@ object Renderers {
val errors = system.status.constraintErrors val errors = system.status.constraintErrors
val typeVariableWithCapturedConstraint = errors.firstIsInstanceOrNull<CannotCapture>()?.typeVariable val typeVariableWithCapturedConstraint = errors.firstIsInstanceOrNull<CannotCapture>()?.typeVariable
if (typeVariableWithCapturedConstraint == null) { if (typeVariableWithCapturedConstraint == null) {
LOG.error(renderDebugMessage("An error 'cannot capture type parameter' is not found in errors", inferenceErrorData)) LOG.error(debugMessage("An error 'cannot capture type parameter' is not found in errors", inferenceErrorData))
return result return result
} }
@@ -324,7 +327,7 @@ object Renderers {
val boundWithCapturedType = typeBounds.bounds.firstOrNull { it.constrainingType.isCaptured() } val boundWithCapturedType = typeBounds.bounds.firstOrNull { it.constrainingType.isCaptured() }
val capturedTypeConstructor = boundWithCapturedType?.constrainingType?.constructor as? CapturedTypeConstructor val capturedTypeConstructor = boundWithCapturedType?.constrainingType?.constructor as? CapturedTypeConstructor
if (capturedTypeConstructor == null) { if (capturedTypeConstructor == null) {
LOG.error(renderDebugMessage("There is no captured type in bounds, but there is an error 'cannot capture type parameter'", inferenceErrorData)) LOG.error(debugMessage("There is no captured type in bounds, but there is an error 'cannot capture type parameter'", inferenceErrorData))
return result return result
} }
@@ -333,7 +336,7 @@ object Renderers {
val explanation: String val explanation: String
val upperBound = TypeIntersector.getUpperBoundsAsType(typeParameter) val upperBound = TypeIntersector.getUpperBoundsAsType(typeParameter)
if (!KotlinBuiltIns.isNullableAny(upperBound) && capturedTypeConstructor.typeProjection.projectionKind == Variance.IN_VARIANCE) { if (!KotlinBuiltIns.isNullableAny(upperBound) && capturedTypeConstructor.typeProjection.projectionKind == Variance.IN_VARIANCE) {
explanation = "Type parameter has an upper bound '" + result.typeRenderer.render(upperBound) + "'" + explanation = "Type parameter has an upper bound '" + result.typeRenderer.render(upperBound, RenderingContext.of(upperBound)) + "'" +
" that cannot be satisfied capturing 'in' projection" " that cannot be satisfied capturing 'in' projection"
} }
else { else {
@@ -365,24 +368,20 @@ object Renderers {
} }
} }
private fun renderTypes(types: Collection<KotlinType>) = StringUtil.join(types, { RENDER_TYPE.render(it) }, ", ") private fun renderTypes(types: Collection<KotlinType>, context: RenderingContext) = StringUtil.join(types, { RENDER_TYPE.render(it, context) }, ", ")
@JvmField val RENDER_COLLECTION_OF_TYPES = Renderer<Collection<KotlinType>> { renderTypes(it) } @JvmField val RENDER_COLLECTION_OF_TYPES = ContextDependentRenderer<Collection<KotlinType>> { types, context -> renderTypes(types, context) }
private fun renderConstraintSystem(constraintSystem: ConstraintSystem, renderTypeBounds: DiagnosticParameterRenderer<TypeBounds>): String { fun renderConstraintSystem(constraintSystem: ConstraintSystem, shortTypeBounds: Boolean): String {
val typeBounds = linkedSetOf<TypeBounds>() val typeBounds = linkedSetOf<TypeBounds>()
for (variable in constraintSystem.typeVariables) { for (variable in constraintSystem.typeVariables) {
typeBounds.add(constraintSystem.getTypeBounds(variable)) typeBounds.add(constraintSystem.getTypeBounds(variable))
} }
return "type parameter bounds:\n" + return "type parameter bounds:\n" +
StringUtil.join(typeBounds, { renderTypeBounds.render(it) }, "\n") + "\n\n" + "status:\n" + StringUtil.join(typeBounds, { renderTypeBounds(it, short = shortTypeBounds) }, "\n") + "\n\n" + "status:\n" +
ConstraintsUtil.getDebugMessageForStatus(constraintSystem.status) ConstraintsUtil.getDebugMessageForStatus(constraintSystem.status)
} }
@JvmField val RENDER_CONSTRAINT_SYSTEM = Renderer<ConstraintSystem> { renderConstraintSystem(it, RENDER_TYPE_BOUNDS) }
@JvmField val RENDER_CONSTRAINT_SYSTEM_SHORT = Renderer<ConstraintSystem> { renderConstraintSystem(it, RENDER_TYPE_BOUNDS_SHORT) }
private fun renderTypeBounds(typeBounds: TypeBounds, short: Boolean): String { private fun renderTypeBounds(typeBounds: TypeBounds, short: Boolean): String {
val renderBound = { bound: Bound -> val renderBound = { bound: Bound ->
val arrow = if (bound.kind == LOWER_BOUND) ">: " else if (bound.kind == UPPER_BOUND) "<: " else ":= " val arrow = if (bound.kind == LOWER_BOUND) ">: " else if (bound.kind == UPPER_BOUND) "<: " else ":= "
@@ -398,28 +397,25 @@ object Renderers {
"$typeVariableName ${StringUtil.join(typeBounds.bounds, renderBound, ", ")}" "$typeVariableName ${StringUtil.join(typeBounds.bounds, renderBound, ", ")}"
} }
@JvmField val RENDER_TYPE_BOUNDS = Renderer<TypeBounds> { renderTypeBounds(it, short = false) } private fun debugMessage(message: String, inferenceErrorData: InferenceErrorData) = buildString {
@JvmField val RENDER_TYPE_BOUNDS_SHORT = Renderer<TypeBounds> { renderTypeBounds(it, short = true) }
private fun renderDebugMessage(message: String, inferenceErrorData: InferenceErrorData) = buildString {
append(message) append(message)
append("\nConstraint system: \n") append("\nConstraint system: \n")
append(RENDER_CONSTRAINT_SYSTEM.render(inferenceErrorData.constraintSystem)) append(renderConstraintSystem(inferenceErrorData.constraintSystem, false))
append("\nDescriptor:\n") append("\nDescriptor:\n")
append(inferenceErrorData.descriptor) append(inferenceErrorData.descriptor)
append("\nExpected type:\n") append("\nExpected type:\n")
val context = RenderingContext.Empty
if (TypeUtils.noExpectedType(inferenceErrorData.expectedType)) { if (TypeUtils.noExpectedType(inferenceErrorData.expectedType)) {
append(inferenceErrorData.expectedType) append(inferenceErrorData.expectedType)
} }
else { else {
append(RENDER_TYPE.render(inferenceErrorData.expectedType)) append(RENDER_TYPE.render(inferenceErrorData.expectedType, context))
} }
append("\nArgument types:\n") append("\nArgument types:\n")
if (inferenceErrorData.receiverArgumentType != null) { if (inferenceErrorData.receiverArgumentType != null) {
append(RENDER_TYPE.render(inferenceErrorData.receiverArgumentType)).append(".") append(RENDER_TYPE.render(inferenceErrorData.receiverArgumentType, context)).append(".")
} }
append("(").append(renderTypes(inferenceErrorData.valueArgumentsTypes)).append(")") append("(").append(renderTypes(inferenceErrorData.valueArgumentsTypes, context)).append(")")
} }
private val WHEN_MISSING_LIMIT = 7 private val WHEN_MISSING_LIMIT = 7
@@ -448,4 +444,4 @@ object Renderers {
fun DescriptorRenderer.asRenderer() = Renderer<DeclarationDescriptor> { fun DescriptorRenderer.asRenderer() = Renderer<DeclarationDescriptor> {
render(it) render(it)
} }
@@ -0,0 +1,68 @@
/*
* 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.diagnostics.*
// holds data about the parameters of the diagnostic we're about to render
sealed class RenderingContext {
abstract operator fun <T> get(key: Key<T>): T
abstract class Key<T>(val name: String) {
abstract fun compute(objectsToRender: Collection<Any?>): T
}
class Impl(private val objectsToRender: Collection<Any?>) : RenderingContext() {
private val data = linkedMapOf<Key<*>, Any?>()
override fun <T> get(key: Key<T>): T {
if (!data.containsKey(key)) {
val result = key.compute(objectsToRender)
data[key] = result
return result
}
return data[key] as T
}
}
object Empty : RenderingContext() {
override fun <T> get(key: Key<T>): T {
return key.compute(emptyList())
}
}
companion object {
@JvmStatic
fun of(vararg objectsToRender: Any?): RenderingContext {
return Impl(objectsToRender.toList())
}
@JvmStatic
fun fromDiagnostic(d: Diagnostic): RenderingContext {
val parameters = when (d) {
is SimpleDiagnostic<*> -> listOf()
is DiagnosticWithParameters1<*, *> -> listOf(d.a)
is DiagnosticWithParameters2<*, *, *> -> listOf(d.a, d.b)
is DiagnosticWithParameters3<*, *, *, *> -> listOf(d.a, d.b, d.c)
is ParametrizedDiagnostic<*> -> error("Unexpected diagnostic: ${d.javaClass}")
else -> listOf()
}
return Impl(parameters)
}
}
}
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -26,10 +26,10 @@ import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.Table
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.FunctionArgumentsRow; import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.FunctionArgumentsRow;
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.TableRow; import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.TableRow;
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TextRenderer.TextElement; import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TextRenderer.TextElement;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition; import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition;
import org.jetbrains.kotlin.types.KotlinType; import org.jetbrains.kotlin.types.KotlinType;
import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -167,26 +167,33 @@ public class TabledDescriptorRenderer {
protected void renderTable(TableRenderer table, StringBuilder result) { protected void renderTable(TableRenderer table, StringBuilder result) {
if (table.rows.isEmpty()) return; if (table.rows.isEmpty()) return;
RenderingContext context = computeRenderingContext(table);
for (TableRow row : table.rows) { for (TableRow row : table.rows) {
if (row instanceof TextRenderer) { if (row instanceof TextRenderer) {
renderText((TextRenderer) row, result); renderText((TextRenderer) row, result);
} }
if (row instanceof DescriptorRow) { if (row instanceof DescriptorRow) {
result.append(DescriptorRenderer.COMPACT.render(((DescriptorRow) row).descriptor)); result.append(Renderers.COMPACT.render(((DescriptorRow) row).descriptor, context));
} }
if (row instanceof FunctionArgumentsRow) { if (row instanceof FunctionArgumentsRow) {
FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row; FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row;
renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, result); renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, result, context);
} }
result.append("\n"); result.append("\n");
} }
} }
private void renderFunctionArguments(@Nullable KotlinType receiverType, @NotNull List<KotlinType> argumentTypes, StringBuilder result) { private void renderFunctionArguments(
@Nullable KotlinType receiverType,
@NotNull List<KotlinType> argumentTypes,
StringBuilder result,
@NotNull RenderingContext context
) {
boolean hasReceiver = receiverType != null; boolean hasReceiver = receiverType != null;
if (hasReceiver) { if (hasReceiver) {
result.append("receiver: "); result.append("receiver: ");
result.append(getTypeRenderer().render(receiverType)); result.append(getTypeRenderer().render(receiverType, context));
result.append(" arguments: "); result.append(" arguments: ");
} }
if (argumentTypes.isEmpty()) { if (argumentTypes.isEmpty()) {
@@ -197,7 +204,7 @@ public class TabledDescriptorRenderer {
result.append("("); result.append("(");
for (Iterator<KotlinType> iterator = argumentTypes.iterator(); iterator.hasNext(); ) { for (Iterator<KotlinType> iterator = argumentTypes.iterator(); iterator.hasNext(); ) {
KotlinType argumentType = iterator.next(); KotlinType argumentType = iterator.next();
String renderedArgument = getTypeRenderer().render(argumentType); String renderedArgument = getTypeRenderer().render(argumentType, context);
result.append(renderedArgument); result.append(renderedArgument);
if (iterator.hasNext()) { if (iterator.hasNext()) {
@@ -212,4 +219,25 @@ public class TabledDescriptorRenderer {
} }
public static enum TextElementType { STRONG, ERROR, DEFAULT } public static enum TextElementType { STRONG, ERROR, DEFAULT }
@NotNull
protected static RenderingContext computeRenderingContext(@NotNull TableRenderer table) {
ArrayList<Object> toRender = new ArrayList<Object>();
for (TableRow row : table.rows) {
if (row instanceof DescriptorRow) {
toRender.add(((DescriptorRow) row).descriptor);
}
else if (row instanceof FunctionArgumentsRow) {
toRender.add(((FunctionArgumentsRow) row).receiverType);
toRender.addAll(((FunctionArgumentsRow) row).argumentTypes);
}
else if (row instanceof TextRenderer) {
}
else {
throw new AssertionError("Unknown row of type " + row.getClass());
}
}
return new RenderingContext.Impl(toRender);
}
} }
@@ -42,10 +42,9 @@ class DiagnosticWithParameters1Renderer<A : Any>(
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters1<*, A>>(message) { ) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters1<*, A>>(message) {
override fun renderParameters(diagnostic: DiagnosticWithParameters1<*, A>): Array<out Any> { override fun renderParameters(diagnostic: DiagnosticWithParameters1<*, A>): Array<out Any> {
return arrayOf(renderParameter(diagnostic.a, rendererForA)) val context = RenderingContext.of(diagnostic.a)
return arrayOf(renderParameter(diagnostic.a, rendererForA, context))
} }
} }
class DiagnosticWithParameters2Renderer<A : Any, B : Any>( class DiagnosticWithParameters2Renderer<A : Any, B : Any>(
@@ -55,9 +54,10 @@ class DiagnosticWithParameters2Renderer<A : Any, B : Any>(
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters2<*, A, B>>(message) { ) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters2<*, A, B>>(message) {
override fun renderParameters(diagnostic: DiagnosticWithParameters2<*, A, B>): Array<out Any> { override fun renderParameters(diagnostic: DiagnosticWithParameters2<*, A, B>): Array<out Any> {
val context = RenderingContext.of(diagnostic.a, diagnostic.b)
return arrayOf( return arrayOf(
renderParameter(diagnostic.a, rendererForA), renderParameter(diagnostic.a, rendererForA, context),
renderParameter(diagnostic.b, rendererForB) renderParameter(diagnostic.b, rendererForB, context)
) )
} }
} }
@@ -70,10 +70,11 @@ class DiagnosticWithParameters3Renderer<A : Any, B : Any, C : Any>(
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters3<*, A, B, C>>(message) { ) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters3<*, A, B, C>>(message) {
override fun renderParameters(diagnostic: DiagnosticWithParameters3<*, A, B, C>): Array<out Any> { override fun renderParameters(diagnostic: DiagnosticWithParameters3<*, A, B, C>): Array<out Any> {
val context = RenderingContext.of(diagnostic.a, diagnostic.b, diagnostic.c)
return arrayOf( return arrayOf(
renderParameter(diagnostic.a, rendererForA), renderParameter(diagnostic.a, rendererForA, context),
renderParameter(diagnostic.b, rendererForB), renderParameter(diagnostic.b, rendererForB, context),
renderParameter(diagnostic.c, rendererForC) renderParameter(diagnostic.c, rendererForC, context)
) )
} }
} }
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,15 +17,17 @@
package org.jetbrains.kotlin.resolve; package org.jetbrains.kotlin.resolve;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import kotlin.Pair; import kotlin.Pair;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.rendering.Renderers;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
@@ -34,8 +36,8 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfoFactory;
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope; import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.resolve.scopes.ScopeUtils;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.validation.OperatorValidator; import org.jetbrains.kotlin.resolve.validation.OperatorValidator;
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator; import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
@@ -308,7 +310,13 @@ public class DelegatedPropertyResolver {
argumentTypes.add(context.getType(argument.getArgumentExpression())); argumentTypes.add(context.getType(argument.getArgumentExpression()));
} }
builder.append(Renderers.RENDER_COLLECTION_OF_TYPES.render(argumentTypes)); String arguments = StringUtil.join(argumentTypes, new Function<KotlinType, String>() {
@Override
public String fun(KotlinType type) {
return DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type);
}
}, ", ");
builder.append(arguments);
builder.append(")"); builder.append(")");
return builder.toString(); return builder.toString();
} }
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -110,7 +110,7 @@ abstract class AbstractConstraintSystemTest() : KotlinLiteFixture() {
val system = builder.build() val system = builder.build()
val resultingStatus = Renderers.RENDER_CONSTRAINT_SYSTEM_SHORT.render(system) val resultingStatus = Renderers.renderConstraintSystem(system, shortTypeBounds = true)
val resultingSubstitutor = system.resultingSubstitutor val resultingSubstitutor = system.resultingSubstitutor
val result = typeParameterDescriptors.map { val result = typeParameterDescriptors.map {
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor; import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticParameterRenderer; import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticParameterRenderer;
import org.jetbrains.kotlin.diagnostics.rendering.RenderingContext;
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer; import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer;
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.DescriptorRow; import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.DescriptorRow;
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.FunctionArgumentsRow; import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.FunctionArgumentsRow;
@@ -94,9 +95,10 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
@Override @Override
protected void renderTable(TableRenderer table, StringBuilder result) { protected void renderTable(TableRenderer table, StringBuilder result) {
if (table.rows.isEmpty()) return; if (table.rows.isEmpty()) return;
RenderingContext context = computeRenderingContext(table);
int rowsNumber = countColumnNumber(table); int rowsNumber = countColumnNumber(table);
result.append("<table>"); result.append("<table>");
for (TableRow row : table.rows) { for (TableRow row : table.rows) {
result.append("<tr>"); result.append("<tr>");
@@ -111,7 +113,7 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
} }
if (row instanceof FunctionArgumentsRow) { if (row instanceof FunctionArgumentsRow) {
FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row; FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row;
renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, functionArgumentsRow.isErrorPosition, result); renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, functionArgumentsRow.isErrorPosition, result, context);
} }
result.append("</tr>"); result.append("</tr>");
} }
@@ -124,7 +126,8 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
@Nullable KotlinType receiverType, @Nullable KotlinType receiverType,
@NotNull List<KotlinType> argumentTypes, @NotNull List<KotlinType> argumentTypes,
Predicate<ConstraintPosition> isErrorPosition, Predicate<ConstraintPosition> isErrorPosition,
StringBuilder result StringBuilder result,
@NotNull RenderingContext context
) { ) {
boolean hasReceiver = receiverType != null; boolean hasReceiver = receiverType != null;
tdSpace(result); tdSpace(result);
@@ -134,7 +137,7 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
if (isErrorPosition.apply(RECEIVER_POSITION.position())) { if (isErrorPosition.apply(RECEIVER_POSITION.position())) {
error = true; error = true;
} }
receiver = "receiver: " + RenderersUtilKt.renderStrong(getTypeRenderer().render(receiverType), error); receiver = "receiver: " + RenderersUtilKt.renderStrong(getTypeRenderer().render(receiverType, context), error);
} }
td(result, receiver); td(result, receiver);
td(result, hasReceiver ? "arguments: " : ""); td(result, hasReceiver ? "arguments: " : "");
@@ -151,7 +154,7 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
if (isErrorPosition.apply(VALUE_PARAMETER_POSITION.position(i))) { if (isErrorPosition.apply(VALUE_PARAMETER_POSITION.position(i))) {
error = true; error = true;
} }
String renderedArgument = getTypeRenderer().render(argumentType); String renderedArgument = getTypeRenderer().render(argumentType, context);
tdRight(result, RenderersUtilKt.renderStrong(renderedArgument, error) + (iterator.hasNext() ? RenderersUtilKt.renderStrong(",") : "")); tdRight(result, RenderersUtilKt.renderStrong(renderedArgument, error) + (iterator.hasNext() ? RenderersUtilKt.renderStrong(",") : ""));
i++; i++;
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -71,11 +71,13 @@ public class IdeErrorMessages {
@NotNull @NotNull
@Override @Override
public String[] render(@NotNull TypeMismatchDueToTypeProjectionsData object) { public String[] render(@NotNull TypeMismatchDueToTypeProjectionsData object) {
RenderingContext context = RenderingContext
.of(object.getExpectedType(), object.getExpressionType(), object.getReceiverType(), object.getCallableDescriptor());
return new String[] { return new String[] {
HTML_RENDER_TYPE.render(object.getExpectedType()), HTML_RENDER_TYPE.render(object.getExpectedType(), context),
HTML_RENDER_TYPE.render(object.getExpressionType()), HTML_RENDER_TYPE.render(object.getExpressionType(), context),
HTML_RENDER_TYPE.render(object.getReceiverType()), HTML_RENDER_TYPE.render(object.getReceiverType(), context),
HTML.render(object.getCallableDescriptor()) HTML.render(object.getCallableDescriptor(), context)
}; };
} }
}); });
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.idea.highlighter package org.jetbrains.kotlin.idea.highlighter
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor 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.Renderer
import org.jetbrains.kotlin.diagnostics.rendering.Renderers import org.jetbrains.kotlin.diagnostics.rendering.Renderers
import org.jetbrains.kotlin.diagnostics.rendering.asRenderer import org.jetbrains.kotlin.diagnostics.rendering.asRenderer
@@ -67,28 +68,29 @@ object IdeRenderers {
Renderers.renderUpperBoundViolatedInferenceError(it, HtmlTabledDescriptorRenderer.create()).toString() Renderers.renderUpperBoundViolatedInferenceError(it, HtmlTabledDescriptorRenderer.create()).toString()
} }
@JvmField val HTML_RENDER_RETURN_TYPE = Renderer<CallableMemberDescriptor> { @JvmField val HTML_RENDER_RETURN_TYPE = ContextDependentRenderer<CallableMemberDescriptor> {
val returnType = it.returnType!! member, context ->
DescriptorRenderer.HTML.renderType(returnType) HTML_RENDER_TYPE.render(member.returnType!!, context)
} }
@JvmField val HTML_COMPACT_WITH_MODIFIERS = DescriptorRenderer.HTML.withOptions { @JvmField val HTML_COMPACT_WITH_MODIFIERS = DescriptorRenderer.HTML.withOptions {
withDefinedIn = false withDefinedIn = false
}.asRenderer() }.asRenderer()
@JvmField val HTML_CONFLICTING_JVM_DECLARATIONS_DATA = Renderer { @JvmField val HTML_CONFLICTING_JVM_DECLARATIONS_DATA = ContextDependentRenderer {
data: ConflictingJvmDeclarationsData -> data: ConflictingJvmDeclarationsData, renderingContext ->
val conflicts = data.signatureOrigins val conflicts = data.signatureOrigins
.mapNotNull { it.descriptor } .mapNotNull { it.descriptor }
.sortedWith(MemberComparator.INSTANCE) .sortedWith(MemberComparator.INSTANCE)
.joinToString("") { "<li>" + HTML_COMPACT_WITH_MODIFIERS.render(it) + "</li>\n" } .joinToString("") { "<li>" + HTML_COMPACT_WITH_MODIFIERS.render(it, renderingContext) + "</li>\n" }
"The following declarations have the same JVM signature (<code>${data.signature.name}${data.signature.desc}</code>):<br/>\n<ul>\n$conflicts</ul>" "The following declarations have the same JVM signature (<code>${data.signature.name}${data.signature.desc}</code>):<br/>\n<ul>\n$conflicts</ul>"
} }
@JvmField val HTML_THROWABLE = Renderer<Throwable> { @JvmField val HTML_THROWABLE = ContextDependentRenderer<Throwable> {
Renderers.THROWABLE.render(it).replace("\n", "<br/>") throwable, context ->
Renderers.THROWABLE.render(throwable, context).replace("\n", "<br/>")
} }
@JvmField val HTML = DescriptorRenderer.HTML.asRenderer() @JvmField val HTML = DescriptorRenderer.HTML.asRenderer()
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -19,9 +19,10 @@ package org.jetbrains.kotlin.js.resolve.diagnostics
import com.google.gwt.dev.js.rhino.Utils.isEndOfLine import com.google.gwt.dev.js.rhino.Utils.isEndOfLine
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticParameterRenderer import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticParameterRenderer
import org.jetbrains.kotlin.diagnostics.rendering.RenderingContext
object RenderFirstLineOfElementText : DiagnosticParameterRenderer<PsiElement> { object RenderFirstLineOfElementText : DiagnosticParameterRenderer<PsiElement> {
override fun render(element: PsiElement): String { override fun render(element: PsiElement, context: RenderingContext): String {
val text = element.text val text = element.text
val index = text.indexOf('\n') val index = text.indexOf('\n')
return if (index == -1) text else text.substring(0, index) + "..." return if (index == -1) text else text.substring(0, index) + "..."
@@ -31,7 +32,7 @@ object RenderFirstLineOfElementText : DiagnosticParameterRenderer<PsiElement> {
abstract class JsCallDataRenderer : DiagnosticParameterRenderer<JsCallData> { abstract class JsCallDataRenderer : DiagnosticParameterRenderer<JsCallData> {
protected abstract fun format(data: JsCallDataWithCode): String protected abstract fun format(data: JsCallDataWithCode): String
override fun render(data: JsCallData): String = override fun render(data: JsCallData, context: RenderingContext): String =
when (data) { when (data) {
is JsCallDataWithCode -> format(data) is JsCallDataWithCode -> format(data)
is JsCallData -> data.message is JsCallData -> data.message