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.expressions.FirQualifiedAccess
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.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.types.coneType
object FirOptInUsageAccessChecker : FirQualifiedAccessChecker() {
override fun check(expression: FirQualifiedAccess, context: CheckerContext, reporter: DiagnosticReporter) {
@@ -21,14 +24,16 @@ object FirOptInUsageAccessChecker : FirQualifiedAccessChecker() {
) return
val reference = expression.calleeReference as? FirResolvedNamedReference ?: return
val resolvedSymbol = reference.resolvedSymbol
val dispatchReceiverType =
expression.dispatchReceiver.takeIf { it !is FirNoReceiverExpression }?.typeRef?.coneType?.fullyExpandedType(context.session)
with(FirOptInUsageBaseChecker) {
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)
reportNotAcceptedExperimentalities(experimentalities, expression.lValue, context, reporter)
return
}
val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = false) +
val experimentalities = resolvedSymbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType) +
loadExperimentalitiesFromTypeArguments(context, expression.typeArguments)
reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter)
}
@@ -75,9 +75,9 @@ object FirOptInUsageBaseChecker {
}
fun FirBasedSymbol<*>.loadExperimentalities(
context: CheckerContext, fromSetter: Boolean
context: CheckerContext, fromSetter: Boolean, dispatchReceiverType: ConeKotlinType?
): Set<Experimentality> = loadExperimentalities(
context, knownExperimentalities = null, visited = mutableSetOf(), fromSetter
context, knownExperimentalities = null, visited = mutableSetOf(), fromSetter, dispatchReceiverType
)
@OptIn(SymbolInternals::class)
@@ -86,6 +86,7 @@ object FirOptInUsageBaseChecker {
knownExperimentalities: SmartSet<Experimentality>?,
visited: MutableSet<FirAnnotatedDeclaration>,
fromSetter: Boolean,
dispatchReceiverType: ConeKotlinType?,
): Set<Experimentality> {
ensureResolved(FirResolvePhase.STATUS)
val fir = this.fir as? FirAnnotatedDeclaration ?: return emptySet()
@@ -99,12 +100,12 @@ object FirOptInUsageBaseChecker {
val parentClassScope = parentClassSymbol?.unsubstitutedScope(context)
if (this is FirNamedFunctionSymbol) {
parentClassScope?.processDirectlyOverriddenFunctions(this) {
it.loadExperimentalities(context, result, visited, fromSetter = false)
it.loadExperimentalities(context, result, visited, fromSetter = false, dispatchReceiverType = null)
ProcessorAction.NEXT
}
} else if (this is FirPropertySymbol) {
parentClassScope?.processDirectlyOverriddenProperties(this) {
it.loadExperimentalities(context, result, visited, fromSetter)
it.loadExperimentalities(context, result, visited, fromSetter, dispatchReceiverType = null)
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) {
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) {
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) {
@@ -164,7 +169,7 @@ object FirOptInUsageBaseChecker {
) {
if (this !is ConeClassLikeType) return
lookupTag.toSymbol(context.session)?.loadExperimentalities(
context, result, visited, fromSetter = false
context, result, visited, fromSetter = false, dispatchReceiverType = null
)
fullyExpandedType(context.session).typeArguments.forEach {
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) {
val symbol = expression.symbol ?: return
with(FirOptInUsageBaseChecker) {
val experimentalities = symbol.loadExperimentalities(context, fromSetter = false)
val experimentalities = symbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType = null)
reportNotAcceptedExperimentalities(experimentalities, expression, context, reporter)
}
}
@@ -59,7 +59,7 @@ object FirOptInUsageTypeRefChecker : FirTypeRefChecker() {
}
with(FirOptInUsageBaseChecker) {
val experimentalities = symbol.loadExperimentalities(context, fromSetter = false) +
val experimentalities = symbol.loadExperimentalities(context, fromSetter = false, dispatchReceiverType = null) +
loadExperimentalitiesFromConeArguments(context, coneType.typeArguments.toList())
reportNotAcceptedExperimentalities(experimentalities, typeRef, context, reporter)
}
@@ -55,4 +55,4 @@ fun use1() {
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) {
arg.foo()
arg.<!OPT_IN_USAGE_ERROR!>bar<!>()
arg.bar()
}
@Marker
@@ -120,5 +120,5 @@ fun operatorContainerUsage(s: String, a: AnotherContainer) {
val res1 = s <!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<!>
<!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) {
arg.foo()
arg.<!OPT_IN_USAGE_ERROR!>bar<!>()
arg.bar()
}
@Marker
@@ -120,5 +120,5 @@ fun operatorContainerUsage(s: String, a: AnotherContainer) {
val res1 = s <!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<!>
<!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) {}<!>
}