diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt index 847e05c125e..bb2d362017f 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -313,6 +313,24 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.TYPEALIAS_EXPANSION_DEPRECATION_ERROR) { firDiagnostic -> + TypealiasExpansionDeprecationErrorImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a), + firSymbolBuilder.buildSymbol(firDiagnostic.b), + firDiagnostic.c, + firDiagnostic as KtPsiDiagnostic, + token, + ) + } + add(FirErrors.TYPEALIAS_EXPANSION_DEPRECATION) { firDiagnostic -> + TypealiasExpansionDeprecationImpl( + firSymbolBuilder.buildSymbol(firDiagnostic.a), + firSymbolBuilder.buildSymbol(firDiagnostic.b), + firDiagnostic.c, + firDiagnostic as KtPsiDiagnostic, + token, + ) + } add(FirErrors.API_NOT_AVAILABLE) { firDiagnostic -> ApiNotAvailableImpl( firDiagnostic.a, diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt index 82b47730e00..63ed02a1b9f 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnostics.kt @@ -259,6 +259,20 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val message: String } + abstract class TypealiasExpansionDeprecationError : KtFirDiagnostic() { + override val diagnosticClass get() = TypealiasExpansionDeprecationError::class + abstract val alias: KtSymbol + abstract val reference: KtSymbol + abstract val message: String + } + + abstract class TypealiasExpansionDeprecation : KtFirDiagnostic() { + override val diagnosticClass get() = TypealiasExpansionDeprecation::class + abstract val alias: KtSymbol + abstract val reference: KtSymbol + abstract val message: String + } + abstract class ApiNotAvailable : KtFirDiagnostic() { override val diagnosticClass get() = ApiNotAvailable::class abstract val sinceKotlinVersion: ApiVersion diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index c636a30b091..2304a9b57e3 100644 --- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -297,6 +297,22 @@ internal class DeprecationImpl( override val token: KtLifetimeToken, ) : KtFirDiagnostic.Deprecation(), KtAbstractFirDiagnostic +internal class TypealiasExpansionDeprecationErrorImpl( + override val alias: KtSymbol, + override val reference: KtSymbol, + override val message: String, + override val firDiagnostic: KtPsiDiagnostic, + override val token: KtLifetimeToken, +) : KtFirDiagnostic.TypealiasExpansionDeprecationError(), KtAbstractFirDiagnostic + +internal class TypealiasExpansionDeprecationImpl( + override val alias: KtSymbol, + override val reference: KtSymbol, + override val message: String, + override val firDiagnostic: KtPsiDiagnostic, + override val token: KtLifetimeToken, +) : KtFirDiagnostic.TypealiasExpansionDeprecation(), KtAbstractFirDiagnostic + internal class ApiNotAvailableImpl( override val sinceKotlinVersion: ApiVersion, override val currentVersion: ApiVersion, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index 6c27139551a..cf790a178ac 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -123,6 +123,17 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("message") } + val TYPEALIAS_EXPANSION_DEPRECATION_ERROR by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) { + parameter("alias") + parameter("reference") + parameter("message") + } + val TYPEALIAS_EXPANSION_DEPRECATION by warning(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) { + parameter("alias") + parameter("reference") + parameter("message") + } + val API_NOT_AVAILABLE by error(PositioningStrategy.SELECTOR_BY_QUALIFIED) { parameter("sinceKotlinVersion") parameter("currentVersion") diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 4d619bf3ee4..d5be0d73966 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -155,6 +155,8 @@ object FirErrors { val NO_THIS by error0() val DEPRECATION_ERROR by error2, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val DEPRECATION by warning2, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) + val TYPEALIAS_EXPANSION_DEPRECATION_ERROR by error3, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) + val TYPEALIAS_EXPANSION_DEPRECATION by warning3, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val API_NOT_AVAILABLE by error2(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED) val UNRESOLVED_REFERENCE_WRONG_RECEIVER by error1>>() val UNRESOLVED_IMPORT by error1(SourceElementPositioningStrategies.IMPORT_LAST_NAME) 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 d1c960d9039..6c973b9f143 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 @@ -291,6 +291,6 @@ object FirImportsChecker : FirFileChecker() { 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, null, context, reporter) + FirDeprecationChecker.reportApiStatusIfNeeded(import.source, classLike, 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 aff1f7cb9af..b804baf906a 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,11 +14,11 @@ 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, diagnostic.deprecationInfo, reporter, context) + FirDeprecationChecker.reportApiStatus(diagnostic.source, diagnostic.symbol, null, diagnostic.deprecationInfo, reporter, context) } if (expression.resolvedToCompanionObject) { val companionSymbol = (expression.symbol as? FirRegularClassSymbol)?.companionObjectSymbol ?: return - FirDeprecationChecker.reportApiStatusIfNeeded(expression.source, companionSymbol, null, context, reporter) + FirDeprecationChecker.reportApiStatusIfNeeded(expression.source, companionSymbol, context, reporter) } } } 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 ca30a36504c..30beedab1f6 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 @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.resolved import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue @@ -43,26 +44,28 @@ object FirDeprecationChecker : FirBasicExpressionChecker() { 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 - reportApiStatus(resolvedReference.source, referencedSymbol, constructorOnlyDeprecation, reporter, context) + reportApiStatus(resolvedReference.source, referencedSymbol, null, constructorOnlyDeprecation, reporter, context) } else { - reportApiStatusIfNeeded(resolvedReference.source, referencedSymbol, expression, context, reporter) + reportApiStatusIfNeeded(resolvedReference.source, referencedSymbol, context, reporter, callSite = expression) } } internal fun reportApiStatusIfNeeded( source: KtSourceElement?, referencedSymbol: FirBasedSymbol<*>, - callSite: FirElement?, context: CheckerContext, - reporter: DiagnosticReporter + reporter: DiagnosticReporter, + typealiasSymbol: FirTypeAliasSymbol? = null, + callSite: FirElement? = null, ) { val deprecation = getWorstDeprecation(callSite, referencedSymbol, context) ?: return - reportApiStatus(source, referencedSymbol, deprecation, reporter, context) + reportApiStatus(source, referencedSymbol, typealiasSymbol, deprecation, reporter, context) } internal fun reportApiStatus( source: KtSourceElement?, referencedSymbol: FirBasedSymbol<*>, + typealiasSymbol: FirTypeAliasSymbol?, deprecationInfo: DeprecationInfo, reporter: DiagnosticReporter, context: CheckerContext, @@ -70,22 +73,31 @@ object FirDeprecationChecker : FirBasicExpressionChecker() { if (deprecationInfo is FutureApiDeprecationInfo) { reportApiNotAvailable(source, deprecationInfo, reporter, context) } else { - reportDeprecation(source, referencedSymbol, deprecationInfo, reporter, context) + reportDeprecation(source, referencedSymbol, typealiasSymbol, deprecationInfo, reporter, context) } } private fun reportDeprecation( source: KtSourceElement?, referencedSymbol: FirBasedSymbol<*>, + typealiasSymbol: FirTypeAliasSymbol?, deprecationInfo: DeprecationInfo, reporter: DiagnosticReporter, context: CheckerContext ) { - val diagnostic = when (deprecationInfo.deprecationLevel) { - DeprecationLevelValue.ERROR, DeprecationLevelValue.HIDDEN -> FirErrors.DEPRECATION_ERROR - DeprecationLevelValue.WARNING -> FirErrors.DEPRECATION + if (typealiasSymbol == null) { + val diagnostic = when (deprecationInfo.deprecationLevel) { + DeprecationLevelValue.ERROR, DeprecationLevelValue.HIDDEN -> FirErrors.DEPRECATION_ERROR + DeprecationLevelValue.WARNING -> FirErrors.DEPRECATION + } + reporter.reportOn(source, diagnostic, referencedSymbol, deprecationInfo.message ?: "", context) + } else { + val diagnostic = when (deprecationInfo.deprecationLevel) { + 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, deprecationInfo.message ?: "", context) } private fun reportApiNotAvailable( 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 fcc1888ac60..ed9a0a908a3 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 @@ -6,21 +6,45 @@ package org.jetbrains.kotlin.fir.analysis.checkers.type import org.jetbrains.kotlin.KtFakeSourceElementKind +import org.jetbrains.kotlin.KtSourceElement +import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirDeprecationChecker -import org.jetbrains.kotlin.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.fir.resolve.toSymbol -import org.jetbrains.kotlin.fir.types.ConeClassLikeType -import org.jetbrains.kotlin.fir.types.FirTypeRef -import org.jetbrains.kotlin.fir.types.coneTypeSafe +import org.jetbrains.kotlin.fir.symbols.SymbolInternals +import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol +import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase +import org.jetbrains.kotlin.fir.types.* object FirDeprecatedTypeChecker : FirTypeRefChecker() { override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) { val source = typeRef.source ?: return if (source.kind is KtFakeSourceElementKind) return - val resolved = typeRef.coneTypeSafe() ?: return - val symbol = resolved.lookupTag.toSymbol(context.session) ?: return - FirDeprecationChecker.reportApiStatusIfNeeded(source, symbol, null, context, reporter) + val resolved = typeRef.coneTypeSafe() ?: return + checkType(resolved, null, source, context, reporter) } + + @OptIn(SymbolInternals::class) + private fun checkType( + type: ConeClassLikeType, + typeAliasSymbol: FirTypeAliasSymbol?, + source: KtSourceElement, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + val symbol = type.lookupTag.toSymbol(context.session) ?: 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) + } + } + } + } + diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt index b65bcf21c56..bd557971b06 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrorsDefaultMessages.kt @@ -524,6 +524,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.THROWABLE_TYPE_MI import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOO_MANY_ARGUMENTS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TOPLEVEL_TYPEALIASES_ONLY +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPEALIAS_EXPANSION_DEPRECATION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPEALIAS_EXPANSION_DEPRECATION_ERROR import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPEALIAS_SHOULD_EXPAND_TO_CLASS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED @@ -660,6 +662,9 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() { map.put(VAL_OR_VAR_ON_SECONDARY_CONSTRUCTOR_PARAMETER, "''{0}'' on secondary constructor parameter is not allowed", TO_STRING) map.put(DEPRECATION, "''{0}'' is deprecated. {1}", SYMBOL, STRING) map.put(DEPRECATION_ERROR, "''{0}'' is deprecated. {1}", SYMBOL, STRING) + map.put(TYPEALIAS_EXPANSION_DEPRECATION, "''{0}'' uses ''{1}'', which is deprecated. {2}", SYMBOL, SYMBOL, STRING) + map.put(TYPEALIAS_EXPANSION_DEPRECATION_ERROR, "''{0}'' uses ''{1}'', which is an error. {2}", SYMBOL, SYMBOL, STRING) + map.put( API_NOT_AVAILABLE, "This declaration is only available since Kotlin {0} and cannot be used with the specified API version {1}", diff --git a/compiler/testData/diagnostics/tests/deprecated/typealiasConstructor.fir.kt b/compiler/testData/diagnostics/tests/deprecated/typealiasConstructor.fir.kt index 59cd467ddb8..82cca1fbe3d 100644 --- a/compiler/testData/diagnostics/tests/deprecated/typealiasConstructor.fir.kt +++ b/compiler/testData/diagnostics/tests/deprecated/typealiasConstructor.fir.kt @@ -10,7 +10,7 @@ typealias DeprecatedClassAlias = DeprecatedClass typealias WithDeprecatedCtorAlias = WithDeprecatedCtor typealias ArrayListOfDeprecatedClass = ArrayList<DeprecatedClass> -class Test1 : DeprecatedClassAlias() +class Test1 : DeprecatedClassAlias() class Test2 : WithDeprecatedCtorAlias() diff --git a/compiler/testData/diagnostics/tests/deprecated/typealiasForDeprecatedClass.fir.kt b/compiler/testData/diagnostics/tests/deprecated/typealiasForDeprecatedClass.fir.kt deleted file mode 100644 index a446443791a..00000000000 --- a/compiler/testData/diagnostics/tests/deprecated/typealiasForDeprecatedClass.fir.kt +++ /dev/null @@ -1,21 +0,0 @@ -@Deprecated("") -class Foo - -@Deprecated("", level = DeprecationLevel.ERROR) -class Err - -typealias Test1 = Foo -typealias Test2 = List<Foo> -typealias Test3 = List - -typealias TestErr1 = Err -typealias TestErr2 = List<Err> -typealias TestErr3 = List - -fun use1(b: Test1) = b -fun use2(b: Test2) = b -fun use3(b: Test3) = b - -fun useErr1(b: TestErr1) = b -fun useErr2(b: TestErr2) = b -fun useErr3(b: TestErr3) = b diff --git a/compiler/testData/diagnostics/tests/deprecated/typealiasForDeprecatedClass.kt b/compiler/testData/diagnostics/tests/deprecated/typealiasForDeprecatedClass.kt index 45454cd459c..97a8b8488c2 100644 --- a/compiler/testData/diagnostics/tests/deprecated/typealiasForDeprecatedClass.kt +++ b/compiler/testData/diagnostics/tests/deprecated/typealiasForDeprecatedClass.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL @Deprecated("") class Foo