[FIR] Introduce NOT_AN_ANNOTATION_CLASS diagnostic

This commit is contained in:
Mikhail Glukhikh
2020-08-03 11:25:20 +03:00
parent 8fd087a964
commit 2e2099afae
11 changed files with 40 additions and 42 deletions
@@ -87,6 +87,7 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect
is ConeVariableExpectedError -> FirErrors.VARIABLE_EXPECTED.on(source)
is ConeTypeMismatchError -> FirErrors.TYPE_MISMATCH.on(source, diagnostic.expectedType, diagnostic.actualType)
is ConeUnexpectedTypeArgumentsError -> FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED.on(diagnostic.source.safeAs() ?: source)
is ConeIllegalAnnotationError -> FirErrors.NOT_AN_ANNOTATION_CLASS.on(source, diagnostic.name.asString())
is ConeSimpleDiagnostic -> if (source.kind is FirFakeSourceElementKind) {
null
} else if (diagnostic.kind == SymbolNotFound) {
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_PROPERTY_
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_RECEIVER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HIDDEN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NOT_AN_ANNOTATION_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_UNDERSCORE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CANDIDATE
@@ -74,6 +75,9 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(DEPRECATED_MODIFIER_PAIR, "Modifier ''{0}'' is deprecated in presence of ''{1}''", TO_STRING, TO_STRING)
map.put(INCOMPATIBLE_MODIFIERS, "Modifier ''{0}'' is incompatible with ''{1}''", TO_STRING, TO_STRING)
// Annotations
map.put(NOT_AN_ANNOTATION_CLASS, "Illegal annotation class: {0}", NULLABLE_STRING)
// Exposed visibility group
map.put(EXPOSED_TYPEALIAS_EXPANDED_TYPE, "{0} typealias exposes {2} in expanded type{1}", TO_STRING, TO_STRING, TO_STRING)
map.put(EXPOSED_PROPERTY_TYPE, "{0} property exposes its {2} type{1}", TO_STRING, TO_STRING, TO_STRING)
@@ -62,6 +62,7 @@ object FirErrors {
val NULLABLE_TYPE_OF_ANNOTATION_MEMBER by existing<FirSourceElement, KtTypeReference>(Errors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER)
val INVALID_TYPE_OF_ANNOTATION_MEMBER by existing<FirSourceElement, KtTypeReference>(Errors.INVALID_TYPE_OF_ANNOTATION_MEMBER)
val VAR_ANNOTATION_PARAMETER by existing<FirSourceElement, KtParameter>(Errors.VAR_ANNOTATION_PARAMETER)
val NOT_AN_ANNOTATION_CLASS by error1<FirSourceElement, PsiElement, String>()
// Exposed visibility group
val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3<FirSourceElement, PsiElement, FirEffectiveVisibility, FirMemberDeclaration, FirEffectiveVisibility>()
@@ -20,10 +20,7 @@ import org.jetbrains.kotlin.fir.resolve.*
import org.jetbrains.kotlin.fir.resolve.calls.*
import org.jetbrains.kotlin.fir.resolve.calls.tower.FirTowerResolver
import org.jetbrains.kotlin.fir.resolve.calls.tower.TowerResolveManager
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeHiddenCandidateError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedNameError
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
import org.jetbrains.kotlin.fir.resolve.inference.ResolvedCallableReferenceAtom
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.StoreNameReference
@@ -333,24 +330,35 @@ class FirCallResolver(
containingDeclarations
)
val resolutionResult = createCandidateForAnnotationCall(annotationCall, callInfo)
?: ResolutionResult(callInfo, CandidateApplicability.HIDDEN, emptyList())
val resolvedReference = createResolvedNamedReference(
reference,
reference.name,
callInfo,
resolutionResult.candidates,
resolutionResult.applicability,
explicitReceiver = null
)
val annotationClassSymbol = annotationCall.getCorrespondingClassSymbolOrNull(session)
val resolvedReference = if (annotationClassSymbol != null && annotationClassSymbol.fir.classKind == ClassKind.ANNOTATION_CLASS) {
val resolutionResult = createCandidateForAnnotationCall(annotationClassSymbol, callInfo)
?: ResolutionResult(callInfo, CandidateApplicability.HIDDEN, emptyList())
createResolvedNamedReference(
reference,
reference.name,
callInfo,
resolutionResult.candidates,
resolutionResult.applicability,
explicitReceiver = null
)
} else {
buildErrorReference(
callInfo,
if (annotationClassSymbol != null) ConeIllegalAnnotationError(reference.name)
else ConeUnresolvedNameError(reference.name),
reference.source,
reference.name
)
}
return annotationCall.transformCalleeReference(StoreNameReference, resolvedReference)
}
private fun createCandidateForAnnotationCall(annotationCall: FirAnnotationCall, callInfo: CallInfo): ResolutionResult? {
val annotationClassSymbol = annotationCall.getCorrespondingClassSymbolOrNull(session)
?.takeIf { it.fir.classKind == ClassKind.ANNOTATION_CLASS }
?: return null
private fun createCandidateForAnnotationCall(
annotationClassSymbol: FirRegularClassSymbol,
callInfo: CallInfo
): ResolutionResult? {
var constructorSymbol: FirConstructorSymbol? = null
annotationClassSymbol.fir.buildUseSiteMemberScope(session, scopeSession)?.processDeclaredConstructors {
if (it.fir.isPrimary && constructorSymbol == null) {
@@ -67,6 +67,10 @@ class ConeTypeMismatchError(val expectedType: ConeKotlinType, val actualType: Co
class ConeContractDescriptionError(override val reason: String) : ConeDiagnostic()
class ConeIllegalAnnotationError(val name: Name) : ConeDiagnostic() {
override val reason: String get() = "Not a legal annotation: $name"
}
private fun describeSymbol(symbol: AbstractFirBasedSymbol<*>): String {
return when (symbol) {
is FirClassLikeSymbol<*> -> symbol.classId.asString()
@@ -1,6 +1,6 @@
// !WITH_NEW_INFERENCE
import java.util.ArrayList
@ArrayList<Int>(1, 1) fun b() {}
<!NOT_AN_ANNOTATION_CLASS!>@ArrayList<Int>(1, 1)<!> fun b() {}
@<!UNRESOLVED_REFERENCE!>Xoo<!>(<!UNRESOLVED_REFERENCE!>x<!>) fun c() {}
<!INAPPLICABLE_CANDIDATE!>@java.lang.Deprecated(<!UNRESOLVED_REFERENCE!>x<!>)<!> fun a() {}
@@ -1,19 +0,0 @@
// FILE: a.kt
annotation class annotation
// FILE: test/b.kt
package test
@test.annotation class annotation
// FILE: other/c.kt
package other
annotation class My
@test.annotation class Your
@My class Our
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: a.kt
annotation class annotation
@@ -1,3 +0,0 @@
class Foo
@Foo class Bar
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
class Foo
<!NOT_AN_ANNOTATION_CLASS!>@Foo<!> class Bar
@@ -1,2 +1,2 @@
// Class constructor parameter CAN be recursively annotated
class RecursivelyAnnotated(@RecursivelyAnnotated(1) val x: Int)
class RecursivelyAnnotated(<!NOT_AN_ANNOTATION_CLASS, NOT_AN_ANNOTATION_CLASS!>@RecursivelyAnnotated(1)<!> val x: Int)