[FIR] Expand typealiases when checking deprecations
^KT-59901 Fixed
This commit is contained in:
committed by
Space Team
parent
03fdba5aa7
commit
4a9ba1c9ac
+7
-7
@@ -44,13 +44,13 @@ internal class KtFirSymbolInfoProvider(
|
|||||||
|
|
||||||
return when (val firSymbol = symbol.firSymbol) {
|
return when (val firSymbol = symbol.firSymbol) {
|
||||||
is FirPropertySymbol -> {
|
is FirPropertySymbol -> {
|
||||||
firSymbol.getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.PROPERTY)
|
firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession, AnnotationUseSiteTarget.PROPERTY)
|
||||||
}
|
}
|
||||||
is FirBackingFieldSymbol -> {
|
is FirBackingFieldSymbol -> {
|
||||||
firSymbol.getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.FIELD)
|
firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession, AnnotationUseSiteTarget.FIELD)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
firSymbol.getDeprecationForCallSite(apiVersion)
|
firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,9 +67,9 @@ internal class KtFirSymbolInfoProvider(
|
|||||||
override fun getDeprecation(symbol: KtSymbol, annotationUseSiteTarget: AnnotationUseSiteTarget?): DeprecationInfo? {
|
override fun getDeprecation(symbol: KtSymbol, annotationUseSiteTarget: AnnotationUseSiteTarget?): DeprecationInfo? {
|
||||||
require(symbol is KtFirSymbol<*>)
|
require(symbol is KtFirSymbol<*>)
|
||||||
return if (annotationUseSiteTarget != null) {
|
return if (annotationUseSiteTarget != null) {
|
||||||
symbol.firSymbol.getDeprecationForCallSite(apiVersion, annotationUseSiteTarget)
|
symbol.firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession, annotationUseSiteTarget)
|
||||||
} else {
|
} else {
|
||||||
symbol.firSymbol.getDeprecationForCallSite(apiVersion)
|
symbol.firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ internal class KtFirSymbolInfoProvider(
|
|||||||
override fun getGetterDeprecation(symbol: KtPropertySymbol): DeprecationInfo? {
|
override fun getGetterDeprecation(symbol: KtPropertySymbol): DeprecationInfo? {
|
||||||
require(symbol is KtFirSymbol<*>)
|
require(symbol is KtFirSymbol<*>)
|
||||||
return symbol.firSymbol.getDeprecationForCallSite(
|
return symbol.firSymbol.getDeprecationForCallSite(
|
||||||
apiVersion,
|
analysisSession.useSiteSession,
|
||||||
AnnotationUseSiteTarget.PROPERTY_GETTER,
|
AnnotationUseSiteTarget.PROPERTY_GETTER,
|
||||||
AnnotationUseSiteTarget.PROPERTY,
|
AnnotationUseSiteTarget.PROPERTY,
|
||||||
)
|
)
|
||||||
@@ -87,7 +87,7 @@ internal class KtFirSymbolInfoProvider(
|
|||||||
override fun getSetterDeprecation(symbol: KtPropertySymbol): DeprecationInfo? {
|
override fun getSetterDeprecation(symbol: KtPropertySymbol): DeprecationInfo? {
|
||||||
require(symbol is KtFirSymbol<*>)
|
require(symbol is KtFirSymbol<*>)
|
||||||
return symbol.firSymbol.getDeprecationForCallSite(
|
return symbol.firSymbol.getDeprecationForCallSite(
|
||||||
apiVersion,
|
analysisSession.useSiteSession,
|
||||||
AnnotationUseSiteTarget.PROPERTY_SETTER,
|
AnnotationUseSiteTarget.PROPERTY_SETTER,
|
||||||
AnnotationUseSiteTarget.PROPERTY,
|
AnnotationUseSiteTarget.PROPERTY,
|
||||||
)
|
)
|
||||||
|
|||||||
-1
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.checkers
|
package org.jetbrains.kotlin.fir.analysis.checkers
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.type.FirUnsupportedDefaultValueInFunctionTypeParameterChecker
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.type.*
|
import org.jetbrains.kotlin.fir.analysis.checkers.type.*
|
||||||
|
|
||||||
object CommonTypeCheckers : TypeCheckers() {
|
object CommonTypeCheckers : TypeCheckers() {
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ object FirOptInLanguageVersionSettingsChecker : FirLanguageVersionSettingsChecke
|
|||||||
rawReport(false, "Class $fqNameAsString is not an opt-in requirement marker")
|
rawReport(false, "Class $fqNameAsString is not an opt-in requirement marker")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val deprecationInfo = symbol.getDeprecation(context.languageVersionSettings.apiVersion)?.all ?: return
|
val deprecationInfo = symbol.getOwnDeprecation(context.languageVersionSettings.apiVersion)?.all ?: return
|
||||||
rawReport(
|
rawReport(
|
||||||
deprecationInfo.deprecationLevel != DeprecationLevelValue.WARNING,
|
deprecationInfo.deprecationLevel != DeprecationLevelValue.WARNING,
|
||||||
"Opt-in requirement marker $fqNameAsString is deprecated" + deprecationInfo.message?.let { ". $it" }.orEmpty()
|
"Opt-in requirement marker $fqNameAsString is deprecated" + deprecationInfo.message?.let { ". $it" }.orEmpty()
|
||||||
|
|||||||
+3
-2
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
|||||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.getContainingFile
|
import org.jetbrains.kotlin.fir.resolve.providers.getContainingFile
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.providers.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
import org.jetbrains.kotlin.fir.scopes.FirContainingNamesAwareScope
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
||||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
@@ -298,7 +299,7 @@ object FirImportsChecker : FirFileChecker() {
|
|||||||
val importedFqName = import.importedFqName ?: return
|
val importedFqName = import.importedFqName ?: return
|
||||||
if (importedFqName.isRoot || importedFqName.shortName().asString().isEmpty()) return
|
if (importedFqName.isRoot || importedFqName.shortName().asString().isEmpty()) return
|
||||||
val classId = (import as? FirResolvedImport)?.resolvedParentClassId ?: ClassId.topLevel(importedFqName)
|
val classId = (import as? FirResolvedImport)?.resolvedParentClassId ?: ClassId.topLevel(importedFqName)
|
||||||
val classLike: FirRegularClassSymbol = classId.resolveToClass(context) ?: return
|
val symbol = classId.toSymbol(context.session) ?: return
|
||||||
FirDeprecationChecker.reportApiStatusIfNeeded(import.source, classLike, context, reporter)
|
FirDeprecationChecker.reportApiStatusIfNeeded(import.source, symbol, context, reporter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -14,7 +14,10 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
|||||||
object FirDeprecatedQualifierChecker : FirResolvedQualifierChecker() {
|
object FirDeprecatedQualifierChecker : FirResolvedQualifierChecker() {
|
||||||
override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
expression.nonFatalDiagnostics.filterIsInstance<ConeDeprecated>().forEach { diagnostic ->
|
expression.nonFatalDiagnostics.filterIsInstance<ConeDeprecated>().forEach { diagnostic ->
|
||||||
FirDeprecationChecker.reportApiStatus(diagnostic.source, diagnostic.symbol, null, diagnostic.deprecationInfo, reporter, context)
|
FirDeprecationChecker.reportApiStatus(
|
||||||
|
diagnostic.source, diagnostic.symbol, isTypealiasExpansion = false,
|
||||||
|
diagnostic.deprecationInfo, reporter, context
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if (expression.resolvedToCompanionObject) {
|
if (expression.resolvedToCompanionObject) {
|
||||||
val companionSymbol = (expression.symbol as? FirRegularClassSymbol)?.companionObjectSymbol ?: return
|
val companionSymbol = (expression.symbol as? FirRegularClassSymbol)?.companionObjectSymbol ?: return
|
||||||
|
|||||||
+43
-34
@@ -12,18 +12,18 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
|||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
import org.jetbrains.kotlin.fir.FirElement
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
import org.jetbrains.kotlin.fir.declarations.FutureApiDeprecationInfo
|
import org.jetbrains.kotlin.fir.declarations.FutureApiDeprecationInfo
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.isLhsOfAssignment
|
import org.jetbrains.kotlin.fir.analysis.checkers.isLhsOfAssignment
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.type.FirDeprecatedTypeChecker
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.getDeprecation
|
import org.jetbrains.kotlin.fir.declarations.getDeprecation
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.getOwnDeprecation
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.references.resolved
|
import org.jetbrains.kotlin.fir.references.resolved
|
||||||
import org.jetbrains.kotlin.fir.resolve.firClassLike
|
import org.jetbrains.kotlin.fir.resolve.firClassLike
|
||||||
import org.jetbrains.kotlin.fir.resolve.typeAliasForConstructor
|
import org.jetbrains.kotlin.fir.resolve.typeAliasForConstructor
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
|
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
|
||||||
@@ -43,31 +43,18 @@ object FirDeprecationChecker : FirBasicExpressionChecker() {
|
|||||||
|
|
||||||
val calleeReference = expression.calleeReference ?: return
|
val calleeReference = expression.calleeReference ?: return
|
||||||
val resolvedReference = calleeReference.resolved ?: return
|
val resolvedReference = calleeReference.resolved ?: return
|
||||||
val source = resolvedReference.source
|
|
||||||
val referencedSymbol = resolvedReference.resolvedSymbol
|
val referencedSymbol = resolvedReference.resolvedSymbol
|
||||||
|
|
||||||
// If this is a constructor call through a typealias, we want to check deprecations on the typealias itself as well as any
|
|
||||||
// intermediary expansions.
|
|
||||||
// However, we'll already check the final expansion below, so we don't want to do it here as well to prevent duplicate diagnostics.
|
|
||||||
val typeAliasForConstructor = (referencedSymbol as? FirConstructorSymbol)?.typeAliasForConstructor
|
|
||||||
if (typeAliasForConstructor != null && expression is FirQualifiedAccessExpression) {
|
|
||||||
FirDeprecatedTypeChecker.reportDeprecationsRecursively(
|
|
||||||
typeAliasForConstructor,
|
|
||||||
source,
|
|
||||||
context,
|
|
||||||
reporter,
|
|
||||||
// We pass the containing class symbol to ignore the final expansion.
|
|
||||||
symbolToIgnore = referencedSymbol.getContainingClassSymbol(context.session)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expression is FirDelegatedConstructorCall) {
|
if (expression is FirDelegatedConstructorCall) {
|
||||||
// Report deprecations on the constructor itself, not on the declaring class as that will be handled by FirDeprecatedTypeChecker
|
// Report deprecations on the constructor itself, not on the declaring class as that will be handled by FirDeprecatedTypeChecker
|
||||||
val constructorOnlyDeprecation = referencedSymbol.getDeprecation(context.session, expression) ?: return
|
val constructorOnlyDeprecation = referencedSymbol.getDeprecation(context.session, expression) ?: return
|
||||||
val typealiasSymbol = expression.constructedTypeRef.firClassLike(context.session)?.symbol as? FirTypeAliasSymbol
|
val isTypealiasExpansion = expression.constructedTypeRef.firClassLike(context.session)?.symbol is FirTypeAliasSymbol
|
||||||
reportApiStatus(source, referencedSymbol, typealiasSymbol, constructorOnlyDeprecation, reporter, context)
|
reportApiStatus(
|
||||||
|
resolvedReference.source, referencedSymbol, isTypealiasExpansion,
|
||||||
|
constructorOnlyDeprecation, reporter, context
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
reportApiStatusIfNeeded(source, referencedSymbol, context, reporter, typeAliasForConstructor, callSite = expression)
|
reportApiStatusIfNeeded(resolvedReference.source, referencedSymbol, context, reporter, callSite = expression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,17 +63,36 @@ object FirDeprecationChecker : FirBasicExpressionChecker() {
|
|||||||
referencedSymbol: FirBasedSymbol<*>,
|
referencedSymbol: FirBasedSymbol<*>,
|
||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
reporter: DiagnosticReporter,
|
reporter: DiagnosticReporter,
|
||||||
typealiasSymbol: FirTypeAliasSymbol? = null,
|
|
||||||
callSite: FirElement? = null,
|
callSite: FirElement? = null,
|
||||||
) {
|
) {
|
||||||
val deprecation = getWorstDeprecation(callSite, referencedSymbol, context) ?: return
|
val deprecation = getWorstDeprecation(callSite, referencedSymbol, context) ?: return
|
||||||
reportApiStatus(source, referencedSymbol, typealiasSymbol, deprecation, reporter, context)
|
val isTypealiasExpansion = deprecation.isTypealiasExpansionOf(referencedSymbol, callSite, context)
|
||||||
|
reportApiStatus(source, referencedSymbol, isTypealiasExpansion, deprecation, reporter, context)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DeprecationInfo.isTypealiasExpansionOf(
|
||||||
|
referencedSymbol: FirBasedSymbol<*>,
|
||||||
|
callSite: FirElement?,
|
||||||
|
context: CheckerContext,
|
||||||
|
): Boolean = when (referencedSymbol) {
|
||||||
|
is FirConstructorSymbol -> referencedSymbol.typeAliasForConstructor
|
||||||
|
?.let { isTypealiasExpansionOf(it, callSite, context) }
|
||||||
|
?: false
|
||||||
|
!is FirTypeAliasSymbol -> false
|
||||||
|
else -> referencedSymbol.getOwnDeprecation(context.session, callSite).let {
|
||||||
|
// If 2 deprecations along a typealias "expansion chain"
|
||||||
|
// are equivalent (a <= b && a >= b), then getDeprecation()
|
||||||
|
// has returned the first of them.
|
||||||
|
// When calling getWorstDeprecation(), deprecations
|
||||||
|
// from typealiases should come first.
|
||||||
|
it == null || it < this
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun reportApiStatus(
|
internal fun reportApiStatus(
|
||||||
source: KtSourceElement?,
|
source: KtSourceElement?,
|
||||||
referencedSymbol: FirBasedSymbol<*>,
|
referencedSymbol: FirBasedSymbol<*>,
|
||||||
typealiasSymbol: FirTypeAliasSymbol?,
|
isTypealiasExpansion: Boolean,
|
||||||
deprecationInfo: DeprecationInfo,
|
deprecationInfo: DeprecationInfo,
|
||||||
reporter: DiagnosticReporter,
|
reporter: DiagnosticReporter,
|
||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
@@ -94,19 +100,19 @@ object FirDeprecationChecker : FirBasicExpressionChecker() {
|
|||||||
if (deprecationInfo is FutureApiDeprecationInfo) {
|
if (deprecationInfo is FutureApiDeprecationInfo) {
|
||||||
reportApiNotAvailable(source, deprecationInfo, reporter, context)
|
reportApiNotAvailable(source, deprecationInfo, reporter, context)
|
||||||
} else {
|
} else {
|
||||||
reportDeprecation(source, referencedSymbol, typealiasSymbol, deprecationInfo, reporter, context)
|
reportDeprecation(source, referencedSymbol, isTypealiasExpansion, deprecationInfo, reporter, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reportDeprecation(
|
private fun reportDeprecation(
|
||||||
source: KtSourceElement?,
|
source: KtSourceElement?,
|
||||||
referencedSymbol: FirBasedSymbol<*>,
|
referencedSymbol: FirBasedSymbol<*>,
|
||||||
typealiasSymbol: FirTypeAliasSymbol?,
|
isTypealiasExpansion: Boolean,
|
||||||
deprecationInfo: DeprecationInfo,
|
deprecationInfo: DeprecationInfo,
|
||||||
reporter: DiagnosticReporter,
|
reporter: DiagnosticReporter,
|
||||||
context: CheckerContext,
|
context: CheckerContext
|
||||||
) {
|
) {
|
||||||
if (typealiasSymbol == null) {
|
if (!isTypealiasExpansion) {
|
||||||
val diagnostic = when (deprecationInfo.deprecationLevel) {
|
val diagnostic = when (deprecationInfo.deprecationLevel) {
|
||||||
DeprecationLevelValue.ERROR, DeprecationLevelValue.HIDDEN -> FirErrors.DEPRECATION_ERROR
|
DeprecationLevelValue.ERROR, DeprecationLevelValue.HIDDEN -> FirErrors.DEPRECATION_ERROR
|
||||||
DeprecationLevelValue.WARNING -> FirErrors.DEPRECATION
|
DeprecationLevelValue.WARNING -> FirErrors.DEPRECATION
|
||||||
@@ -117,7 +123,7 @@ object FirDeprecationChecker : FirBasicExpressionChecker() {
|
|||||||
DeprecationLevelValue.ERROR, DeprecationLevelValue.HIDDEN -> FirErrors.TYPEALIAS_EXPANSION_DEPRECATION_ERROR
|
DeprecationLevelValue.ERROR, DeprecationLevelValue.HIDDEN -> FirErrors.TYPEALIAS_EXPANSION_DEPRECATION_ERROR
|
||||||
DeprecationLevelValue.WARNING -> FirErrors.TYPEALIAS_EXPANSION_DEPRECATION
|
DeprecationLevelValue.WARNING -> FirErrors.TYPEALIAS_EXPANSION_DEPRECATION
|
||||||
}
|
}
|
||||||
reporter.reportOn(source, diagnostic, typealiasSymbol, referencedSymbol, deprecationInfo.message ?: "", context)
|
reporter.reportOn(source, diagnostic, referencedSymbol, referencedSymbol, deprecationInfo.message ?: "", context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,15 +145,18 @@ object FirDeprecationChecker : FirBasicExpressionChecker() {
|
|||||||
private fun getWorstDeprecation(
|
private fun getWorstDeprecation(
|
||||||
callSite: FirElement?,
|
callSite: FirElement?,
|
||||||
symbol: FirBasedSymbol<*>,
|
symbol: FirBasedSymbol<*>,
|
||||||
context: CheckerContext,
|
context: CheckerContext
|
||||||
): DeprecationInfo? {
|
): DeprecationInfo? {
|
||||||
val deprecationInfos = listOfNotNull(
|
val deprecationInfos = listOfNotNull(
|
||||||
symbol.getDeprecation(context.session, callSite),
|
|
||||||
(symbol as? FirConstructorSymbol)
|
(symbol as? FirConstructorSymbol)
|
||||||
?.resolvedReturnTypeRef
|
?.classSymbolItIsCalledThrough(context)
|
||||||
?.toRegularClassSymbol(context.session)
|
?.getDeprecation(context.session, callSite),
|
||||||
?.getDeprecation(context.session, callSite)
|
symbol.getDeprecation(context.session, callSite),
|
||||||
)
|
)
|
||||||
return deprecationInfos.maxOrNull()
|
return deprecationInfos.maxOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun FirConstructorSymbol.classSymbolItIsCalledThrough(context: CheckerContext): FirClassLikeSymbol<*>? {
|
||||||
|
return typeAliasForConstructor ?: (resolvedReturnTypeRef.toRegularClassSymbol(context.session))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-52
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirDeprecationCheck
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
@@ -24,58 +23,9 @@ object FirDeprecatedTypeChecker : FirTypeRefChecker() {
|
|||||||
if (source.kind is KtFakeSourceElementKind) return
|
if (source.kind is KtFakeSourceElementKind) return
|
||||||
|
|
||||||
val resolved = typeRef.coneTypeSafe<ConeClassLikeType>() ?: return
|
val resolved = typeRef.coneTypeSafe<ConeClassLikeType>() ?: return
|
||||||
checkType(resolved, null, source, context, reporter, symbolToIgnore = null)
|
val symbol = resolved.lookupTag.toSymbol(context.session) ?: return
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkType(
|
FirDeprecationChecker.reportApiStatusIfNeeded(source, symbol, context, reporter)
|
||||||
type: ConeClassLikeType,
|
|
||||||
typeAliasSymbol: FirTypeAliasSymbol?,
|
|
||||||
source: KtSourceElement?,
|
|
||||||
context: CheckerContext,
|
|
||||||
reporter: DiagnosticReporter,
|
|
||||||
symbolToIgnore: FirClassLikeSymbol<*>?,
|
|
||||||
) {
|
|
||||||
val symbol = type.lookupTag.toSymbol(context.session) ?: return
|
|
||||||
reportDeprecationsRecursively(symbol, typeAliasSymbol, source, context, reporter, symbolToIgnore)
|
|
||||||
}
|
|
||||||
|
|
||||||
@OptIn(SymbolInternals::class)
|
|
||||||
private fun reportDeprecationsRecursively(
|
|
||||||
symbol: FirClassLikeSymbol<*>,
|
|
||||||
// If not-null, TYPEALIAS_EXPANSION_DEPRECATION will be reported instead of DEPRECATION.
|
|
||||||
typeAliasSymbol: FirTypeAliasSymbol?,
|
|
||||||
source: KtSourceElement?,
|
|
||||||
context: CheckerContext,
|
|
||||||
reporter: DiagnosticReporter,
|
|
||||||
symbolToIgnore: FirClassLikeSymbol<*>?,
|
|
||||||
) {
|
|
||||||
if (symbol == symbolToIgnore) return
|
|
||||||
|
|
||||||
FirDeprecationChecker.reportApiStatusIfNeeded(source, symbol, context, reporter, typealiasSymbol = typeAliasSymbol)
|
|
||||||
if (symbol is FirTypeAliasSymbol) {
|
|
||||||
val typeAlias = symbol.fir
|
|
||||||
typeAlias.lazyResolveToPhase(FirResolvePhase.TYPES)
|
|
||||||
typeAlias.expandedTypeRef.coneType.forEachType {
|
|
||||||
if (it is ConeClassLikeType) checkType(it, symbol, source, context, reporter, symbolToIgnore)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reports deprecations on [symbol]. If [symbol] is a typealias, deprecations will be reported on the expansions recursively.
|
|
||||||
*
|
|
||||||
* @param symbolToIgnore If equal to [symbol], no deprecations on the [symbol] and its expansions will be reported.
|
|
||||||
* It's passed to recursive calls and can be used to only report deprecations on a typealias and its intermediary expansions
|
|
||||||
* but not on the final expansion if set to the fully expanded class symbol.
|
|
||||||
*/
|
|
||||||
fun reportDeprecationsRecursively(
|
|
||||||
symbol: FirClassLikeSymbol<*>,
|
|
||||||
source: KtSourceElement?,
|
|
||||||
context: CheckerContext,
|
|
||||||
reporter: DiagnosticReporter,
|
|
||||||
symbolToIgnore: FirClassLikeSymbol<*>?,
|
|
||||||
) {
|
|
||||||
reportDeprecationsRecursively(symbol, typeAliasSymbol = null, source, context, reporter, symbolToIgnore)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ private fun JavaAnnotation.toFirAnnotationCall(session: FirSession): FirAnnotati
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is required to avoid contract violation during [org.jetbrains.kotlin.fir.declarations.getDeprecationForCallSite]
|
* This is required to avoid contract violation during [org.jetbrains.kotlin.fir.declarations.getOwnDeprecationForCallSite]
|
||||||
* Because argument transformation may lead to [org.jetbrains.kotlin.fir.declarations.FirResolvePhase.TYPES]+ lazy resolution
|
* Because argument transformation may lead to [org.jetbrains.kotlin.fir.declarations.FirResolvePhase.TYPES]+ lazy resolution
|
||||||
* See KT-59342
|
* See KT-59342
|
||||||
* TODO: KT-60520
|
* TODO: KT-60520
|
||||||
|
|||||||
+71
-18
@@ -19,6 +19,10 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.forEachType
|
||||||
|
import org.jetbrains.kotlin.fir.types.toSymbol
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds
|
import org.jetbrains.kotlin.name.StandardClassIds
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames
|
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames
|
||||||
@@ -71,24 +75,33 @@ inline fun buildDeprecationAnnotationInfoPerUseSiteStorage(builder: DeprecationA
|
|||||||
return DeprecationAnnotationInfoPerUseSiteStorageBuilder().apply(builder).build()
|
return DeprecationAnnotationInfoPerUseSiteStorageBuilder().apply(builder).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirBasedSymbol<*>.getDeprecation(session: FirSession, callSite: FirElement?): DeprecationInfo? {
|
private fun FirBasedSymbol<*>.getUseSitesForCallSite(callSite: FirElement?): Array<AnnotationUseSiteTarget> {
|
||||||
return getDeprecation(session.languageVersionSettings.apiVersion, callSite)
|
return when (this) {
|
||||||
|
is FirPropertySymbol -> when (callSite) {
|
||||||
|
is FirVariableAssignment -> arrayOf(AnnotationUseSiteTarget.PROPERTY_SETTER, AnnotationUseSiteTarget.PROPERTY)
|
||||||
|
is FirPropertyAccessExpression -> arrayOf(AnnotationUseSiteTarget.PROPERTY_GETTER, AnnotationUseSiteTarget.PROPERTY)
|
||||||
|
else -> arrayOf(AnnotationUseSiteTarget.PROPERTY)
|
||||||
|
}
|
||||||
|
else -> arrayOf()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirBasedSymbol<*>.getDeprecation(apiVersion: ApiVersion, callSite: FirElement?): DeprecationInfo? {
|
/**
|
||||||
return when (this) {
|
* Returns deprecation that is declared on the
|
||||||
is FirPropertySymbol ->
|
* corresponding declaration.
|
||||||
when (callSite) {
|
*/
|
||||||
is FirVariableAssignment ->
|
fun FirBasedSymbol<*>.getOwnDeprecation(session: FirSession, callSite: FirElement?): DeprecationInfo? {
|
||||||
getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.PROPERTY_SETTER, AnnotationUseSiteTarget.PROPERTY)
|
return getOwnDeprecationForCallSite(session.languageVersionSettings.apiVersion, *getUseSitesForCallSite(callSite))
|
||||||
is FirPropertyAccessExpression ->
|
}
|
||||||
getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.PROPERTY_GETTER, AnnotationUseSiteTarget.PROPERTY)
|
|
||||||
else ->
|
/**
|
||||||
getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.PROPERTY)
|
* Returns deprecation that is declared on
|
||||||
}
|
* the corresponding declaration directly
|
||||||
else ->
|
* or, in case of a typealias, on any of
|
||||||
getDeprecationForCallSite(apiVersion)
|
* its expansions.
|
||||||
}
|
*/
|
||||||
|
fun FirBasedSymbol<*>.getDeprecation(session: FirSession, callSite: FirElement?): DeprecationInfo? {
|
||||||
|
return getDeprecationForCallSite(session, *getUseSitesForCallSite(callSite))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirAnnotationContainer.getDeprecationsProvider(session: FirSession): DeprecationsProvider {
|
fun FirAnnotationContainer.getDeprecationsProvider(session: FirSession): DeprecationsProvider {
|
||||||
@@ -162,18 +175,58 @@ fun List<FirAnnotation>.getDeprecationsProviderFromAnnotations(
|
|||||||
return deprecationAnnotationByUseSite.toDeprecationsProvider(session.firCachesFactory)
|
return deprecationAnnotationByUseSite.toDeprecationsProvider(session.firCachesFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun FirBasedSymbol<*>.getDeprecationForCallSite(
|
/**
|
||||||
|
* Returns deprecation that is declared on the
|
||||||
|
* corresponding declaration.
|
||||||
|
*/
|
||||||
|
private fun FirBasedSymbol<*>.getOwnDeprecationForCallSite(
|
||||||
apiVersion: ApiVersion,
|
apiVersion: ApiVersion,
|
||||||
vararg sites: AnnotationUseSiteTarget
|
vararg sites: AnnotationUseSiteTarget
|
||||||
): DeprecationInfo? {
|
): DeprecationInfo? {
|
||||||
val deprecations = when (this) {
|
val deprecations = when (this) {
|
||||||
is FirCallableSymbol<*> -> getDeprecation(apiVersion)
|
is FirCallableSymbol<*> -> getDeprecation(apiVersion)
|
||||||
is FirClassLikeSymbol<*> -> getDeprecation(apiVersion)
|
is FirClassLikeSymbol<*> -> getOwnDeprecation(apiVersion)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
return (deprecations ?: EmptyDeprecationsPerUseSite).forUseSite(*sites)
|
return (deprecations ?: EmptyDeprecationsPerUseSite).forUseSite(*sites)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns deprecation that is declared on
|
||||||
|
* the corresponding declaration directly
|
||||||
|
* or, in case of a typealias, on any of
|
||||||
|
* its expansions.
|
||||||
|
*/
|
||||||
|
fun FirBasedSymbol<*>.getDeprecationForCallSite(
|
||||||
|
session: FirSession,
|
||||||
|
vararg sites: AnnotationUseSiteTarget,
|
||||||
|
): DeprecationInfo? {
|
||||||
|
val apiVersion = session.languageVersionSettings.apiVersion
|
||||||
|
|
||||||
|
return when (this) {
|
||||||
|
!is FirTypeAliasSymbol -> getOwnDeprecationForCallSite(apiVersion, *sites)
|
||||||
|
else -> {
|
||||||
|
var worstDeprecationInfo = getOwnDeprecationForCallSite(apiVersion, *sites)
|
||||||
|
val visited = mutableMapOf<ConeKotlinType, DeprecationInfo?>()
|
||||||
|
|
||||||
|
resolvedExpandedTypeRef.type.forEachType {
|
||||||
|
val deprecationInfo = visited.getOrPut(it) {
|
||||||
|
val symbol = it.toSymbol(session) ?: return@forEachType
|
||||||
|
symbol.getDeprecationForCallSite(session, *sites)
|
||||||
|
} ?: return@forEachType
|
||||||
|
|
||||||
|
val currentWorstDeprecation = worstDeprecationInfo
|
||||||
|
|
||||||
|
if (currentWorstDeprecation == null || deprecationInfo > currentWorstDeprecation) {
|
||||||
|
worstDeprecationInfo = deprecationInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
worstDeprecationInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun FirAnnotation.getVersionFromArgument(name: Name): ApiVersion? =
|
private fun FirAnnotation.getVersionFromArgument(name: Name): ApiVersion? =
|
||||||
getStringArgument(name)?.let { ApiVersion.parse(it) }
|
getStringArgument(name)?.let { ApiVersion.parse(it) }
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.KtSourceElement
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
import org.jetbrains.kotlin.config.ApiVersion
|
import org.jetbrains.kotlin.config.ApiVersion
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||||
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass
|
import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass
|
||||||
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
|
||||||
@@ -22,8 +21,6 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDeprecated
|
|||||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.resultType
|
||||||
import org.jetbrains.kotlin.fir.resolve.typeForQualifier
|
import org.jetbrains.kotlin.fir.resolve.typeForQualifier
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
@@ -201,7 +198,7 @@ internal fun extractNonFatalDiagnostics(
|
|||||||
val prevDiagnostics = (explicitReceiver as? FirResolvedQualifier)?.nonFatalDiagnostics ?: emptyList()
|
val prevDiagnostics = (explicitReceiver as? FirResolvedQualifier)?.nonFatalDiagnostics ?: emptyList()
|
||||||
var result: MutableList<ConeDiagnostic>? = null
|
var result: MutableList<ConeDiagnostic>? = null
|
||||||
|
|
||||||
val deprecation = symbol.getDeprecation(apiVersion)?.forUseSite()
|
val deprecation = symbol.getOwnDeprecation(apiVersion)?.forUseSite()
|
||||||
if (deprecation != null) {
|
if (deprecation != null) {
|
||||||
result = mutableListOf()
|
result = mutableListOf()
|
||||||
result.addAll(prevDiagnostics)
|
result.addAll(prevDiagnostics)
|
||||||
|
|||||||
+1
-1
@@ -103,7 +103,7 @@ private fun FirDeclaration.isInvisibleOrHidden(session: FirSession, bodyResolveC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val deprecation = symbol.getDeprecationForCallSite(session.languageVersionSettings.apiVersion)
|
val deprecation = symbol.getDeprecationForCallSite(session)
|
||||||
return deprecation != null && deprecation.deprecationLevel == DeprecationLevelValue.HIDDEN
|
return deprecation != null && deprecation.deprecationLevel == DeprecationLevelValue.HIDDEN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -103,7 +103,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (resolveDeprecations) {
|
if (resolveDeprecations) {
|
||||||
val deprecation = symbol.getDeprecation(session, useSiteFile)
|
val deprecation = symbol.getOwnDeprecation(session, useSiteFile)
|
||||||
if (deprecation != null && deprecation.deprecationLevel == DeprecationLevelValue.HIDDEN) {
|
if (deprecation != null && deprecation.deprecationLevel == DeprecationLevelValue.HIDDEN) {
|
||||||
symbolApplicability = minOf(CandidateApplicability.HIDDEN, symbolApplicability)
|
symbolApplicability = minOf(CandidateApplicability.HIDDEN, symbolApplicability)
|
||||||
diagnostic = null
|
diagnostic = null
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ sealed class FirClassLikeSymbol<D : FirClassLikeDeclaration>(
|
|||||||
|
|
||||||
val name get() = classId.shortClassName
|
val name get() = classId.shortClassName
|
||||||
|
|
||||||
fun getDeprecation(apiVersion: ApiVersion): DeprecationsPerUseSite? {
|
fun getOwnDeprecation(apiVersion: ApiVersion): DeprecationsPerUseSite? {
|
||||||
if (annotations.isEmpty()) return null
|
if (annotations.isEmpty()) return null
|
||||||
lazyResolveToPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS)
|
lazyResolveToPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS)
|
||||||
return fir.deprecationsProvider.getDeprecationsInfo(apiVersion)
|
return fir.deprecationsProvider.getDeprecationsInfo(apiVersion)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ fun foo7(x: <!DEPRECATION!>kotlin.native.Throws<!>) {}
|
|||||||
// FILE: main2.kt
|
// FILE: main2.kt
|
||||||
package abc2
|
package abc2
|
||||||
|
|
||||||
import kotlin.native.Throws
|
import <!DEPRECATION!>kotlin.native.Throws<!>
|
||||||
|
|
||||||
@<!DEPRECATION!>Throws<!>(Throwable::class)
|
@<!DEPRECATION!>Throws<!>(Throwable::class)
|
||||||
fun foo1() {}
|
fun foo1() {}
|
||||||
@@ -70,7 +70,7 @@ fun foo7(x: <!DEPRECATION!>kotlin.native.Throws<!>) {}
|
|||||||
package abc4
|
package abc4
|
||||||
|
|
||||||
import kotlin.<!CONFLICTING_IMPORT!>Throws<!>
|
import kotlin.<!CONFLICTING_IMPORT!>Throws<!>
|
||||||
import kotlin.native.<!CONFLICTING_IMPORT!>Throws<!>
|
import <!DEPRECATION!>kotlin.native.<!CONFLICTING_IMPORT!>Throws<!><!>
|
||||||
|
|
||||||
@<!OVERLOAD_RESOLUTION_AMBIGUITY!>Throws<!>(Throwable::class)
|
@<!OVERLOAD_RESOLUTION_AMBIGUITY!>Throws<!>(Throwable::class)
|
||||||
fun foo1() {}
|
fun foo1() {}
|
||||||
@@ -144,7 +144,7 @@ fun foo7(x: <!DEPRECATION!>kotlin.native.Throws<!>) {}
|
|||||||
package abc8
|
package abc8
|
||||||
|
|
||||||
import kotlin.*
|
import kotlin.*
|
||||||
import kotlin.native.Throws
|
import <!DEPRECATION!>kotlin.native.Throws<!>
|
||||||
|
|
||||||
@<!DEPRECATION!>Throws<!>(Throwable::class)
|
@<!DEPRECATION!>Throws<!>(Throwable::class)
|
||||||
fun foo1() {}
|
fun foo1() {}
|
||||||
|
|||||||
Vendored
-18
@@ -1,18 +0,0 @@
|
|||||||
// !API_VERSION: 1.0
|
|
||||||
|
|
||||||
// FILE: a.kt
|
|
||||||
package a
|
|
||||||
|
|
||||||
@SinceKotlin("1.1")
|
|
||||||
class Since_1_1
|
|
||||||
|
|
||||||
typealias Since_1_1_Alias = <!API_NOT_AVAILABLE!>Since_1_1<!>
|
|
||||||
|
|
||||||
@SinceKotlin("1.1")
|
|
||||||
typealias Alias_1_1 = String
|
|
||||||
|
|
||||||
// FILE: b.kt
|
|
||||||
package b
|
|
||||||
|
|
||||||
import a.<!API_NOT_AVAILABLE!>Since_1_1_Alias<!>
|
|
||||||
import a.Alias_1_1
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !API_VERSION: 1.0
|
// !API_VERSION: 1.0
|
||||||
|
|
||||||
// FILE: a.kt
|
// FILE: a.kt
|
||||||
|
|||||||
Reference in New Issue
Block a user