[FIR] Report when typealias expansion contains deprecated type
#KT-57843 Fixed
This commit is contained in:
committed by
Space Team
parent
206fad4256
commit
1f29490118
+18
@@ -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,
|
||||
|
||||
+14
@@ -259,6 +259,20 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val message: String
|
||||
}
|
||||
|
||||
abstract class TypealiasExpansionDeprecationError : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = TypealiasExpansionDeprecationError::class
|
||||
abstract val alias: KtSymbol
|
||||
abstract val reference: KtSymbol
|
||||
abstract val message: String
|
||||
}
|
||||
|
||||
abstract class TypealiasExpansionDeprecation : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = TypealiasExpansionDeprecation::class
|
||||
abstract val alias: KtSymbol
|
||||
abstract val reference: KtSymbol
|
||||
abstract val message: String
|
||||
}
|
||||
|
||||
abstract class ApiNotAvailable : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = ApiNotAvailable::class
|
||||
abstract val sinceKotlinVersion: ApiVersion
|
||||
|
||||
+16
@@ -297,6 +297,22 @@ internal class DeprecationImpl(
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.Deprecation(), KtAbstractFirDiagnostic<PsiElement>
|
||||
|
||||
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<PsiElement>
|
||||
|
||||
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<PsiElement>
|
||||
|
||||
internal class ApiNotAvailableImpl(
|
||||
override val sinceKotlinVersion: ApiVersion,
|
||||
override val currentVersion: ApiVersion,
|
||||
|
||||
+11
@@ -123,6 +123,17 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<String>("message")
|
||||
}
|
||||
|
||||
val TYPEALIAS_EXPANSION_DEPRECATION_ERROR by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
|
||||
parameter<Symbol>("alias")
|
||||
parameter<Symbol>("reference")
|
||||
parameter<String>("message")
|
||||
}
|
||||
val TYPEALIAS_EXPANSION_DEPRECATION by warning<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
|
||||
parameter<Symbol>("alias")
|
||||
parameter<Symbol>("reference")
|
||||
parameter<String>("message")
|
||||
}
|
||||
|
||||
val API_NOT_AVAILABLE by error<PsiElement>(PositioningStrategy.SELECTOR_BY_QUALIFIED) {
|
||||
parameter<ApiVersion>("sinceKotlinVersion")
|
||||
parameter<ApiVersion>("currentVersion")
|
||||
|
||||
@@ -155,6 +155,8 @@ object FirErrors {
|
||||
val NO_THIS by error0<PsiElement>()
|
||||
val DEPRECATION_ERROR by error2<PsiElement, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val DEPRECATION by warning2<PsiElement, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val TYPEALIAS_EXPANSION_DEPRECATION_ERROR by error3<PsiElement, FirBasedSymbol<*>, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val TYPEALIAS_EXPANSION_DEPRECATION by warning3<PsiElement, FirBasedSymbol<*>, FirBasedSymbol<*>, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
val API_NOT_AVAILABLE by error2<PsiElement, ApiVersion, ApiVersion>(SourceElementPositioningStrategies.SELECTOR_BY_QUALIFIED)
|
||||
val UNRESOLVED_REFERENCE_WRONG_RECEIVER by error1<PsiElement, Collection<FirBasedSymbol<*>>>()
|
||||
val UNRESOLVED_IMPORT by error1<PsiElement, String>(SourceElementPositioningStrategies.IMPORT_LAST_NAME)
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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<ConeDeprecated>().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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-10
@@ -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(
|
||||
|
||||
+31
-7
@@ -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<ConeClassLikeType>() ?: return
|
||||
val symbol = resolved.lookupTag.toSymbol(context.session) ?: return
|
||||
|
||||
FirDeprecationChecker.reportApiStatusIfNeeded(source, symbol, null, context, reporter)
|
||||
val resolved = typeRef.coneTypeSafe<ConeClassLikeType>() ?: 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -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}",
|
||||
|
||||
@@ -10,7 +10,7 @@ typealias DeprecatedClassAlias = <!DEPRECATION!>DeprecatedClass<!>
|
||||
typealias WithDeprecatedCtorAlias = WithDeprecatedCtor
|
||||
typealias ArrayListOfDeprecatedClass = ArrayList<<!DEPRECATION!>DeprecatedClass<!>>
|
||||
|
||||
class Test1 : DeprecatedClassAlias()
|
||||
class Test1 : <!TYPEALIAS_EXPANSION_DEPRECATION!>DeprecatedClassAlias<!>()
|
||||
|
||||
class Test2 : <!DEPRECATION!>WithDeprecatedCtorAlias<!>()
|
||||
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
@Deprecated("")
|
||||
class Foo
|
||||
|
||||
@Deprecated("", level = DeprecationLevel.ERROR)
|
||||
class Err
|
||||
|
||||
typealias Test1 = <!DEPRECATION!>Foo<!>
|
||||
typealias Test2 = List<<!DEPRECATION!>Foo<!>>
|
||||
typealias Test3 = List<Test2>
|
||||
|
||||
typealias TestErr1 = <!DEPRECATION_ERROR!>Err<!>
|
||||
typealias TestErr2 = List<<!DEPRECATION_ERROR!>Err<!>>
|
||||
typealias TestErr3 = List<TestErr2>
|
||||
|
||||
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
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
@Deprecated("")
|
||||
class Foo
|
||||
|
||||
|
||||
Reference in New Issue
Block a user