Opt-in: forbid/deprecate constructor call with default arguments under marker

#KT-55074 Fixed
This commit is contained in:
Mikhail Glukhikh
2022-11-21 15:35:25 +01:00
committed by Space Team
parent b92ce68f32
commit 8ddc535caf
5 changed files with 54 additions and 29 deletions
@@ -150,13 +150,21 @@ object FirOptInUsageBaseChecker {
if (fir is FirCallableDeclaration) {
val parentClassSymbol = fir.containingClassLookupTag()?.toSymbol(session) as? FirRegularClassSymbol
if (fir is FirConstructor) {
// For other callable we check dispatch receiver type instead
parentClassSymbol?.loadExperimentalities(
context, result, visited, fromSetter = false, dispatchReceiverType = null, fromSupertype = false
)
} else {
fir.loadOverridableSpecificExperimentalities(context, visited, result)
// Without coneTypeSafe v fails in MT test (FirRenderer.kt)
fir.returnTypeRef.coneTypeSafe<ConeKotlinType>().addExperimentalities(context, result, visited)
fir.receiverParameter?.typeRef?.coneType.addExperimentalities(context, result, visited)
}
dispatchReceiverType?.addExperimentalities(context, result, visited)
if (fir is FirFunction) {
fir.valueParameters.forEach {
it.returnTypeRef.coneType.addExperimentalities(context, result, visited)
}
}
if (fromSetter && this is FirPropertySymbol) {
setterSymbol?.loadExperimentalities(
context, result, visited, fromSetter = false, dispatchReceiverType, fromSupertype = false
@@ -194,21 +202,6 @@ object FirOptInUsageBaseChecker {
return result
}
private fun FirCallableDeclaration.loadOverridableSpecificExperimentalities(
context: CheckerContext,
visited: MutableSet<FirDeclaration>,
result: SmartSet<Experimentality>
) {
// Without coneTypeSafe v fails in MT test (FirRenderer.kt)
returnTypeRef.coneTypeSafe<ConeKotlinType>().addExperimentalities(context, result, visited)
receiverParameter?.typeRef?.coneType.addExperimentalities(context, result, visited)
if (this is FirSimpleFunction) {
valueParameters.forEach {
it.returnTypeRef.coneType.addExperimentalities(context, result, visited)
}
}
}
private fun ConeKotlinType?.addExperimentalities(
context: CheckerContext,
result: SmartSet<Experimentality>,
@@ -224,14 +224,15 @@ class OptInUsageChecker(project: Project) : CallChecker {
moduleAnnotationsResolver, context, languageVersionSettings, visited
)
)
if (this is FunctionDescriptor) {
valueParameters.forEach {
result.addAll(
it.type.loadOptIns(
moduleAnnotationsResolver, context, languageVersionSettings, visited
)
}
if (this is FunctionDescriptor) {
valueParameters.forEach {
result.addAll(
it.type.loadOptIns(
moduleAnnotationsResolver, context, languageVersionSettings, visited,
warningsOnly = this is ConstructorDescriptor
)
}
)
}
}
@@ -258,19 +259,20 @@ class OptInUsageChecker(project: Project) : CallChecker {
moduleAnnotationsResolver: ModuleAnnotationsResolver,
context: BindingContext,
languageVersionSettings: LanguageVersionSettings,
visitedClassifiers: MutableSet<DeclarationDescriptor>
visitedClassifiers: MutableSet<DeclarationDescriptor>,
warningsOnly: Boolean = false
): Set<OptInDescription> =
when {
this?.isError != false -> emptySet()
this is AbbreviatedType -> abbreviation.constructor.declarationDescriptor?.loadOptIns(
moduleAnnotationsResolver, context, languageVersionSettings, visitedClassifiers,
useFutureError = !languageVersionSettings.supportsFeature(LanguageFeature.OptInContagiousSignatures)
useFutureError = warningsOnly || !languageVersionSettings.supportsFeature(LanguageFeature.OptInContagiousSignatures)
).orEmpty() + expandedType.loadOptIns(
moduleAnnotationsResolver, context, languageVersionSettings, visitedClassifiers
)
else -> constructor.declarationDescriptor?.loadOptIns(
moduleAnnotationsResolver, context, languageVersionSettings, visitedClassifiers,
useFutureError = !languageVersionSettings.supportsFeature(LanguageFeature.OptInContagiousSignatures)
useFutureError = warningsOnly || !languageVersionSettings.supportsFeature(LanguageFeature.OptInContagiousSignatures)
).orEmpty() + arguments.flatMap {
if (it.isStarProjection) emptySet()
else it.type.loadOptIns(moduleAnnotationsResolver, context, languageVersionSettings, visitedClassifiers)
@@ -0,0 +1,26 @@
@RequiresOptIn
annotation class Marker
@Marker
class Some(val x: Int)
class Other(val x: Int) {
@OptIn(Marker::class)
constructor(some: Some): this(some.x)
@Marker
constructor(): this(42)
@OptIn(Marker::class)
constructor(y: Long, some: Some? = null): this(some?.x ?: y.toInt())
}
fun foo(some: <!OPT_IN_USAGE_ERROR!>Some<!>? = null) {}
fun test() {
val o1 = <!OPT_IN_USAGE_ERROR!>Other<!>()
val o2 = <!OPT_IN_USAGE_ERROR!>Other<!>(<!OPT_IN_USAGE_ERROR!>Some<!>(0))
val o3 = <!OPT_IN_USAGE_ERROR!>Other<!>(444L)
<!OPT_IN_USAGE_ERROR!>foo<!>()
<!OPT_IN_USAGE_ERROR!>foo<!>(null)
}
@@ -1,4 +1,3 @@
// FIR_IDENTICAL
@RequiresOptIn
annotation class Marker
@@ -16,8 +15,12 @@ class Other(val x: Int) {
constructor(y: Long, some: Some? = null): this(some?.x ?: y.toInt())
}
fun foo(some: <!OPT_IN_USAGE_ERROR!>Some<!>? = null) {}
fun test() {
val o1 = <!OPT_IN_USAGE_ERROR!>Other<!>()
val o2 = Other(<!OPT_IN_USAGE_ERROR!>Some<!>(0))
val o3 = Other(444L)
val o2 = <!OPT_IN_USAGE_FUTURE_ERROR!>Other<!>(<!OPT_IN_USAGE_ERROR!>Some<!>(0))
val o3 = <!OPT_IN_USAGE_FUTURE_ERROR!>Other<!>(444L)
<!OPT_IN_USAGE_ERROR!>foo<!>()
<!OPT_IN_USAGE_ERROR!>foo<!>(null)
}
@@ -1,5 +1,6 @@
package
public fun foo(/*0*/ some: Some? = ...): kotlin.Unit
public fun test(): kotlin.Unit
@kotlin.RequiresOptIn public final annotation class Marker : kotlin.Annotation {