FIR: spread OptIn markers to children except fake override case

This commit implements KT-49001 for FIR
This commit is contained in:
Mikhail Glukhikh
2021-09-21 17:06:31 +03:00
committed by TeamCityServer
parent 69e06a242a
commit a76aee9b69
7 changed files with 27 additions and 17 deletions
@@ -10,8 +10,11 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.coneType
object FirOptInUsageAccessChecker : FirQualifiedAccessChecker() { object FirOptInUsageAccessChecker : FirQualifiedAccessChecker() {
override fun check(expression: FirQualifiedAccess, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(expression: FirQualifiedAccess, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -21,14 +24,16 @@ object FirOptInUsageAccessChecker : FirQualifiedAccessChecker() {
) return ) return
val reference = expression.calleeReference as? FirResolvedNamedReference ?: return val reference = expression.calleeReference as? FirResolvedNamedReference ?: return
val resolvedSymbol = reference.resolvedSymbol val resolvedSymbol = reference.resolvedSymbol
val dispatchReceiverType =
expression.dispatchReceiver.takeIf { it !is FirNoReceiverExpression }?.typeRef?.coneType?.fullyExpandedType(context.session)
with(FirOptInUsageBaseChecker) { with(FirOptInUsageBaseChecker) {
if (expression is FirVariableAssignment && resolvedSymbol is FirPropertySymbol) { if (expression is FirVariableAssignment && resolvedSymbol is FirPropertySymbol) {
val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = true) + val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = true, dispatchReceiverType) +
loadExperimentalitiesFromTypeArguments(context, expression.typeArguments) loadExperimentalitiesFromTypeArguments(context, expression.typeArguments)
reportNotAcceptedExperimentalities(experimentalities, expression.lValue, context, reporter) reportNotAcceptedExperimentalities(experimentalities, expression.lValue, context, reporter)
return return
} }
val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = false) + val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType) +
loadExperimentalitiesFromTypeArguments(context, expression.typeArguments) loadExperimentalitiesFromTypeArguments(context, expression.typeArguments)
reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter) reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter)
} }
@@ -75,9 +75,9 @@ object FirOptInUsageBaseChecker {
} }
fun FirBasedSymbol<*>.loadExperimentalities( fun FirBasedSymbol<*>.loadExperimentalities(
context: CheckerContext, fromSetter: Boolean context: CheckerContext, fromSetter: Boolean, dispatchReceiverType: ConeKotlinType?
): Set<Experimentality> = loadExperimentalities( ): Set<Experimentality> = loadExperimentalities(
context, knownExperimentalities = null, visited = mutableSetOf(), fromSetter context, knownExperimentalities = null, visited = mutableSetOf(), fromSetter, dispatchReceiverType
) )
@OptIn(SymbolInternals::class) @OptIn(SymbolInternals::class)
@@ -86,6 +86,7 @@ object FirOptInUsageBaseChecker {
knownExperimentalities: SmartSet<Experimentality>?, knownExperimentalities: SmartSet<Experimentality>?,
visited: MutableSet<FirAnnotatedDeclaration>, visited: MutableSet<FirAnnotatedDeclaration>,
fromSetter: Boolean, fromSetter: Boolean,
dispatchReceiverType: ConeKotlinType?,
): Set<Experimentality> { ): Set<Experimentality> {
ensureResolved(FirResolvePhase.STATUS) ensureResolved(FirResolvePhase.STATUS)
val fir = this.fir as? FirAnnotatedDeclaration ?: return emptySet() val fir = this.fir as? FirAnnotatedDeclaration ?: return emptySet()
@@ -99,12 +100,12 @@ object FirOptInUsageBaseChecker {
val parentClassScope = parentClassSymbol?.unsubstitutedScope(context) val parentClassScope = parentClassSymbol?.unsubstitutedScope(context)
if (this is FirNamedFunctionSymbol) { if (this is FirNamedFunctionSymbol) {
parentClassScope?.processDirectlyOverriddenFunctions(this) { parentClassScope?.processDirectlyOverriddenFunctions(this) {
it.loadExperimentalities(context, result, visited, fromSetter = false) it.loadExperimentalities(context, result, visited, fromSetter = false, dispatchReceiverType = null)
ProcessorAction.NEXT ProcessorAction.NEXT
} }
} else if (this is FirPropertySymbol) { } else if (this is FirPropertySymbol) {
parentClassScope?.processDirectlyOverriddenProperties(this) { parentClassScope?.processDirectlyOverriddenProperties(this) {
it.loadExperimentalities(context, result, visited, fromSetter) it.loadExperimentalities(context, result, visited, fromSetter, dispatchReceiverType = null)
ProcessorAction.NEXT ProcessorAction.NEXT
} }
} }
@@ -119,13 +120,17 @@ object FirOptInUsageBaseChecker {
} }
} }
} }
parentClassSymbol?.loadExperimentalities(context, result, visited, fromSetter = false) if (dispatchReceiverType == null) {
parentClassSymbol?.loadExperimentalities(context, result, visited, fromSetter = false, dispatchReceiverType = null)
} else {
dispatchReceiverType.addExperimentalities(context, result, visited)
}
if (fromSetter && this is FirPropertySymbol) { if (fromSetter && this is FirPropertySymbol) {
setterSymbol?.loadExperimentalities(context, result, visited, fromSetter = false) setterSymbol?.loadExperimentalities(context, result, visited, fromSetter = false, dispatchReceiverType)
} }
} else if (this is FirRegularClassSymbol && fir is FirRegularClass && !fir.isLocal) { } else if (this is FirRegularClassSymbol && fir is FirRegularClass && !fir.isLocal) {
val parentClassSymbol = outerClassSymbol(context) val parentClassSymbol = outerClassSymbol(context)
parentClassSymbol?.loadExperimentalities(context, result, visited, fromSetter = false) parentClassSymbol?.loadExperimentalities(context, result, visited, fromSetter = false, dispatchReceiverType = null)
} }
for (annotation in fir.annotations) { for (annotation in fir.annotations) {
@@ -164,7 +169,7 @@ object FirOptInUsageBaseChecker {
) { ) {
if (this !is ConeClassLikeType) return if (this !is ConeClassLikeType) return
lookupTag.toSymbol(context.session)?.loadExperimentalities( lookupTag.toSymbol(context.session)?.loadExperimentalities(
context, result, visited, fromSetter = false context, result, visited, fromSetter = false, dispatchReceiverType = null
) )
fullyExpandedType(context.session).typeArguments.forEach { fullyExpandedType(context.session).typeArguments.forEach {
if (!it.isStarProjection) it.type?.addExperimentalities(context, result, visited) if (!it.isStarProjection) it.type?.addExperimentalities(context, result, visited)
@@ -13,7 +13,7 @@ object FirOptInUsageQualifierChecker : FirResolvedQualifierChecker() {
override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) { override fun check(expression: FirResolvedQualifier, context: CheckerContext, reporter: DiagnosticReporter) {
val symbol = expression.symbol ?: return val symbol = expression.symbol ?: return
with(FirOptInUsageBaseChecker) { with(FirOptInUsageBaseChecker) {
val experimentalities = symbol.loadExperimentalities(context, fromSetter = false) val experimentalities = symbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType = null)
reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter) reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter)
} }
} }
@@ -59,7 +59,7 @@ object FirOptInUsageTypeRefChecker : FirTypeRefChecker() {
} }
with(FirOptInUsageBaseChecker) { with(FirOptInUsageBaseChecker) {
val experimentalities = symbol.loadExperimentalities(context, fromSetter = false) + val experimentalities = symbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType = null) +
loadExperimentalitiesFromConeArguments(context, coneType.typeArguments.toList()) loadExperimentalitiesFromConeArguments(context, coneType.typeArguments.toList())
reportNotAcceptedExperimentalities(experimentalities, typeRef, context, reporter) reportNotAcceptedExperimentalities(experimentalities, typeRef, context, reporter)
} }
@@ -55,4 +55,4 @@ fun use1() {
C.D.<!OPT_IN_USAGE!>E<!>.<!OPT_IN_USAGE!>F<!>() C.D.<!OPT_IN_USAGE!>E<!>.<!OPT_IN_USAGE!>F<!>()
} }
fun use2(f: <!OPT_IN_USAGE!>C.D.E.F<!>) = <!OPT_IN_USAGE!>f<!>.hashCode() fun use2(f: <!OPT_IN_USAGE!>C.D.E.F<!>) = <!OPT_IN_USAGE!>f<!>.<!OPT_IN_USAGE!>hashCode<!>()
@@ -49,7 +49,7 @@ interface NotExperimentalExtension : ExperimentalType {
fun use(arg: NotExperimentalExtension) { fun use(arg: NotExperimentalExtension) {
arg.foo() arg.foo()
arg.<!OPT_IN_USAGE_ERROR!>bar<!>() arg.bar()
} }
@Marker @Marker
@@ -120,5 +120,5 @@ fun operatorContainerUsage(s: String, a: AnotherContainer) {
val res1 = s <!OPT_IN_USAGE_ERROR!>-<!> s val res1 = s <!OPT_IN_USAGE_ERROR!>-<!> s
val res2 = <!OPT_IN_USAGE_ERROR!>s<!>() val res2 = <!OPT_IN_USAGE_ERROR!>s<!>()
val res3 = <!OPT_IN_USAGE_ERROR!>res1<!> <!OPT_IN_USAGE_ERROR!>><!> <!OPT_IN_USAGE_ERROR!>res2<!> val res3 = <!OPT_IN_USAGE_ERROR!>res1<!> <!OPT_IN_USAGE_ERROR!>><!> <!OPT_IN_USAGE_ERROR!>res2<!>
<!OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR!>for (c in a) {}<!> <!OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR!>for (c in a) {}<!>
} }
@@ -49,7 +49,7 @@ interface NotExperimentalExtension : ExperimentalType {
fun use(arg: NotExperimentalExtension) { fun use(arg: NotExperimentalExtension) {
arg.foo() arg.foo()
arg.<!OPT_IN_USAGE_ERROR!>bar<!>() arg.bar()
} }
@Marker @Marker
@@ -120,5 +120,5 @@ fun operatorContainerUsage(s: String, a: AnotherContainer) {
val res1 = s <!OPT_IN_USAGE_ERROR!>-<!> s val res1 = s <!OPT_IN_USAGE_ERROR!>-<!> s
val res2 = <!OPT_IN_USAGE_ERROR!>s<!>() val res2 = <!OPT_IN_USAGE_ERROR!>s<!>()
val res3 = <!OPT_IN_USAGE_ERROR!>res1<!> <!OPT_IN_USAGE_ERROR!>><!> <!OPT_IN_USAGE_ERROR!>res2<!> val res3 = <!OPT_IN_USAGE_ERROR!>res1<!> <!OPT_IN_USAGE_ERROR!>><!> <!OPT_IN_USAGE_ERROR!>res2<!>
<!OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR!>for (c in a) {}<!> <!OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR, OPT_IN_USAGE_ERROR!>for (c in a) {}<!>
} }