Provide diagnostic for typealias using deprecated class or constructor

#KT-19205 Fixed Target versions 1.1.5
This commit is contained in:
Dmitry Petrov
2017-07-25 17:58:40 +03:00
parent c78ad9c047
commit 0391c24ab2
6 changed files with 84 additions and 22 deletions
@@ -99,6 +99,8 @@ public interface Errors {
DiagnosticFactory2<PsiElement, DeclarationDescriptor, String> DEPRECATION = DiagnosticFactory2.create(WARNING);
DiagnosticFactory2<PsiElement, DeclarationDescriptor, String> DEPRECATION_ERROR = DiagnosticFactory2.create(ERROR);
DiagnosticFactory3<PsiElement, TypeAliasDescriptor, DeclarationDescriptor, String> TYPEALIAS_EXPANSION_DEPRECATION = DiagnosticFactory3.create(WARNING);
DiagnosticFactory3<PsiElement, TypeAliasDescriptor, DeclarationDescriptor, String> TYPEALIAS_EXPANSION_DEPRECATION_ERROR = DiagnosticFactory3.create(ERROR);
DiagnosticFactory3<PsiElement, DeclarationDescriptor, SinceKotlinInfo.Version, Pair<LanguageVersion, String>> SINCE_KOTLIN_INFO_DEPRECATION = DiagnosticFactory3.create(WARNING);
DiagnosticFactory3<PsiElement, DeclarationDescriptor, SinceKotlinInfo.Version, Pair<LanguageVersion, String>> SINCE_KOTLIN_INFO_DEPRECATION_ERROR = DiagnosticFactory3.create(ERROR);
@@ -322,14 +322,19 @@ public class DefaultErrorMessages {
MAP.put(DEPRECATION, "''{0}'' is deprecated. {1}", DEPRECATION_RENDERER, STRING);
MAP.put(DEPRECATION_ERROR, "Using ''{0}'' is an error. {1}", DEPRECATION_RENDERER, STRING);
MAP.put(TYPEALIAS_EXPANSION_DEPRECATION, "''{0}'' uses ''{1}'', which is deprecated. {2}", DEPRECATION_RENDERER, DEPRECATION_RENDERER, STRING);
MAP.put(TYPEALIAS_EXPANSION_DEPRECATION_ERROR, "''{0}'' uses ''{1}'', which is an error. {2}", DEPRECATION_RENDERER, DEPRECATION_RENDERER, STRING);
DiagnosticParameterRenderer<Pair<LanguageVersion, String>> sinceKotlinInfoMessage = (pair, renderingContext) -> {
String message = pair.getSecond();
return pair.getFirst().getVersionString() + (message != null ? ". " + message : "");
};
MAP.put(SINCE_KOTLIN_INFO_DEPRECATION, "''{0}''{1} should not be used in Kotlin {2}", DEPRECATION_RENDERER,
(obj, renderingContext) -> obj.equals(SinceKotlinInfo.Version.INFINITY) ? "" : " is only supported since Kotlin " + obj.asString() + " and", sinceKotlinInfoMessage);
(obj, renderingContext) -> obj.equals(SinceKotlinInfo.Version.INFINITY) ? "" : " is only supported since Kotlin " + obj.asString() + " and",
sinceKotlinInfoMessage);
MAP.put(SINCE_KOTLIN_INFO_DEPRECATION_ERROR, "''{0}''{1} cannot be used in Kotlin {2}", DEPRECATION_RENDERER,
(obj, renderingContext) -> obj.equals(SinceKotlinInfo.Version.INFINITY) ? "" : " is only available since Kotlin " + obj.asString() + " and", sinceKotlinInfoMessage);
(obj, renderingContext) -> obj.equals(SinceKotlinInfo.Version.INFINITY) ? "" : " is only available since Kotlin " + obj.asString() + " and",
sinceKotlinInfoMessage);
MAP.put(API_NOT_AVAILABLE, "This declaration is only available since Kotlin {0} and cannot be used with the specified API version {1}", STRING, STRING);
@@ -131,6 +131,20 @@ private data class DeprecatedBySinceKotlinInfo(
get() = sinceKotlinInfo.version
}
private data class DeprecatedTypealiasByAnnotation(
val typeAliasTarget: TypeAliasDescriptor,
val nested: DeprecatedByAnnotation
) : Deprecation {
override val target get() = typeAliasTarget
override val deprecationLevel get() = nested.deprecationLevel
override val message get() = nested.message
}
private fun Deprecation.wrapInTypeAliasExpansion(typeAliasDescriptor: TypeAliasDescriptor) = when {
this is DeprecatedByAnnotation -> DeprecatedTypealiasByAnnotation(typeAliasDescriptor, this)
else -> this
}
fun DeclarationDescriptor.getDeprecations(languageVersionSettings: LanguageVersionSettings): List<Deprecation> {
val deprecations = this.getOwnDeprecations(languageVersionSettings)
if (deprecations.isNotEmpty()) {
@@ -201,7 +215,12 @@ private fun DeclarationDescriptor.getOwnDeprecations(languageVersionSettings: La
val annotation = target.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.deprecated)
?: target.annotations.findAnnotation(JAVA_DEPRECATED)
if (annotation != null) {
result.add(DeprecatedByAnnotation(annotation, target))
val deprecatedByAnnotation = DeprecatedByAnnotation(annotation, target)
val deprecation = when (target) {
is TypeAliasConstructorDescriptor -> DeprecatedTypealiasByAnnotation(target.typeAliasDescriptor, deprecatedByAnnotation)
else -> deprecatedByAnnotation
}
result.add(deprecation)
}
val sinceKotlinInfo =
@@ -232,7 +251,7 @@ private fun DeclarationDescriptor.getOwnDeprecations(languageVersionSettings: La
when (this) {
is TypeAliasDescriptor -> {
result.addAll(expandedType.deprecationsByConstituentTypes(languageVersionSettings))
expandedType.deprecationsByConstituentTypes(languageVersionSettings).mapTo(result) { it.wrapInTypeAliasExpansion(this) }
}
is TypeAliasConstructorDescriptor -> {
result.addAll(typeAliasDescriptor.getOwnDeprecations(languageVersionSettings))
@@ -257,20 +276,32 @@ internal fun createDeprecationDiagnostic(
element: PsiElement, deprecation: Deprecation, languageVersionSettings: LanguageVersionSettings
): Diagnostic {
val targetOriginal = deprecation.target.original
if (deprecation is DeprecatedBySinceKotlinInfo) {
val factory = when (deprecation.deprecationLevel) {
WARNING -> Errors.SINCE_KOTLIN_INFO_DEPRECATION
ERROR, HIDDEN -> Errors.SINCE_KOTLIN_INFO_DEPRECATION_ERROR
return when (deprecation) {
is DeprecatedBySinceKotlinInfo -> {
val factory = when (deprecation.deprecationLevel) {
WARNING -> Errors.SINCE_KOTLIN_INFO_DEPRECATION
ERROR, HIDDEN -> Errors.SINCE_KOTLIN_INFO_DEPRECATION_ERROR
}
factory.on(element, targetOriginal, deprecation.sinceKotlinVersion,
languageVersionSettings.languageVersion to deprecation.message)
}
return factory.on(element, targetOriginal, deprecation.sinceKotlinVersion,
languageVersionSettings.languageVersion to deprecation.message)
}
val factory = when (deprecation.deprecationLevel) {
WARNING -> Errors.DEPRECATION
ERROR, HIDDEN -> Errors.DEPRECATION_ERROR
is DeprecatedTypealiasByAnnotation -> {
val factory = when (deprecation.deprecationLevel) {
WARNING -> Errors.TYPEALIAS_EXPANSION_DEPRECATION
ERROR, HIDDEN -> Errors.TYPEALIAS_EXPANSION_DEPRECATION_ERROR
}
factory.on(element, deprecation.typeAliasTarget.original, deprecation.nested.target.original, deprecation.nested.message ?: "")
}
else -> {
val factory = when (deprecation.deprecationLevel) {
WARNING -> Errors.DEPRECATION
ERROR, HIDDEN -> Errors.DEPRECATION_ERROR
}
factory.on(element, targetOriginal, deprecation.message ?: "")
}
}
return factory.on(element, targetOriginal, deprecation.message ?: "")
}
// values from kotlin.DeprecationLevel