K2 opt-in: fix reporting of WasExperimental-bound errors
This commit is contained in:
committed by
Space Team
parent
f62bdb0e3d
commit
3e22f6c052
+11
-5
@@ -90,16 +90,22 @@ fun FirClassLikeSymbol<*>.getTargetAnnotation(): FirAnnotation? {
|
||||
return getAnnotationByClassId(StandardClassIds.Annotations.Target)
|
||||
}
|
||||
|
||||
fun FirExpression.extractClassesFromArgument(): List<FirRegularClassSymbol> {
|
||||
fun FirExpression.extractClassesFromArgument(session: FirSession): List<FirRegularClassSymbol> {
|
||||
return unfoldArrayOrVararg().mapNotNull {
|
||||
it.extractClassFromArgument()
|
||||
it.extractClassFromArgument(session)
|
||||
}
|
||||
}
|
||||
|
||||
fun FirExpression.extractClassFromArgument(): FirRegularClassSymbol? {
|
||||
fun FirExpression.extractClassFromArgument(session: FirSession): FirRegularClassSymbol? {
|
||||
if (this !is FirGetClassCall) return null
|
||||
val qualifier = argument as? FirResolvedQualifier ?: return null
|
||||
return qualifier.symbol as? FirRegularClassSymbol
|
||||
return when (val argument = argument) {
|
||||
is FirResolvedQualifier ->
|
||||
argument.symbol as? FirRegularClassSymbol
|
||||
is FirClassReferenceExpression ->
|
||||
argument.classTypeRef.coneTypeSafe<ConeClassLikeType>()?.fullyExpandedType(session)?.toRegularClassSymbol(session)
|
||||
else ->
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun checkRepeatedAnnotation(
|
||||
|
||||
+3
-3
@@ -69,7 +69,7 @@ private fun FirDeclaration.getOwnSinceKotlinVersion(session: FirSession): FirSin
|
||||
if (apiVersion != null) {
|
||||
// TODO: combine wasExperimentalMarkerClasses in case of several associated declarations with the same maximal API version
|
||||
if (result == null || apiVersion > result!!.apiVersion) {
|
||||
result = FirSinceKotlinValue(apiVersion, loadWasExperimentalMarkerClasses())
|
||||
result = FirSinceKotlinValue(apiVersion, loadWasExperimentalMarkerClasses(session))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,9 +96,9 @@ private fun FirDeclaration.getOwnSinceKotlinVersion(session: FirSession): FirSin
|
||||
return result
|
||||
}
|
||||
|
||||
private fun FirDeclaration.loadWasExperimentalMarkerClasses(): List<FirRegularClassSymbol> {
|
||||
private fun FirDeclaration.loadWasExperimentalMarkerClasses(session: FirSession): List<FirRegularClassSymbol> {
|
||||
val wasExperimental = getAnnotationByClassId(OptInNames.WAS_EXPERIMENTAL_CLASS_ID) ?: return emptyList()
|
||||
val annotationClasses = wasExperimental.findArgumentByName(OptInNames.WAS_EXPERIMENTAL_ANNOTATION_CLASS) ?: return emptyList()
|
||||
return annotationClasses.extractClassesFromArgument()
|
||||
return annotationClasses.extractClassesFromArgument(session)
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.extractClassesFromArgument
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirOptInUsageBaseChecker.loadExperimentalityForMarkerAnnotation
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.extractClassFromArgument
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.modality
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
@@ -46,7 +45,7 @@ object FirOptInAnnotationCallChecker : FirAnnotationCallChecker() {
|
||||
reporter.reportOn(expression.source, FirErrors.OPT_IN_WITHOUT_ARGUMENTS, context)
|
||||
} else {
|
||||
val annotationClasses = expression.findArgumentByName(OPT_IN_ANNOTATION_CLASS)
|
||||
for (classSymbol in annotationClasses?.extractClassesFromArgument().orEmpty()) {
|
||||
for (classSymbol in annotationClasses?.extractClassesFromArgument(context.session).orEmpty()) {
|
||||
checkOptInArgumentIsMarker(classSymbol, expression.source, reporter, context)
|
||||
}
|
||||
}
|
||||
@@ -73,7 +72,7 @@ object FirOptInAnnotationCallChecker : FirAnnotationCallChecker() {
|
||||
return
|
||||
}
|
||||
}
|
||||
val classSymbol = expression.findArgumentByName(OPT_IN_ANNOTATION_CLASS)?.extractClassFromArgument() ?: return
|
||||
val classSymbol = expression.findArgumentByName(OPT_IN_ANNOTATION_CLASS)?.extractClassFromArgument(context.session) ?: return
|
||||
checkOptInArgumentIsMarker(classSymbol, expression.source, reporter, context)
|
||||
}
|
||||
}
|
||||
|
||||
+18
-10
@@ -95,7 +95,8 @@ object FirOptInUsageBaseChecker {
|
||||
if (annotationType.lookupTag.classId == OptInNames.SUBCLASS_OPT_IN_REQUIRED_CLASS_ID) {
|
||||
val annotationClass = annotation.findArgumentByName(OptInNames.OPT_IN_ANNOTATION_CLASS) ?: continue
|
||||
result.addIfNotNull(
|
||||
annotationClass.extractClassFromArgument()?.loadExperimentalityForMarkerAnnotation()?.copy(fromSupertype = true)
|
||||
annotationClass.extractClassFromArgument(session)
|
||||
?.loadExperimentalityForMarkerAnnotation()?.copy(fromSupertype = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -256,7 +257,7 @@ object FirOptInUsageBaseChecker {
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
for ((annotationClassId, severity, markerMessage, supertypeName) in experimentalities) {
|
||||
if (!symbol.fir.isExperimentalityAcceptable(annotationClassId, fromSupertype = false) &&
|
||||
if (!symbol.fir.isExperimentalityAcceptable(context.session, annotationClassId, fromSupertype = false) &&
|
||||
!isExperimentalityAcceptableInContext(annotationClassId, context, fromSupertype = false)
|
||||
) {
|
||||
val (diagnostic, verb) = when (severity) {
|
||||
@@ -285,40 +286,47 @@ object FirOptInUsageBaseChecker {
|
||||
return true
|
||||
}
|
||||
for (annotationContainer in context.annotationContainers) {
|
||||
if (annotationContainer.isExperimentalityAcceptable(annotationClassId, fromSupertype)) {
|
||||
if (annotationContainer.isExperimentalityAcceptable(context.session, annotationClassId, fromSupertype)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun FirAnnotationContainer.isExperimentalityAcceptable(annotationClassId: ClassId, fromSupertype: Boolean): Boolean {
|
||||
return getAnnotationByClassId(annotationClassId) != null || isAnnotatedWithOptIn(annotationClassId) ||
|
||||
fromSupertype && isAnnotatedWithSubclassOptInRequired(annotationClassId)
|
||||
private fun FirAnnotationContainer.isExperimentalityAcceptable(
|
||||
session: FirSession,
|
||||
annotationClassId: ClassId,
|
||||
fromSupertype: Boolean
|
||||
): Boolean {
|
||||
return getAnnotationByClassId(annotationClassId) != null || isAnnotatedWithOptIn(session, annotationClassId) ||
|
||||
fromSupertype && isAnnotatedWithSubclassOptInRequired(session, annotationClassId)
|
||||
}
|
||||
|
||||
private fun FirAnnotationContainer.isAnnotatedWithOptIn(annotationClassId: ClassId): Boolean {
|
||||
private fun FirAnnotationContainer.isAnnotatedWithOptIn(session: FirSession, annotationClassId: ClassId): Boolean {
|
||||
for (annotation in annotations) {
|
||||
val coneType = annotation.annotationTypeRef.coneType as? ConeClassLikeType
|
||||
if (coneType?.lookupTag?.classId != OptInNames.OPT_IN_CLASS_ID) {
|
||||
continue
|
||||
}
|
||||
val annotationClasses = annotation.findArgumentByName(OptInNames.OPT_IN_ANNOTATION_CLASS) ?: continue
|
||||
if (annotationClasses.extractClassesFromArgument().any { it.classId == annotationClassId }) {
|
||||
if (annotationClasses.extractClassesFromArgument(session).any { it.classId == annotationClassId }) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun FirAnnotationContainer.isAnnotatedWithSubclassOptInRequired(annotationClassId: ClassId): Boolean {
|
||||
private fun FirAnnotationContainer.isAnnotatedWithSubclassOptInRequired(
|
||||
session: FirSession,
|
||||
annotationClassId: ClassId
|
||||
): Boolean {
|
||||
for (annotation in annotations) {
|
||||
val coneType = annotation.annotationTypeRef.coneType as? ConeClassLikeType
|
||||
if (coneType?.lookupTag?.classId != OptInNames.SUBCLASS_OPT_IN_REQUIRED_CLASS_ID) {
|
||||
continue
|
||||
}
|
||||
val annotationClass = annotation.findArgumentByName(OptInNames.OPT_IN_ANNOTATION_CLASS) ?: continue
|
||||
if (annotationClass.extractClassFromArgument()?.classId == annotationClassId) {
|
||||
if (annotationClass.extractClassFromArgument(session)?.classId == annotationClassId) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,6 @@ data class Some(val duration: Duration = Duration.INFINITE)
|
||||
fun foo(duration: Duration = Duration.INFINITE) {}
|
||||
|
||||
fun test() {
|
||||
Some()
|
||||
foo()
|
||||
<!OPT_IN_USAGE_ERROR!>Some<!>()
|
||||
<!OPT_IN_USAGE_ERROR!>foo<!>()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user