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
@@ -10,8 +10,8 @@ typealias DeprecatedClassAlias = <!DEPRECATION!>DeprecatedClass<!>
typealias WithDeprecatedCtorAlias = WithDeprecatedCtor
typealias ArrayListOfDeprecatedClass = ArrayList<<!DEPRECATION!>DeprecatedClass<!>>
class Test1 : <!DEPRECATION!>DeprecatedClassAlias<!>()
class Test1 : <!TYPEALIAS_EXPANSION_DEPRECATION!>DeprecatedClassAlias<!>()
class Test2 : <!DEPRECATION!>WithDeprecatedCtorAlias<!>()
class Test2 : <!TYPEALIAS_EXPANSION_DEPRECATION!>WithDeprecatedCtorAlias<!>()
val test3 = <!DEPRECATION!>ArrayListOfDeprecatedClass<!>()
val test3 = <!TYPEALIAS_EXPANSION_DEPRECATION!>ArrayListOfDeprecatedClass<!>()
@@ -1,10 +1,21 @@
@Deprecated("")
class Foo
@Deprecated("", level = DeprecationLevel.ERROR)
class Err
typealias Test1 = <!DEPRECATION!>Foo<!>
typealias Test2 = List<<!DEPRECATION!>Foo<!>>
typealias Test3 = List<<!DEPRECATION!>Test2<!>>
typealias Test3 = List<<!TYPEALIAS_EXPANSION_DEPRECATION!>Test2<!>>
fun use1(b: <!DEPRECATION!>Test1<!>) = b
fun use2(b: <!DEPRECATION!>Test2<!>) = b
fun use3(b: <!DEPRECATION!>Test3<!>) = b
typealias TestErr1 = <!DEPRECATION_ERROR!>Err<!>
typealias TestErr2 = List<<!DEPRECATION_ERROR!>Err<!>>
typealias TestErr3 = List<<!TYPEALIAS_EXPANSION_DEPRECATION_ERROR!>TestErr2<!>>
fun use1(b: <!TYPEALIAS_EXPANSION_DEPRECATION!>Test1<!>) = b
fun use2(b: <!TYPEALIAS_EXPANSION_DEPRECATION!>Test2<!>) = b
fun use3(b: <!TYPEALIAS_EXPANSION_DEPRECATION!>Test3<!>) = b
fun useErr1(b: <!TYPEALIAS_EXPANSION_DEPRECATION_ERROR!>TestErr1<!>) = b
fun useErr2(b: <!TYPEALIAS_EXPANSION_DEPRECATION_ERROR!>TestErr2<!>) = b
fun useErr3(b: <!TYPEALIAS_EXPANSION_DEPRECATION_ERROR!>TestErr3<!>) = b
@@ -3,6 +3,16 @@ package
public fun use1(/*0*/ b: Test1 /* = Foo */): Test1 /* = Foo */
public fun use2(/*0*/ b: Test2 /* = kotlin.collections.List<Foo> */): Test2 /* = kotlin.collections.List<Foo> */
public fun use3(/*0*/ b: Test3 /* = kotlin.collections.List<Test2 /* = kotlin.collections.List<Foo> */> */): Test3 /* = kotlin.collections.List<Test2 /* = kotlin.collections.List<Foo> */> */
public fun useErr1(/*0*/ b: TestErr1 /* = Err */): TestErr1 /* = Err */
public fun useErr2(/*0*/ b: TestErr2 /* = kotlin.collections.List<Err> */): TestErr2 /* = kotlin.collections.List<Err> */
public fun useErr3(/*0*/ b: TestErr3 /* = kotlin.collections.List<TestErr2 /* = kotlin.collections.List<Err> */> */): TestErr3 /* = kotlin.collections.List<TestErr2 /* = kotlin.collections.List<Err> */> */
@kotlin.Deprecated(level = DeprecationLevel.ERROR, message = "") public final class Err {
public constructor Err()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.Deprecated(message = "") public final class Foo {
public constructor Foo()
@@ -13,3 +23,6 @@ public fun use3(/*0*/ b: Test3 /* = kotlin.collections.List<Test2 /* = kotlin.co
public typealias Test1 = Foo
public typealias Test2 = kotlin.collections.List<Foo>
public typealias Test3 = kotlin.collections.List<Test2>
public typealias TestErr1 = Err
public typealias TestErr2 = kotlin.collections.List<Err>
public typealias TestErr3 = kotlin.collections.List<TestErr2>