[FE 1.0] Introduce new kind of diagnostic factories for deprecation warnings/errors
This commit is contained in:
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
|
||||
sealed class DiagnosticFactoryForDeprecation<E : PsiElement, D : Diagnostic, F : DiagnosticFactoryWithPsiElement<E, D>>(
|
||||
val deprecatingFeature: LanguageFeature,
|
||||
val warningFactory: F,
|
||||
val errorFactory: F
|
||||
) {
|
||||
fun LanguageVersionSettings.chooseFactory(): F {
|
||||
return if (supportsFeature(deprecatingFeature)) errorFactory else warningFactory
|
||||
}
|
||||
}
|
||||
|
||||
class DiagnosticFactoryForDeprecation0<E : PsiElement>(
|
||||
featureForError: LanguageFeature,
|
||||
warningFactory: DiagnosticFactory0<E>,
|
||||
errorFactory: DiagnosticFactory0<E>
|
||||
) : DiagnosticFactoryForDeprecation<E, SimpleDiagnostic<E>, DiagnosticFactory0<E>>(featureForError, warningFactory, errorFactory) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun <E : PsiElement> create(
|
||||
featureForError: LanguageFeature,
|
||||
positioningStrategy: PositioningStrategy<E> = PositioningStrategies.DEFAULT
|
||||
): DiagnosticFactoryForDeprecation0<E> {
|
||||
return DiagnosticFactoryForDeprecation0(
|
||||
featureForError,
|
||||
warningFactory = DiagnosticFactory0.create(Severity.WARNING, positioningStrategy),
|
||||
errorFactory = DiagnosticFactory0.create(Severity.ERROR, positioningStrategy),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun on(languageVersionSettings: LanguageVersionSettings, element: E): SimpleDiagnostic<E> {
|
||||
return languageVersionSettings.chooseFactory().on(element)
|
||||
}
|
||||
}
|
||||
|
||||
class DiagnosticFactoryForDeprecation1<E : PsiElement, A : Any>(
|
||||
featureForError: LanguageFeature,
|
||||
warningFactory: DiagnosticFactory1<E, A>,
|
||||
errorFactory: DiagnosticFactory1<E, A>
|
||||
) : DiagnosticFactoryForDeprecation<E, DiagnosticWithParameters1<E, A>, DiagnosticFactory1<E, A>>(featureForError, warningFactory, errorFactory) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun <E : PsiElement, A : Any> create(
|
||||
featureForError: LanguageFeature,
|
||||
positioningStrategy: PositioningStrategy<E> = PositioningStrategies.DEFAULT
|
||||
): DiagnosticFactoryForDeprecation1<E, A> {
|
||||
return DiagnosticFactoryForDeprecation1(
|
||||
featureForError,
|
||||
warningFactory = DiagnosticFactory1.create(Severity.WARNING, positioningStrategy),
|
||||
errorFactory = DiagnosticFactory1.create(Severity.ERROR, positioningStrategy),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun on(languageVersionSettings: LanguageVersionSettings, element: E, a: A): ParametrizedDiagnostic<E> {
|
||||
return languageVersionSettings.chooseFactory().on(element, a)
|
||||
}
|
||||
}
|
||||
|
||||
class DiagnosticFactoryForDeprecation2<E : PsiElement, A : Any, B : Any>(
|
||||
featureForError: LanguageFeature,
|
||||
warningFactory: DiagnosticFactory2<E, A, B>,
|
||||
errorFactory: DiagnosticFactory2<E, A, B>
|
||||
) : DiagnosticFactoryForDeprecation<E, DiagnosticWithParameters2<E, A, B>, DiagnosticFactory2<E, A, B>>(featureForError, warningFactory, errorFactory) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun <E : PsiElement, A : Any, B : Any> create(
|
||||
featureForError: LanguageFeature,
|
||||
positioningStrategy: PositioningStrategy<E> = PositioningStrategies.DEFAULT
|
||||
): DiagnosticFactoryForDeprecation2<E, A, B> {
|
||||
return DiagnosticFactoryForDeprecation2(
|
||||
featureForError,
|
||||
warningFactory = DiagnosticFactory2.create(Severity.WARNING, positioningStrategy),
|
||||
errorFactory = DiagnosticFactory2.create(Severity.ERROR, positioningStrategy),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun on(languageVersionSettings: LanguageVersionSettings, element: E, a: A, b: B): ParametrizedDiagnostic<E> {
|
||||
return languageVersionSettings.chooseFactory().on(element, a, b)
|
||||
}
|
||||
}
|
||||
|
||||
class DiagnosticFactoryForDeprecation3<E : PsiElement, A : Any, B : Any, C : Any>(
|
||||
featureForError: LanguageFeature,
|
||||
warningFactory: DiagnosticFactory3<E, A, B, C>,
|
||||
errorFactory: DiagnosticFactory3<E, A, B, C>
|
||||
) : DiagnosticFactoryForDeprecation<E, DiagnosticWithParameters3<E, A, B, C>, DiagnosticFactory3<E, A, B, C>>(featureForError, warningFactory, errorFactory) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun <E : PsiElement, A : Any, B : Any, C : Any> create(
|
||||
featureForError: LanguageFeature,
|
||||
positioningStrategy: PositioningStrategy<E> = PositioningStrategies.DEFAULT
|
||||
): DiagnosticFactoryForDeprecation3<E, A, B, C> {
|
||||
return DiagnosticFactoryForDeprecation3(
|
||||
featureForError,
|
||||
warningFactory = DiagnosticFactory3.create(Severity.WARNING, positioningStrategy),
|
||||
errorFactory = DiagnosticFactory3.create(Severity.ERROR, positioningStrategy),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun on(languageVersionSettings: LanguageVersionSettings, element: E, a: A, b: B, c: C): ParametrizedDiagnostic<E> {
|
||||
return languageVersionSettings.chooseFactory().on(element, a, b, c)
|
||||
}
|
||||
}
|
||||
|
||||
class DiagnosticFactoryForDeprecation4<E : PsiElement, A : Any, B : Any, C : Any, D : Any>(
|
||||
featureForError: LanguageFeature,
|
||||
warningFactory: DiagnosticFactory4<E, A, B, C, D>,
|
||||
errorFactory: DiagnosticFactory4<E, A, B, C, D>
|
||||
) : DiagnosticFactoryForDeprecation<E, DiagnosticWithParameters4<E, A, B, C, D>, DiagnosticFactory4<E, A, B, C, D>>(featureForError, warningFactory, errorFactory) {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun <E : PsiElement, A : Any, B : Any, C : Any, D : Any> create(
|
||||
featureForError: LanguageFeature,
|
||||
positioningStrategy: PositioningStrategy<E> = PositioningStrategies.DEFAULT
|
||||
): DiagnosticFactoryForDeprecation4<E, A, B, C, D> {
|
||||
return DiagnosticFactoryForDeprecation4(
|
||||
featureForError,
|
||||
warningFactory = DiagnosticFactory4.create(Severity.WARNING, positioningStrategy),
|
||||
errorFactory = DiagnosticFactory4.create(Severity.ERROR, positioningStrategy),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun on(languageVersionSettings: LanguageVersionSettings, element: E, a: A, b: B, c: C, d: D): ParametrizedDiagnostic<E> {
|
||||
return languageVersionSettings.chooseFactory().on(element, a, b, c, d)
|
||||
}
|
||||
}
|
||||
@@ -824,8 +824,8 @@ public interface Errors {
|
||||
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_CANNOT_CAPTURE_TYPES = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> TYPE_INFERENCE_INCORPORATION_ERROR = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, TypeParameterDescriptor> TYPE_INFERENCE_ONLY_INPUT_TYPES = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, TypeParameterDescriptor> TYPE_INFERENCE_ONLY_INPUT_TYPES_WARNING = DiagnosticFactory1.create(WARNING);
|
||||
|
||||
DiagnosticFactoryForDeprecation1<PsiElement, TypeParameterDescriptor> TYPE_INFERENCE_ONLY_INPUT_TYPES = DiagnosticFactoryForDeprecation1.create(LanguageFeature.StrictOnlyInputTypesChecks);
|
||||
DiagnosticFactory1<PsiElement, InferenceErrorData> TYPE_INFERENCE_UPPER_BOUND_VIOLATED = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory2<KtElement, KotlinType, KotlinType> TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> TYPE_INFERENCE_CANDIDATE_WITH_SAM_AND_VARARG = DiagnosticFactory0.create(WARNING);
|
||||
@@ -1218,6 +1218,9 @@ public interface Errors {
|
||||
Initializer __initializer = Initializer.INSTANCE;
|
||||
|
||||
class Initializer {
|
||||
private static final String WARNING = "_WARNING";
|
||||
private static final String ERROR = "_ERROR";
|
||||
|
||||
static {
|
||||
initializeFactoryNames(Errors.class);
|
||||
}
|
||||
@@ -1226,7 +1229,6 @@ public interface Errors {
|
||||
initializeFactoryNamesAndDefaultErrorMessages(aClass, DiagnosticFactoryToRendererMap::new);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public static void initializeFactoryNamesAndDefaultErrorMessages(
|
||||
@NotNull Class<?> aClass,
|
||||
@NotNull DefaultErrorMessages.Extension defaultErrorMessages
|
||||
@@ -1237,10 +1239,13 @@ public interface Errors {
|
||||
try {
|
||||
Object value = field.get(null);
|
||||
if (value instanceof DiagnosticFactory) {
|
||||
DiagnosticFactory<?> factory = (DiagnosticFactory<?>)value;
|
||||
factory.initializeName(field.getName());
|
||||
|
||||
factory.setDefaultRenderer((DiagnosticRenderer) diagnosticToRendererMap.get(factory));
|
||||
initializeNameAndRenderer(diagnosticToRendererMap, field.getName(), (DiagnosticFactory<?>) value);
|
||||
}
|
||||
if (value instanceof DiagnosticFactoryForDeprecation) {
|
||||
String errorName = field.getName();
|
||||
DiagnosticFactoryForDeprecation<?, ?, ?> factory = (DiagnosticFactoryForDeprecation<?, ?, ?>) value;
|
||||
initializeNameAndRenderer(diagnosticToRendererMap, field.getName() + ERROR, factory.getErrorFactory());
|
||||
initializeNameAndRenderer(diagnosticToRendererMap, field.getName() + WARNING, factory.getWarningFactory());
|
||||
}
|
||||
}
|
||||
catch (IllegalAccessException e) {
|
||||
@@ -1248,7 +1253,11 @@ public interface Errors {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void initializeNameAndRenderer(DiagnosticFactoryToRendererMap diagnosticToRendererMap, String name, DiagnosticFactory<?> factory) {
|
||||
factory.initializeName(name);
|
||||
factory.setDefaultRenderer((DiagnosticRenderer) diagnosticToRendererMap.get(factory));
|
||||
}
|
||||
|
||||
private static final Initializer INSTANCE = new Initializer();
|
||||
|
||||
-2
@@ -929,8 +929,6 @@ public class DefaultErrorMessages {
|
||||
MAP.put(TYPE_INFERENCE_INCORPORATION_ERROR, "Type inference failed. Please try to specify type arguments explicitly.");
|
||||
MAP.put(TYPE_INFERENCE_ONLY_INPUT_TYPES, "Type inference failed. The value of the type parameter {0} should be mentioned in input types " +
|
||||
"(argument types, receiver type or expected type). Try to specify it explicitly.", NAME);
|
||||
MAP.put(TYPE_INFERENCE_ONLY_INPUT_TYPES_WARNING, "Type inference failed. The value of the type parameter {0} should be mentioned in input types " +
|
||||
"(argument types, receiver type or expected type). Try to specify it explicitly.", NAME);
|
||||
MAP.put(TYPE_INFERENCE_UPPER_BOUND_VIOLATED, "{0}", TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER);
|
||||
MAP.put(TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH, "Type inference failed. Expected type mismatch: inferred type is {1} but {0} was expected", RENDER_TYPE, RENDER_TYPE);
|
||||
MAP.put(TYPE_INFERENCE_CANDIDATE_WITH_SAM_AND_VARARG, "Please use spread operator to pass an array as vararg. It will be an error in 1.5.");
|
||||
|
||||
+61
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.diagnostics.rendering;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.config.LanguageVersion;
|
||||
import org.jetbrains.kotlin.diagnostics.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
@@ -94,6 +95,66 @@ public final class DiagnosticFactoryToRendererMap {
|
||||
map.put(factory, renderer);
|
||||
}
|
||||
|
||||
public <E extends PsiElement> void put(@NotNull DiagnosticFactoryForDeprecation0<E> factory, @NotNull String message) {
|
||||
checkMutability();
|
||||
map.put(factory.getErrorFactory(), new SimpleDiagnosticRenderer(message));
|
||||
map.put(factory.getWarningFactory(), new SimpleDiagnosticRenderer(deprecationMessage(factory, message)));
|
||||
}
|
||||
|
||||
public <E extends PsiElement, A> void put(@NotNull DiagnosticFactoryForDeprecation1<E, A> factory, @NotNull String message, @Nullable DiagnosticParameterRenderer<? super A> rendererA) {
|
||||
checkMutability();
|
||||
map.put(factory.getErrorFactory(), new DiagnosticWithParameters1Renderer<A>(message, rendererA));
|
||||
map.put(factory.getWarningFactory(), new DiagnosticWithParameters1Renderer<A>(deprecationMessage(factory, message), rendererA));
|
||||
}
|
||||
|
||||
public <E extends PsiElement, A> void put(@NotNull DiagnosticFactoryForDeprecation1<E, A> factory, @NotNull String message, @NotNull MultiRenderer<? super A> rendererA) {
|
||||
checkMutability();
|
||||
map.put(factory.getErrorFactory(), new DiagnosticWithParametersMultiRenderer<A>(message, rendererA));
|
||||
map.put(factory.getWarningFactory(), new DiagnosticWithParametersMultiRenderer<A>(deprecationMessage(factory, message), rendererA));
|
||||
}
|
||||
|
||||
public <E extends PsiElement, A, B> void put(@NotNull DiagnosticFactoryForDeprecation2<E, A, B> factory,
|
||||
@NotNull String message,
|
||||
@Nullable DiagnosticParameterRenderer<? super A> rendererA,
|
||||
@Nullable DiagnosticParameterRenderer<? super B> rendererB) {
|
||||
checkMutability();
|
||||
map.put(factory.getErrorFactory(), new DiagnosticWithParameters2Renderer<A, B>(message, rendererA, rendererB));
|
||||
map.put(factory.getWarningFactory(), new DiagnosticWithParameters2Renderer<A, B>(deprecationMessage(factory, message), rendererA, rendererB));
|
||||
}
|
||||
|
||||
public <E extends PsiElement, A, B, C> void put(@NotNull DiagnosticFactoryForDeprecation3<E, A, B, C> factory,
|
||||
@NotNull String message,
|
||||
@Nullable DiagnosticParameterRenderer<? super A> rendererA,
|
||||
@Nullable DiagnosticParameterRenderer<? super B> rendererB,
|
||||
@Nullable DiagnosticParameterRenderer<? super C> rendererC) {
|
||||
checkMutability();
|
||||
map.put(factory.getErrorFactory(), new DiagnosticWithParameters3Renderer<A, B, C>(message, rendererA, rendererB, rendererC));
|
||||
map.put(factory.getWarningFactory(), new DiagnosticWithParameters3Renderer<A, B, C>(deprecationMessage(factory, message), rendererA, rendererB, rendererC));
|
||||
}
|
||||
|
||||
public <E extends PsiElement, A, B, C, D> void put(@NotNull DiagnosticFactoryForDeprecation4<E, A, B, C, D> factory,
|
||||
@NotNull String message,
|
||||
@Nullable DiagnosticParameterRenderer<? super A> rendererA,
|
||||
@Nullable DiagnosticParameterRenderer<? super B> rendererB,
|
||||
@Nullable DiagnosticParameterRenderer<? super C> rendererC,
|
||||
@Nullable DiagnosticParameterRenderer<? super D> rendererD) {
|
||||
checkMutability();
|
||||
map.put(factory.getErrorFactory(), new DiagnosticWithParameters4Renderer<A, B, C, D>(message, rendererA, rendererB, rendererC, rendererD));
|
||||
map.put(factory.getWarningFactory(), new DiagnosticWithParameters4Renderer<A, B, C, D>(deprecationMessage(factory, message), rendererA, rendererB, rendererC, rendererD));
|
||||
}
|
||||
|
||||
private static String deprecationMessage(DiagnosticFactoryForDeprecation<?, ?, ?> factory, String errorMessage) {
|
||||
LanguageVersion sinceVersion = factory.getDeprecatingFeature().getSinceVersion();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append(errorMessage).append(". This will become an error");
|
||||
if (sinceVersion != null) {
|
||||
builder.append(" in Kotlin ").append(sinceVersion.getVersionString());
|
||||
} else {
|
||||
builder.append(" in a future release");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DiagnosticRenderer<?> get(@NotNull DiagnosticFactory<?> factory) {
|
||||
return map.get(factory);
|
||||
|
||||
+3
-4
@@ -506,10 +506,9 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
OnlyInputTypesDiagnostic::class.java -> {
|
||||
val typeVariable = (error as OnlyInputTypesDiagnostic).typeVariable as? TypeVariableFromCallableDescriptor ?: return
|
||||
psiKotlinCall.psiCall.calleeExpression?.let {
|
||||
val factory = if (context.languageVersionSettings.supportsFeature(LanguageFeature.StrictOnlyInputTypesChecks))
|
||||
TYPE_INFERENCE_ONLY_INPUT_TYPES
|
||||
else TYPE_INFERENCE_ONLY_INPUT_TYPES_WARNING
|
||||
trace.report(factory.on(it, typeVariable.originalTypeParameter))
|
||||
trace.report(
|
||||
TYPE_INFERENCE_ONLY_INPUT_TYPES.on(context.languageVersionSettings, it, typeVariable.originalTypeParameter)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -271,7 +271,7 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
|
||||
}
|
||||
else if (status.hasTypeParameterWithUnsatisfiedOnlyInputTypesError()) {
|
||||
//todo
|
||||
return TYPE_INFERENCE_ONLY_INPUT_TYPES.on(reference, data.descriptor.getTypeParameters().get(0));
|
||||
return TYPE_INFERENCE_ONLY_INPUT_TYPES.getErrorFactory().on(reference, data.descriptor.getTypeParameters().get(0));
|
||||
}
|
||||
else {
|
||||
assert status.hasUnknownParameters();
|
||||
|
||||
Reference in New Issue
Block a user