From 4a9ba1c9ac337ca731a615b03ea95d63810a334d Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Tue, 1 Aug 2023 09:25:49 +0300 Subject: [PATCH] [FIR] Expand typealiases when checking deprecations ^KT-59901 Fixed --- .../fir/components/KtFirSymbolInfoProvider.kt | 14 +-- .../analysis/checkers/CommonTypeCheckers.kt | 1 - .../FirOptInLanguageVersionSettingsChecker.kt | 2 +- .../checkers/declaration/FirImportsChecker.kt | 5 +- .../FirDeprecatedQualifierChecker.kt | 5 +- .../expression/FirDeprecationChecker.kt | 77 +++++++++------- .../checkers/type/FirDeprecatedTypeChecker.kt | 54 +---------- .../kotlin/fir/java/javaAnnotationsMapping.kt | 2 +- .../fir/declarations/deprecationUtils.kt | 89 +++++++++++++++---- .../kotlin/fir/QualifiedNameResolution.kt | 5 +- .../resolve/calls/ConstructorProcessing.kt | 2 +- .../providers/impl/FirTypeResolverImpl.kt | 2 +- .../fir/symbols/impl/FirClassLikeSymbol.kt | 2 +- .../nativeTests/throwsClash.fir.kt | 6 +- .../apiVersion/typealiasesOnImport.fir.kt | 18 ---- .../apiVersion/typealiasesOnImport.kt | 1 + 16 files changed, 140 insertions(+), 145 deletions(-) delete mode 100644 compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesOnImport.fir.kt diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolInfoProvider.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolInfoProvider.kt index bab9da538fb..99e263585af 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolInfoProvider.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirSymbolInfoProvider.kt @@ -44,13 +44,13 @@ internal class KtFirSymbolInfoProvider( return when (val firSymbol = symbol.firSymbol) { is FirPropertySymbol -> { - firSymbol.getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.PROPERTY) + firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession, AnnotationUseSiteTarget.PROPERTY) } is FirBackingFieldSymbol -> { - firSymbol.getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.FIELD) + firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession, AnnotationUseSiteTarget.FIELD) } else -> { - firSymbol.getDeprecationForCallSite(apiVersion) + firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession) } } } @@ -67,9 +67,9 @@ internal class KtFirSymbolInfoProvider( override fun getDeprecation(symbol: KtSymbol, annotationUseSiteTarget: AnnotationUseSiteTarget?): DeprecationInfo? { require(symbol is KtFirSymbol<*>) return if (annotationUseSiteTarget != null) { - symbol.firSymbol.getDeprecationForCallSite(apiVersion, annotationUseSiteTarget) + symbol.firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession, annotationUseSiteTarget) } else { - symbol.firSymbol.getDeprecationForCallSite(apiVersion) + symbol.firSymbol.getDeprecationForCallSite(analysisSession.useSiteSession) } } @@ -77,7 +77,7 @@ internal class KtFirSymbolInfoProvider( override fun getGetterDeprecation(symbol: KtPropertySymbol): DeprecationInfo? { require(symbol is KtFirSymbol<*>) return symbol.firSymbol.getDeprecationForCallSite( - apiVersion, + analysisSession.useSiteSession, AnnotationUseSiteTarget.PROPERTY_GETTER, AnnotationUseSiteTarget.PROPERTY, ) @@ -87,7 +87,7 @@ internal class KtFirSymbolInfoProvider( override fun getSetterDeprecation(symbol: KtPropertySymbol): DeprecationInfo? { require(symbol is KtFirSymbol<*>) return symbol.firSymbol.getDeprecationForCallSite( - apiVersion, + analysisSession.useSiteSession, AnnotationUseSiteTarget.PROPERTY_SETTER, AnnotationUseSiteTarget.PROPERTY, ) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt index 313bc0512b7..af3515efeaf 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonTypeCheckers.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.fir.analysis.checkers -import org.jetbrains.kotlin.fir.analysis.checkers.type.FirUnsupportedDefaultValueInFunctionTypeParameterChecker import org.jetbrains.kotlin.fir.analysis.checkers.type.* object CommonTypeCheckers : TypeCheckers() { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/config/FirOptInLanguageVersionSettingsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/config/FirOptInLanguageVersionSettingsChecker.kt index 9c521d86713..9add703470f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/config/FirOptInLanguageVersionSettingsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/config/FirOptInLanguageVersionSettingsChecker.kt @@ -40,7 +40,7 @@ object FirOptInLanguageVersionSettingsChecker : FirLanguageVersionSettingsChecke rawReport(false, "Class $fqNameAsString is not an opt-in requirement marker") return } - val deprecationInfo = symbol.getDeprecation(context.languageVersionSettings.apiVersion)?.all ?: return + val deprecationInfo = symbol.getOwnDeprecation(context.languageVersionSettings.apiVersion)?.all ?: return rawReport( deprecationInfo.deprecationLevel != DeprecationLevelValue.WARNING, "Opt-in requirement marker $fqNameAsString is deprecated" + deprecationInfo.message?.let { ". $it" }.orEmpty() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt index 0f04fd846a7..def9be4db87 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirImportsChecker.kt @@ -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.getContainingFile 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.impl.declaredMemberScope import org.jetbrains.kotlin.fir.symbols.SymbolInternals @@ -298,7 +299,7 @@ object FirImportsChecker : FirFileChecker() { val importedFqName = import.importedFqName ?: return if (importedFqName.isRoot || importedFqName.shortName().asString().isEmpty()) return val classId = (import as? FirResolvedImport)?.resolvedParentClassId ?: ClassId.topLevel(importedFqName) - val classLike: FirRegularClassSymbol = classId.resolveToClass(context) ?: return - FirDeprecationChecker.reportApiStatusIfNeeded(import.source, classLike, context, reporter) + val symbol = classId.toSymbol(context.session) ?: return + FirDeprecationChecker.reportApiStatusIfNeeded(import.source, symbol, context, reporter) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecatedQualifierChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecatedQualifierChecker.kt index b804baf906a..cf66a6442e2 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecatedQualifierChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecatedQualifierChecker.kt @@ -14,7 +14,10 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol object FirDeprecatedQualifierChecker : FirResolvedQualifierChecker() { override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) { expression.nonFatalDiagnostics.filterIsInstance().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) { val companionSymbol = (expression.symbol as? FirRegularClassSymbol)?.companionObjectSymbol ?: return diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecationChecker.kt index b83ac40accf..516176d08fb 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecationChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDeprecationChecker.kt @@ -12,18 +12,18 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.reportOn import org.jetbrains.kotlin.fir.FirElement 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.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.FutureApiDeprecationInfo 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.getOwnDeprecation import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.resolved import org.jetbrains.kotlin.fir.resolve.firClassLike import org.jetbrains.kotlin.fir.resolve.typeAliasForConstructor 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.FirTypeAliasSymbol import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo @@ -43,31 +43,18 @@ object FirDeprecationChecker : FirBasicExpressionChecker() { val calleeReference = expression.calleeReference ?: return val resolvedReference = calleeReference.resolved ?: return - val source = resolvedReference.source 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) { // 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 typealiasSymbol = expression.constructedTypeRef.firClassLike(context.session)?.symbol as? FirTypeAliasSymbol - reportApiStatus(source, referencedSymbol, typealiasSymbol, constructorOnlyDeprecation, reporter, context) + val isTypealiasExpansion = expression.constructedTypeRef.firClassLike(context.session)?.symbol is FirTypeAliasSymbol + reportApiStatus( + resolvedReference.source, referencedSymbol, isTypealiasExpansion, + constructorOnlyDeprecation, reporter, context + ) } 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<*>, context: CheckerContext, reporter: DiagnosticReporter, - typealiasSymbol: FirTypeAliasSymbol? = null, callSite: FirElement? = null, ) { 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( source: KtSourceElement?, referencedSymbol: FirBasedSymbol<*>, - typealiasSymbol: FirTypeAliasSymbol?, + isTypealiasExpansion: Boolean, deprecationInfo: DeprecationInfo, reporter: DiagnosticReporter, context: CheckerContext, @@ -94,19 +100,19 @@ object FirDeprecationChecker : FirBasicExpressionChecker() { if (deprecationInfo is FutureApiDeprecationInfo) { reportApiNotAvailable(source, deprecationInfo, reporter, context) } else { - reportDeprecation(source, referencedSymbol, typealiasSymbol, deprecationInfo, reporter, context) + reportDeprecation(source, referencedSymbol, isTypealiasExpansion, deprecationInfo, reporter, context) } } private fun reportDeprecation( source: KtSourceElement?, referencedSymbol: FirBasedSymbol<*>, - typealiasSymbol: FirTypeAliasSymbol?, + isTypealiasExpansion: Boolean, deprecationInfo: DeprecationInfo, reporter: DiagnosticReporter, - context: CheckerContext, + context: CheckerContext ) { - if (typealiasSymbol == null) { + if (!isTypealiasExpansion) { val diagnostic = when (deprecationInfo.deprecationLevel) { DeprecationLevelValue.ERROR, DeprecationLevelValue.HIDDEN -> FirErrors.DEPRECATION_ERROR DeprecationLevelValue.WARNING -> FirErrors.DEPRECATION @@ -117,7 +123,7 @@ object FirDeprecationChecker : FirBasicExpressionChecker() { DeprecationLevelValue.ERROR, DeprecationLevelValue.HIDDEN -> FirErrors.TYPEALIAS_EXPANSION_DEPRECATION_ERROR 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( callSite: FirElement?, symbol: FirBasedSymbol<*>, - context: CheckerContext, + context: CheckerContext ): DeprecationInfo? { val deprecationInfos = listOfNotNull( - symbol.getDeprecation(context.session, callSite), (symbol as? FirConstructorSymbol) - ?.resolvedReturnTypeRef - ?.toRegularClassSymbol(context.session) - ?.getDeprecation(context.session, callSite) + ?.classSymbolItIsCalledThrough(context) + ?.getDeprecation(context.session, callSite), + symbol.getDeprecation(context.session, callSite), ) return deprecationInfos.maxOrNull() } + + private fun FirConstructorSymbol.classSymbolItIsCalledThrough(context: CheckerContext): FirClassLikeSymbol<*>? { + return typeAliasForConstructor ?: (resolvedReturnTypeRef.toRegularClassSymbol(context.session)) + } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirDeprecatedTypeChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirDeprecatedTypeChecker.kt index 4564b6e860b..44069d095c0 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirDeprecatedTypeChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/type/FirDeprecatedTypeChecker.kt @@ -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.resolve.toSymbol 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.lazyResolveToPhase import org.jetbrains.kotlin.fir.types.* @@ -24,58 +23,9 @@ object FirDeprecatedTypeChecker : FirTypeRefChecker() { if (source.kind is KtFakeSourceElementKind) return val resolved = typeRef.coneTypeSafe() ?: return - checkType(resolved, null, source, context, reporter, symbolToIgnore = null) - } + val symbol = resolved.lookupTag.toSymbol(context.session) ?: return - private fun checkType( - 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) + FirDeprecationChecker.reportApiStatusIfNeeded(source, symbol, context, reporter) } } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt index be38181aad4..9b7d9b45306 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/javaAnnotationsMapping.kt @@ -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 * See KT-59342 * TODO: KT-60520 diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/deprecationUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/deprecationUtils.kt index 4aa6f9d8117..12d9d94c227 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/deprecationUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/declarations/deprecationUtils.kt @@ -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.FirClassLikeSymbol 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.StandardClassIds import org.jetbrains.kotlin.name.StandardClassIds.Annotations.ParameterNames @@ -71,24 +75,33 @@ inline fun buildDeprecationAnnotationInfoPerUseSiteStorage(builder: DeprecationA return DeprecationAnnotationInfoPerUseSiteStorageBuilder().apply(builder).build() } -fun FirBasedSymbol<*>.getDeprecation(session: FirSession, callSite: FirElement?): DeprecationInfo? { - return getDeprecation(session.languageVersionSettings.apiVersion, callSite) +private fun FirBasedSymbol<*>.getUseSitesForCallSite(callSite: FirElement?): Array { + 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) { - is FirPropertySymbol -> - when (callSite) { - is FirVariableAssignment -> - getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.PROPERTY_SETTER, AnnotationUseSiteTarget.PROPERTY) - is FirPropertyAccessExpression -> - getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.PROPERTY_GETTER, AnnotationUseSiteTarget.PROPERTY) - else -> - getDeprecationForCallSite(apiVersion, AnnotationUseSiteTarget.PROPERTY) - } - else -> - getDeprecationForCallSite(apiVersion) - } +/** + * Returns deprecation that is declared on the + * corresponding declaration. + */ +fun FirBasedSymbol<*>.getOwnDeprecation(session: FirSession, callSite: FirElement?): DeprecationInfo? { + return getOwnDeprecationForCallSite(session.languageVersionSettings.apiVersion, *getUseSitesForCallSite(callSite)) +} + +/** + * Returns deprecation that is declared on + * the corresponding declaration directly + * or, in case of a typealias, on any of + * its expansions. + */ +fun FirBasedSymbol<*>.getDeprecation(session: FirSession, callSite: FirElement?): DeprecationInfo? { + return getDeprecationForCallSite(session, *getUseSitesForCallSite(callSite)) } fun FirAnnotationContainer.getDeprecationsProvider(session: FirSession): DeprecationsProvider { @@ -162,18 +175,58 @@ fun List.getDeprecationsProviderFromAnnotations( return deprecationAnnotationByUseSite.toDeprecationsProvider(session.firCachesFactory) } -fun FirBasedSymbol<*>.getDeprecationForCallSite( +/** + * Returns deprecation that is declared on the + * corresponding declaration. + */ +private fun FirBasedSymbol<*>.getOwnDeprecationForCallSite( apiVersion: ApiVersion, vararg sites: AnnotationUseSiteTarget ): DeprecationInfo? { val deprecations = when (this) { is FirCallableSymbol<*> -> getDeprecation(apiVersion) - is FirClassLikeSymbol<*> -> getDeprecation(apiVersion) + is FirClassLikeSymbol<*> -> getOwnDeprecation(apiVersion) else -> null } 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() + + 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? = getStringArgument(name)?.let { ApiVersion.parse(it) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt index 528b4b82a51..f931f846f6e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/QualifiedNameResolution.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.fir import org.jetbrains.kotlin.KtSourceElement 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.fullyExpandedClass 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.typeForQualifier 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.name.ClassId import org.jetbrains.kotlin.name.FqName @@ -201,7 +198,7 @@ internal fun extractNonFatalDiagnostics( val prevDiagnostics = (explicitReceiver as? FirResolvedQualifier)?.nonFatalDiagnostics ?: emptyList() var result: MutableList? = null - val deprecation = symbol.getDeprecation(apiVersion)?.forUseSite() + val deprecation = symbol.getOwnDeprecation(apiVersion)?.forUseSite() if (deprecation != null) { result = mutableListOf() result.addAll(prevDiagnostics) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt index 031a59e500c..8f00e028865 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ConstructorProcessing.kt @@ -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 } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt index 2f7e513e0f9..bd678386c31 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/impl/FirTypeResolverImpl.kt @@ -103,7 +103,7 @@ class FirTypeResolverImpl(private val session: FirSession) : FirTypeResolver() { } if (resolveDeprecations) { - val deprecation = symbol.getDeprecation(session, useSiteFile) + val deprecation = symbol.getOwnDeprecation(session, useSiteFile) if (deprecation != null && deprecation.deprecationLevel == DeprecationLevelValue.HIDDEN) { symbolApplicability = minOf(CandidateApplicability.HIDDEN, symbolApplicability) diagnostic = null diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt index 9733f16f47b..881bf0927bb 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/symbols/impl/FirClassLikeSymbol.kt @@ -29,7 +29,7 @@ sealed class FirClassLikeSymbol( val name get() = classId.shortClassName - fun getDeprecation(apiVersion: ApiVersion): DeprecationsPerUseSite? { + fun getOwnDeprecation(apiVersion: ApiVersion): DeprecationsPerUseSite? { if (annotations.isEmpty()) return null lazyResolveToPhase(FirResolvePhase.COMPILER_REQUIRED_ANNOTATIONS) return fir.deprecationsProvider.getDeprecationsInfo(apiVersion) diff --git a/compiler/testData/diagnostics/nativeTests/throwsClash.fir.kt b/compiler/testData/diagnostics/nativeTests/throwsClash.fir.kt index e7ffa029762..c42614b1f41 100644 --- a/compiler/testData/diagnostics/nativeTests/throwsClash.fir.kt +++ b/compiler/testData/diagnostics/nativeTests/throwsClash.fir.kt @@ -33,7 +33,7 @@ fun foo7(x: kotlin.native.Throws) {} // FILE: main2.kt package abc2 -import kotlin.native.Throws +import kotlin.native.Throws @Throws(Throwable::class) fun foo1() {} @@ -70,7 +70,7 @@ fun foo7(x: kotlin.native.Throws) {} package abc4 import kotlin.Throws -import kotlin.native.Throws +import kotlin.native.Throws @Throws(Throwable::class) fun foo1() {} @@ -144,7 +144,7 @@ fun foo7(x: kotlin.native.Throws) {} package abc8 import kotlin.* -import kotlin.native.Throws +import kotlin.native.Throws @Throws(Throwable::class) fun foo1() {} diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesOnImport.fir.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesOnImport.fir.kt deleted file mode 100644 index 3569c23c07d..00000000000 --- a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesOnImport.fir.kt +++ /dev/null @@ -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 = Since_1_1 - -@SinceKotlin("1.1") -typealias Alias_1_1 = String - -// FILE: b.kt -package b - -import a.Since_1_1_Alias -import a.Alias_1_1 diff --git a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesOnImport.kt b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesOnImport.kt index 4bc1376c96e..343a9b6de31 100644 --- a/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesOnImport.kt +++ b/compiler/testData/diagnostics/tests/sourceCompatibility/apiVersion/typealiasesOnImport.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !API_VERSION: 1.0 // FILE: a.kt