[FE 1.0] Report warning on non-deprecated overrides of deprecated members
Also don't propagate deprecation status to overrides after 1.7 ^KT-47902 Fixed
This commit is contained in:
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier;
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DescriptorBasedDeprecation;
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
@@ -98,6 +99,8 @@ public interface Errors {
|
||||
VERSION_REQUIREMENT_DEPRECATION = DiagnosticFactory3.create(WARNING);
|
||||
DiagnosticFactory3<PsiElement, DeclarationDescriptor, VersionRequirement.Version, Pair<LanguageVersion, String>>
|
||||
VERSION_REQUIREMENT_DEPRECATION_ERROR = DiagnosticFactory3.create(ERROR);
|
||||
// descriptor and deprecation infos are needed only for IDE quickfix for this warning
|
||||
DiagnosticFactory3<KtNamedDeclaration, String, CallableMemberDescriptor, List<DescriptorBasedDeprecation>> OVERRIDE_DEPRECATION = DiagnosticFactory3.create(WARNING, DECLARATION_NAME);
|
||||
|
||||
DiagnosticFactory0<PsiElement> DEPRECATED_SINCE_KOTLIN_WITHOUT_DEPRECATED = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> DEPRECATED_SINCE_KOTLIN_WITH_DEPRECATED_LEVEL = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
+2
@@ -394,6 +394,8 @@ public class DefaultErrorMessages {
|
||||
(obj, renderingContext) -> obj.equals(VersionRequirement.Version.INFINITY) ? "" : " is only available since Kotlin " + obj.asString() + " and",
|
||||
versionRequirementMessage);
|
||||
|
||||
MAP.put(OVERRIDE_DEPRECATION, "This declaration overrides deprecated member but not marked as deprecated itself. {0}Please add @Deprecated annotation or suppress", TO_STRING, TO_STRING, TO_STRING);
|
||||
|
||||
MAP.put(DEPRECATED_SINCE_KOTLIN_WITHOUT_DEPRECATED, "DeprecatedSinceKotlin annotation can be used only together with Deprecated annotation");
|
||||
MAP.put(DEPRECATED_SINCE_KOTLIN_WITH_DEPRECATED_LEVEL, "DeprecatedSinceKotlin annotation can be used only with unspecified deprecation level of Deprecated annotation");
|
||||
MAP.put(DEPRECATED_SINCE_KOTLIN_WITH_UNORDERED_VERSIONS, "Values of DeprecatedSinceKotlin annotation should be ordered so 'warningSince' <= 'errorSince' <= 'hiddenSince' if specified");
|
||||
|
||||
@@ -38,6 +38,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
||||
TrailingCommaDeclarationChecker,
|
||||
MissingDependencySupertypeChecker.ForDeclarations,
|
||||
FunInterfaceDeclarationChecker(),
|
||||
DeprecationInheritanceChecker,
|
||||
DeprecatedSinceKotlinAnnotationChecker,
|
||||
ContractDescriptionBlockChecker,
|
||||
PrivateInlineFunctionsReturningAnonymousObjectsChecker,
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.resolve.checkers
|
||||
|
||||
import org.jetbrains.kotlin.config.LanguageFeature.StopPropagatingDeprecationThroughOverrides
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
|
||||
object DeprecationInheritanceChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (declaration !is KtNamedDeclaration) return
|
||||
val deprecationResolver = context.deprecationResolver
|
||||
if (!deprecationResolver.areDeprecationsInheritedFromOverriden(descriptor)) return
|
||||
val (deprecations, message) = if (context.languageVersionSettings.supportsFeature(StopPropagatingDeprecationThroughOverrides)) {
|
||||
deprecationResolver.getHiddenDeprecationsFromOverriden(descriptor) to ""
|
||||
} else {
|
||||
deprecationResolver.getDeprecations(descriptor) to "This deprecation won't be inherited in kotlin 1.7. "
|
||||
}
|
||||
context.trace.report(Errors.OVERRIDE_DEPRECATION.on(declaration, message, descriptor, deprecations))
|
||||
}
|
||||
}
|
||||
+42
-11
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.resolve.deprecation
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.StandardNames
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.config.MavenComparableVersion
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.DescriptorDerivedFromTypeAlias
|
||||
import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor
|
||||
@@ -27,23 +24,46 @@ import org.jetbrains.kotlin.resolve.checkers.ExperimentalUsageChecker
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedMemberDescriptor
|
||||
import org.jetbrains.kotlin.storage.MemoizedFunctionToNotNull
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
|
||||
class DeprecationResolver(
|
||||
storageManager: StorageManager,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val deprecationSettings: DeprecationSettings
|
||||
) {
|
||||
private val deprecations = storageManager.createMemoizedFunction { descriptor: DeclarationDescriptor ->
|
||||
val deprecations = descriptor.getOwnDeprecations()
|
||||
when {
|
||||
deprecations.isNotEmpty() -> deprecations
|
||||
descriptor is CallableMemberDescriptor -> listOfNotNull(deprecationByOverridden(descriptor))
|
||||
else -> emptyList()
|
||||
private val deprecations: MemoizedFunctionToNotNull<DeclarationDescriptor, DeprecationInfo> =
|
||||
storageManager.createMemoizedFunction { descriptor ->
|
||||
val deprecations = descriptor.getOwnDeprecations()
|
||||
when {
|
||||
deprecations.isNotEmpty() -> DeprecationInfo(deprecations, hasInheritedDeprecations = false)
|
||||
descriptor is CallableMemberDescriptor -> {
|
||||
val inheritedDeprecations = listOfNotNull(deprecationByOverridden(descriptor))
|
||||
when (inheritedDeprecations.isNotEmpty()) {
|
||||
true -> when (languageVersionSettings.supportsFeature(LanguageFeature.StopPropagatingDeprecationThroughOverrides)) {
|
||||
true -> DeprecationInfo(emptyList(), hasInheritedDeprecations = true, inheritedDeprecations)
|
||||
false -> DeprecationInfo(inheritedDeprecations, hasInheritedDeprecations = true)
|
||||
}
|
||||
false -> DeprecationInfo.EMPTY
|
||||
}
|
||||
}
|
||||
else -> DeprecationInfo.EMPTY
|
||||
}
|
||||
}
|
||||
|
||||
private data class DeprecationInfo(
|
||||
val deprecations: List<DescriptorBasedDeprecation>,
|
||||
val hasInheritedDeprecations: Boolean,
|
||||
val hiddenInheritedDeprecations: List<DescriptorBasedDeprecation> = emptyList()
|
||||
) {
|
||||
companion object {
|
||||
val EMPTY = DeprecationInfo(emptyList(), hasInheritedDeprecations = false, emptyList())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +72,18 @@ class DeprecationResolver(
|
||||
}
|
||||
|
||||
fun getDeprecations(descriptor: DeclarationDescriptor): List<DescriptorBasedDeprecation> =
|
||||
deprecations(descriptor.original)
|
||||
deprecations(descriptor.original).deprecations
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
fun areDeprecationsInheritedFromOverriden(descriptor: DeclarationDescriptor): Boolean {
|
||||
contract {
|
||||
returns(true) implies (descriptor is CallableMemberDescriptor)
|
||||
}
|
||||
return deprecations(descriptor.original).hasInheritedDeprecations
|
||||
}
|
||||
|
||||
fun getHiddenDeprecationsFromOverriden(descriptor: DeclarationDescriptor): List<DescriptorBasedDeprecation> =
|
||||
deprecations(descriptor.original).hiddenInheritedDeprecations
|
||||
|
||||
fun isDeprecatedHidden(descriptor: DeclarationDescriptor): Boolean =
|
||||
getDeprecations(descriptor).any { it.deprecationLevel == DeprecationLevelValue.HIDDEN }
|
||||
|
||||
Reference in New Issue
Block a user