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.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages;
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.diagnostics.rendering.*;
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
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>() {
@NotNull
@Override
public String render(@NotNull ConflictingJvmDeclarationsData data) {
public String render(@NotNull ConflictingJvmDeclarationsData data, @NotNull RenderingContext context) {
List<String> renderedDescriptors = new ArrayList<String>();
for (JvmDeclarationOrigin origin : data.getSignatureOrigins()) {
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");
* 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,6 +41,7 @@ import java.util.List;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.diagnostics.rendering.Renderers.*;
import static org.jetbrains.kotlin.diagnostics.rendering.RenderingContext.*;
public class DefaultErrorMessages {
@@ -118,11 +119,13 @@ public class DefaultErrorMessages {
@NotNull
@Override
public String[] render(@NotNull TypeMismatchDueToTypeProjectionsData object) {
RenderingContext context =
of(object.getExpectedType(), object.getExpressionType(), object.getReceiverType(), object.getCallableDescriptor());
return new String[] {
RENDER_TYPE.render(object.getExpectedType()),
RENDER_TYPE.render(object.getExpressionType()),
RENDER_TYPE.render(object.getReceiverType()),
DescriptorRenderer.FQ_NAMES_IN_TYPES.render(object.getCallableDescriptor())
RENDER_TYPE.render(object.getExpectedType(), context),
RENDER_TYPE.render(object.getExpressionType(), context),
RENDER_TYPE.render(object.getReceiverType(), context),
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>() {
@NotNull
@Override
public String render(@NotNull BadNamedArgumentsTarget target) {
public String render(@NotNull BadNamedArgumentsTarget target, @NotNull RenderingContext context) {
switch (target) {
case NON_KOTLIN_FUNCTION:
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>() {
@NotNull
@Override
public String render(@NotNull KtExpression expression) {
public String render(@NotNull KtExpression expression, @NotNull RenderingContext context) {
String expressionType = expression.toString();
return expressionType.substring(0, 1) +
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>() {
@NotNull
@Override
public String render(@NotNull KtTypeConstraint typeConstraint) {
public String render(@NotNull KtTypeConstraint typeConstraint, @NotNull RenderingContext context) {
//noinspection ConstantConditions
return typeConstraint.getSubjectTypeParameterName().getReferencedName();
}
@@ -509,11 +512,13 @@ public class DefaultErrorMessages {
@NotNull
@Override
public String[] render(@NotNull VarianceConflictDiagnosticData data) {
RenderingContext context =
of(data.getTypeParameter(), data.getTypeParameter().getVariance(), data.getOccurrencePosition(), data.getContainingType());
return new String[] {
NAME.render(data.getTypeParameter()),
RENDER_POSITION_VARIANCE.render(data.getTypeParameter().getVariance()),
RENDER_POSITION_VARIANCE.render(data.getOccurrencePosition()),
RENDER_TYPE.render(data.getContainingType())
NAME.render(data.getTypeParameter(), context),
RENDER_POSITION_VARIANCE.render(data.getTypeParameter().getVariance(), context),
RENDER_POSITION_VARIANCE.render(data.getOccurrencePosition(), context),
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>() {
@NotNull
@Override
public String render(@NotNull KtSimpleNameExpression nameExpression) {
public String render(@NotNull KtSimpleNameExpression nameExpression, @NotNull RenderingContext context) {
//noinspection ConstantConditions
return nameExpression.getReferencedName();
}
@@ -603,15 +608,15 @@ public class DefaultErrorMessages {
ELEMENT_TEXT, new DiagnosticParameterRenderer<KotlinType>() {
@NotNull
@Override
public String render(@NotNull KotlinType type) {
public String render(@NotNull KotlinType type, @NotNull RenderingContext context) {
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>() {
@NotNull
@Override
public String render(@NotNull Boolean hasValueParameters) {
public String render(@NotNull Boolean hasValueParameters, @NotNull RenderingContext context) {
return hasValueParameters ? "..." : "";
}
});
@@ -17,9 +17,13 @@
package org.jetbrains.kotlin.diagnostics.rendering
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> {
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");
* 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.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 + "'"
@@ -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.
@@ -122,19 +122,20 @@ object Renderers {
@JvmField val AMBIGUOUS_CALLS = Renderer {
calls: Collection<ResolvedCall<*>> ->
calls
.map { it.resultingDescriptor }
val descriptors = calls.map { it.resultingDescriptor }
val context = RenderingContext.Impl(descriptors)
descriptors
.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>> {
collection ->
@JvmStatic fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = ContextDependentRenderer<Collection<T>> {
collection, context ->
buildString {
val iterator = collection.iterator()
while (iterator.hasNext()) {
val next = iterator.next()
append(itemRenderer.render(next))
append(itemRenderer.render(next, context))
if (iterator.hasNext()) {
append(", ")
}
@@ -166,7 +167,7 @@ object Renderers {
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
): TabledDescriptorRenderer {
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 substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters(inferenceErrorData.constraintSystem)
@@ -177,7 +178,7 @@ object Renderers {
val firstConflictingVariable = ConstraintsUtil.getFirstConflictingVariable(inferenceErrorData.constraintSystem)
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
}
@@ -238,7 +239,7 @@ object Renderers {
val firstUnknownVariable = inferenceErrorData.constraintSystem.typeVariables.firstOrNull { variable ->
inferenceErrorData.constraintSystem.getTypeBounds(variable).values.isEmpty()
} ?: 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
@@ -256,7 +257,7 @@ object Renderers {
val constraintSystem = inferenceErrorData.constraintSystem
val status = constraintSystem.status
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 typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull {
@@ -266,15 +267,15 @@ object Renderers {
return renderConflictingSubstitutionsInferenceError(inferenceErrorData, result)
}
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
}
val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor)
val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeVariable).value
if (inferredValueForTypeParameter == null) {
LOG.error(renderDebugMessage("System without weak constraints is not successful, there is no value for type parameter " +
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData))
LOG.error(debugMessage("System without weak constraints is not successful, there is no value for type parameter " +
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData))
return result
}
@@ -295,17 +296,19 @@ object Renderers {
}
}
if (violatedUpperBound == null) {
LOG.error(renderDebugMessage("Type parameter (chosen as violating its upper bound)" +
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData))
LOG.error(debugMessage("Type parameter (chosen as violating its upper bound)" +
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData))
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
result.text(newText()
.normal(" is not satisfied: inferred type ")
.error(typeRenderer.render(inferredValueForTypeParameter))
.error(typeRenderer.render(inferredValueForTypeParameter, context))
.normal(" is not a subtype of ")
.strong(typeRenderer.render(violatedUpperBound)))
.strong(typeRenderer.render(violatedUpperBound, context)))
return result
}
@@ -316,7 +319,7 @@ object Renderers {
val errors = system.status.constraintErrors
val typeVariableWithCapturedConstraint = errors.firstIsInstanceOrNull<CannotCapture>()?.typeVariable
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
}
@@ -324,7 +327,7 @@ object Renderers {
val boundWithCapturedType = typeBounds.bounds.firstOrNull { it.constrainingType.isCaptured() }
val capturedTypeConstructor = boundWithCapturedType?.constrainingType?.constructor as? CapturedTypeConstructor
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
}
@@ -333,7 +336,7 @@ object Renderers {
val explanation: String
val upperBound = TypeIntersector.getUpperBoundsAsType(typeParameter)
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"
}
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>()
for (variable in constraintSystem.typeVariables) {
typeBounds.add(constraintSystem.getTypeBounds(variable))
}
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)
}
@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 {
val renderBound = { bound: Bound ->
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, ", ")}"
}
@JvmField val RENDER_TYPE_BOUNDS = Renderer<TypeBounds> { renderTypeBounds(it, short = false) }
@JvmField val RENDER_TYPE_BOUNDS_SHORT = Renderer<TypeBounds> { renderTypeBounds(it, short = true) }
private fun renderDebugMessage(message: String, inferenceErrorData: InferenceErrorData) = buildString {
private fun debugMessage(message: String, inferenceErrorData: InferenceErrorData) = buildString {
append(message)
append("\nConstraint system: \n")
append(RENDER_CONSTRAINT_SYSTEM.render(inferenceErrorData.constraintSystem))
append(renderConstraintSystem(inferenceErrorData.constraintSystem, false))
append("\nDescriptor:\n")
append(inferenceErrorData.descriptor)
append("\nExpected type:\n")
val context = RenderingContext.Empty
if (TypeUtils.noExpectedType(inferenceErrorData.expectedType)) {
append(inferenceErrorData.expectedType)
}
else {
append(RENDER_TYPE.render(inferenceErrorData.expectedType))
append(RENDER_TYPE.render(inferenceErrorData.expectedType, context))
}
append("\nArgument types:\n")
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
@@ -448,4 +444,4 @@ object Renderers {
fun DescriptorRenderer.asRenderer() = Renderer<DeclarationDescriptor> {
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");
* 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.TableRow;
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.types.KotlinType;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -167,26 +167,33 @@ public class TabledDescriptorRenderer {
protected void renderTable(TableRenderer table, StringBuilder result) {
if (table.rows.isEmpty()) return;
RenderingContext context = computeRenderingContext(table);
for (TableRow row : table.rows) {
if (row instanceof TextRenderer) {
renderText((TextRenderer) row, result);
}
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) {
FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row;
renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, result);
renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, result, context);
}
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;
if (hasReceiver) {
result.append("receiver: ");
result.append(getTypeRenderer().render(receiverType));
result.append(getTypeRenderer().render(receiverType, context));
result.append(" arguments: ");
}
if (argumentTypes.isEmpty()) {
@@ -197,7 +204,7 @@ public class TabledDescriptorRenderer {
result.append("(");
for (Iterator<KotlinType> iterator = argumentTypes.iterator(); iterator.hasNext(); ) {
KotlinType argumentType = iterator.next();
String renderedArgument = getTypeRenderer().render(argumentType);
String renderedArgument = getTypeRenderer().render(argumentType, context);
result.append(renderedArgument);
if (iterator.hasNext()) {
@@ -212,4 +219,25 @@ public class TabledDescriptorRenderer {
}
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) {
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>(
@@ -55,9 +54,10 @@ class DiagnosticWithParameters2Renderer<A : Any, B : Any>(
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters2<*, A, B>>(message) {
override fun renderParameters(diagnostic: DiagnosticWithParameters2<*, A, B>): Array<out Any> {
val context = RenderingContext.of(diagnostic.a, diagnostic.b)
return arrayOf(
renderParameter(diagnostic.a, rendererForA),
renderParameter(diagnostic.b, rendererForB)
renderParameter(diagnostic.a, rendererForA, context),
renderParameter(diagnostic.b, rendererForB, context)
)
}
}
@@ -70,10 +70,11 @@ class DiagnosticWithParameters3Renderer<A : Any, B : Any, C : Any>(
) : AbstractDiagnosticWithParametersRenderer<DiagnosticWithParameters3<*, A, B, C>>(message) {
override fun renderParameters(diagnostic: DiagnosticWithParameters3<*, A, B, C>): Array<out Any> {
val context = RenderingContext.of(diagnostic.a, diagnostic.b, diagnostic.c)
return arrayOf(
renderParameter(diagnostic.a, rendererForA),
renderParameter(diagnostic.b, rendererForB),
renderParameter(diagnostic.c, rendererForC)
renderParameter(diagnostic.a, rendererForA, context),
renderParameter(diagnostic.b, rendererForB, context),
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");
* you may not use this file except in compliance with the License.
@@ -17,15 +17,17 @@
package org.jetbrains.kotlin.resolve;
import com.google.common.collect.Lists;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import kotlin.Pair;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.diagnostics.rendering.Renderers;
import org.jetbrains.kotlin.name.Name;
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.inference.ConstraintSystem;
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.smartcasts.DataFlowInfo;
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.ScopeUtils;
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.kotlin.resolve.validation.OperatorValidator;
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
@@ -308,7 +310,13 @@ public class DelegatedPropertyResolver {
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(")");
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");
* 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 resultingStatus = Renderers.RENDER_CONSTRAINT_SYSTEM_SHORT.render(system)
val resultingStatus = Renderers.renderConstraintSystem(system, shortTypeBounds = true)
val resultingSubstitutor = system.resultingSubstitutor
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");
* 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.kotlin.descriptors.ValueParameterDescriptor;
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.TableRenderer.DescriptorRow;
import org.jetbrains.kotlin.diagnostics.rendering.TabledDescriptorRenderer.TableRenderer.FunctionArgumentsRow;
@@ -94,9 +95,10 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
@Override
protected void renderTable(TableRenderer table, StringBuilder result) {
if (table.rows.isEmpty()) return;
RenderingContext context = computeRenderingContext(table);
int rowsNumber = countColumnNumber(table);
result.append("<table>");
for (TableRow row : table.rows) {
result.append("<tr>");
@@ -111,7 +113,7 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
}
if (row instanceof FunctionArgumentsRow) {
FunctionArgumentsRow functionArgumentsRow = (FunctionArgumentsRow) row;
renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, functionArgumentsRow.isErrorPosition, result);
renderFunctionArguments(functionArgumentsRow.receiverType, functionArgumentsRow.argumentTypes, functionArgumentsRow.isErrorPosition, result, context);
}
result.append("</tr>");
}
@@ -124,7 +126,8 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
@Nullable KotlinType receiverType,
@NotNull List<KotlinType> argumentTypes,
Predicate<ConstraintPosition> isErrorPosition,
StringBuilder result
StringBuilder result,
@NotNull RenderingContext context
) {
boolean hasReceiver = receiverType != null;
tdSpace(result);
@@ -134,7 +137,7 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
if (isErrorPosition.apply(RECEIVER_POSITION.position())) {
error = true;
}
receiver = "receiver: " + RenderersUtilKt.renderStrong(getTypeRenderer().render(receiverType), error);
receiver = "receiver: " + RenderersUtilKt.renderStrong(getTypeRenderer().render(receiverType, context), error);
}
td(result, receiver);
td(result, hasReceiver ? "arguments: " : "");
@@ -151,7 +154,7 @@ public class HtmlTabledDescriptorRenderer extends TabledDescriptorRenderer {
if (isErrorPosition.apply(VALUE_PARAMETER_POSITION.position(i))) {
error = true;
}
String renderedArgument = getTypeRenderer().render(argumentType);
String renderedArgument = getTypeRenderer().render(argumentType, context);
tdRight(result, RenderersUtilKt.renderStrong(renderedArgument, error) + (iterator.hasNext() ? RenderersUtilKt.renderStrong(",") : ""));
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");
* you may not use this file except in compliance with the License.
@@ -71,11 +71,13 @@ public class IdeErrorMessages {
@NotNull
@Override
public String[] render(@NotNull TypeMismatchDueToTypeProjectionsData object) {
RenderingContext context = RenderingContext
.of(object.getExpectedType(), object.getExpressionType(), object.getReceiverType(), object.getCallableDescriptor());
return new String[] {
HTML_RENDER_TYPE.render(object.getExpectedType()),
HTML_RENDER_TYPE.render(object.getExpressionType()),
HTML_RENDER_TYPE.render(object.getReceiverType()),
HTML.render(object.getCallableDescriptor())
HTML_RENDER_TYPE.render(object.getExpectedType(), context),
HTML_RENDER_TYPE.render(object.getExpressionType(), context),
HTML_RENDER_TYPE.render(object.getReceiverType(), context),
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");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
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
@@ -67,28 +68,29 @@ object IdeRenderers {
Renderers.renderUpperBoundViolatedInferenceError(it, HtmlTabledDescriptorRenderer.create()).toString()
}
@JvmField val HTML_RENDER_RETURN_TYPE = Renderer<CallableMemberDescriptor> {
val returnType = it.returnType!!
DescriptorRenderer.HTML.renderType(returnType)
@JvmField val HTML_RENDER_RETURN_TYPE = ContextDependentRenderer<CallableMemberDescriptor> {
member, context ->
HTML_RENDER_TYPE.render(member.returnType!!, context)
}
@JvmField val HTML_COMPACT_WITH_MODIFIERS = DescriptorRenderer.HTML.withOptions {
withDefinedIn = false
}.asRenderer()
@JvmField val HTML_CONFLICTING_JVM_DECLARATIONS_DATA = Renderer {
data: ConflictingJvmDeclarationsData ->
@JvmField val HTML_CONFLICTING_JVM_DECLARATIONS_DATA = ContextDependentRenderer {
data: ConflictingJvmDeclarationsData, renderingContext ->
val conflicts = data.signatureOrigins
.mapNotNull { it.descriptor }
.sortedWith(MemberComparator.INSTANCE)
.joinToString("") { "<li>" + HTML_COMPACT_WITH_MODIFIERS.render(it) + "</li>\n" }
.mapNotNull { it.descriptor }
.sortedWith(MemberComparator.INSTANCE)
.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>"
}
@JvmField val HTML_THROWABLE = Renderer<Throwable> {
Renderers.THROWABLE.render(it).replace("\n", "<br/>")
@JvmField val HTML_THROWABLE = ContextDependentRenderer<Throwable> {
throwable, context ->
Renderers.THROWABLE.render(throwable, context).replace("\n", "<br/>")
}
@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");
* 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.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticParameterRenderer
import org.jetbrains.kotlin.diagnostics.rendering.RenderingContext
object RenderFirstLineOfElementText : DiagnosticParameterRenderer<PsiElement> {
override fun render(element: PsiElement): String {
override fun render(element: PsiElement, context: RenderingContext): String {
val text = element.text
val index = text.indexOf('\n')
return if (index == -1) text else text.substring(0, index) + "..."
@@ -31,7 +32,7 @@ object RenderFirstLineOfElementText : DiagnosticParameterRenderer<PsiElement> {
abstract class JsCallDataRenderer : DiagnosticParameterRenderer<JsCallData> {
protected abstract fun format(data: JsCallDataWithCode): String
override fun render(data: JsCallData): String =
override fun render(data: JsCallData, context: RenderingContext): String =
when (data) {
is JsCallDataWithCode -> format(data)
is JsCallData -> data.message