FIR: handle annotations on non-containers more precisely

This commit is contained in:
Mikhail Glukhikh
2021-04-20 13:24:21 +03:00
parent 04daf8fce8
commit e0c8a6658b
11 changed files with 24 additions and 30 deletions
@@ -10,12 +10,13 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression
object FirAnnotationUsedAsAnnotationArgumentChecker : FirAnnotationCallChecker() {
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
val args = expression.argumentList.arguments
for (arg in args) {
for (ann in arg.annotations) {
for (ann in ((arg as? FirWrappedArgumentExpression)?.expression ?: arg).annotations) {
reporter.reportOn(ann.source, FirErrors.ANNOTATION_USED_AS_ANNOTATION_ARGUMENT, context)
}
}
@@ -63,6 +63,7 @@ private fun ConeDiagnostic.toFirDiagnostic(
is ConeContractDescriptionError -> FirErrors.ERROR_IN_CONTRACT_DESCRIPTION.on(source, this.reason)
is ConeTypeParameterSupertype -> FirErrors.SUPERTYPE_NOT_A_CLASS_OR_INTERFACE.on(source, this.reason)
is ConeTypeParameterInQualifiedAccess -> null // reported in various checkers instead
is ConeNotAnnotationContainer -> null
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildAnonymousFunction
import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.builder.buildValueParameter
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.diagnostics.ConeNotAnnotationContainer
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.*
@@ -411,10 +412,10 @@ class ExpressionsConverter(
}
}
return firExpression?.also {
require(it is FirAnnotationContainer)
(it.annotations as MutableList<FirAnnotationCall>) += firAnnotationList
} ?: buildErrorExpression(null, ConeSimpleDiagnostic("Strange annotated expression: ${firExpression?.render()}", DiagnosticKind.Syntax))
val result = firExpression ?: buildErrorExpression(null, ConeNotAnnotationContainer(firExpression?.render() ?: "???"))
require(result is FirAnnotationContainer)
(result.annotations as MutableList<FirAnnotationCall>) += firAnnotationList
return result
}
/**
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter
import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter
import org.jetbrains.kotlin.fir.diagnostics.ConeNotAnnotationContainer
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.*
@@ -2083,15 +2084,10 @@ open class RawFirBuilder(
override fun visitAnnotatedExpression(expression: KtAnnotatedExpression, data: Unit): FirElement {
val rawResult = expression.baseExpression?.accept(this, data)
// return rawResult ?: buildErrorExpression(
// expression.toFirSourceElement(),
// FirSimpleDiagnostic("Strange annotated expression: ${rawResult?.render()}", DiagnosticKind.Syntax),
// )
// TODO !!!!!!!!
val result = rawResult as? FirAnnotationContainer
?: return buildErrorExpression(
?: buildErrorExpression(
expression.toFirSourceElement(),
ConeSimpleDiagnostic("Strange annotated expression: ${rawResult?.render()}", DiagnosticKind.Syntax),
ConeNotAnnotationContainer(rawResult?.render() ?: "???")
)
expression.extractAnnotationsTo(result.annotations as MutableList<FirAnnotationCall>)
return result
@@ -27,11 +27,13 @@ import org.jetbrains.kotlin.fir.visitors.*
@FirBuilderDsl
class FirErrorExpressionBuilder : FirAnnotationContainerBuilder, FirExpressionBuilder {
override var source: FirSourceElement? = null
override val annotations: MutableList<FirAnnotationCall> = mutableListOf()
lateinit var diagnostic: ConeDiagnostic
override fun build(): FirErrorExpression {
return FirErrorExpressionImpl(
source,
annotations,
diagnostic,
)
}
@@ -43,9 +45,6 @@ class FirErrorExpressionBuilder : FirAnnotationContainerBuilder, FirExpressionBu
set(_) {
throw IllegalStateException()
}
@Deprecated("Modification of 'annotations' has no impact for FirErrorExpressionBuilder", level = DeprecationLevel.HIDDEN)
override val annotations: MutableList<FirAnnotationCall> = mutableListOf()
}
@OptIn(ExperimentalContracts::class)
@@ -21,21 +21,24 @@ import org.jetbrains.kotlin.fir.visitors.*
internal class FirErrorExpressionImpl(
override val source: FirSourceElement?,
override val annotations: MutableList<FirAnnotationCall>,
override val diagnostic: ConeDiagnostic,
) : FirErrorExpression() {
override var typeRef: FirTypeRef = FirErrorTypeRefImpl(source, null, ConeStubDiagnostic(diagnostic))
override val annotations: List<FirAnnotationCall> get() = emptyList()
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
typeRef.accept(visitor, data)
annotations.forEach { it.accept(visitor, data) }
}
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirErrorExpressionImpl {
typeRef = typeRef.transform(transformer, data)
transformAnnotations(transformer, data)
return this
}
override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirErrorExpressionImpl {
annotations.transformInplace(transformer, data)
return this
}
@@ -28,7 +28,7 @@ internal class FirErrorLoopImpl(
override val diagnostic: ConeDiagnostic,
) : FirErrorLoop() {
override var block: FirBlock = FirEmptyExpressionBlock()
override var condition: FirExpression = FirErrorExpressionImpl(source, ConeStubDiagnostic(diagnostic))
override var condition: FirExpression = FirErrorExpressionImpl(source, mutableListOf(), ConeStubDiagnostic(diagnostic))
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
annotations.forEach { it.accept(visitor, data) }
@@ -7,6 +7,10 @@ package org.jetbrains.kotlin.fir.diagnostics
class ConeSimpleDiagnostic(override val reason: String, val kind: DiagnosticKind = DiagnosticKind.Other) : ConeDiagnostic()
class ConeNotAnnotationContainer(val text: String) : ConeDiagnostic() {
override val reason: String get() = "Strange annotated expression: $text"
}
enum class DiagnosticKind {
Syntax,
ExpressionExpected,
@@ -128,7 +128,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
impl(errorLoop) {
default("block", "FirEmptyExpressionBlock()")
default("condition", "FirErrorExpressionImpl(source, ConeStubDiagnostic(diagnostic))")
default("condition", "FirErrorExpressionImpl(source, mutableListOf(), ConeStubDiagnostic(diagnostic))")
useTypes(emptyExpressionBlock, coneStubDiagnosticType)
}
@@ -394,7 +394,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
}
impl(errorExpression) {
defaultEmptyList("annotations")
default("typeRef", "FirErrorTypeRefImpl(source, null, ConeStubDiagnostic(diagnostic))")
useTypes(errorTypeRefImpl, coneStubDiagnosticType)
}
@@ -1,11 +0,0 @@
// SKIP_ERRORS_BEFORE
annotation class X(val value: Y, val y: Y)
annotation class Y()
@X(@Y()<!SYNTAX!><!>, y = Y())
fun foo1() {
}
@X(@Y()<!SYNTAX!><!>, y = @Y()<!SYNTAX!><!>)
fun foo2() {
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// SKIP_ERRORS_BEFORE
annotation class X(val value: Y, val y: Y)