[FE] Implement FE logic of expect actual annotations matching
This implementation only checks annotations set on expect/actual declarations and requires further refinement (e.g. checking of other annotation targets, class scopes within typealiases). ^KT-58551
This commit is contained in:
committed by
Space Team
parent
b1bdb619d8
commit
1a4ab9bb4b
+94
@@ -205,6 +205,100 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/annotationMatching")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class AnnotationMatching {
|
||||
@Test
|
||||
public void testAllFilesPresentInAnnotationMatching() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/annotationMatching"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationArgumentsConstExpressions.kt")
|
||||
public void testAnnotationArgumentsConstExpressions() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationArgumentsDefaults.kt")
|
||||
public void testAnnotationArgumentsDefaults() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationTypeParameters.kt")
|
||||
public void testAnnotationTypeParameters() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("basicOnDeclaration.kt")
|
||||
public void testBasicOnDeclaration() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("checkDiagnosticFullText.kt")
|
||||
public void testCheckDiagnosticFullText() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compatibleOverrides.kt")
|
||||
public void testCompatibleOverrides() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("differentOrder.kt")
|
||||
public void testDifferentOrder() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("floatNumbersComparison.kt")
|
||||
public void testFloatNumbersComparison() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kclassArgWithExpectClass.kt")
|
||||
public void testKclassArgWithExpectClass() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnaloguesForJavaAnnotations.kt")
|
||||
public void testKotlinAnaloguesForJavaAnnotations() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealias.kt")
|
||||
public void testTypealias() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealiasToJavaLibrary.kt")
|
||||
public void testTypealiasToJavaLibrary() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealiasToKtLibrary.kt")
|
||||
public void testTypealiasToKtLibrary() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("withOtherIncomatibilities.kt")
|
||||
public void testWithOtherIncomatibilities() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+94
@@ -205,6 +205,100 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/widerVisibilityInActualClassifier.kt");
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/annotationMatching")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class AnnotationMatching {
|
||||
@Test
|
||||
public void testAllFilesPresentInAnnotationMatching() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/multiplatform/annotationMatching"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.(reversed|fir|ll)\\.kts?$"), TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationArgumentsConstExpressions.kt")
|
||||
public void testAnnotationArgumentsConstExpressions() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsConstExpressions.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationArgumentsDefaults.kt")
|
||||
public void testAnnotationArgumentsDefaults() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationArgumentsDefaults.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("annotationTypeParameters.kt")
|
||||
public void testAnnotationTypeParameters() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/annotationTypeParameters.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("basicOnDeclaration.kt")
|
||||
public void testBasicOnDeclaration() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/basicOnDeclaration.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("checkDiagnosticFullText.kt")
|
||||
public void testCheckDiagnosticFullText() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/checkDiagnosticFullText.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("compatibleOverrides.kt")
|
||||
public void testCompatibleOverrides() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/compatibleOverrides.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("differentOrder.kt")
|
||||
public void testDifferentOrder() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/differentOrder.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("floatNumbersComparison.kt")
|
||||
public void testFloatNumbersComparison() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/floatNumbersComparison.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kclassArgWithExpectClass.kt")
|
||||
public void testKclassArgWithExpectClass() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kclassArgWithExpectClass.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kotlinAnaloguesForJavaAnnotations.kt")
|
||||
public void testKotlinAnaloguesForJavaAnnotations() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/kotlinAnaloguesForJavaAnnotations.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealias.kt")
|
||||
public void testTypealias() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealias.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealiasToJavaLibrary.kt")
|
||||
public void testTypealiasToJavaLibrary() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToJavaLibrary.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("typealiasToKtLibrary.kt")
|
||||
public void testTypealiasToKtLibrary() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/typealiasToKtLibrary.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("withOtherIncomatibilities.kt")
|
||||
public void testWithOtherIncomatibilities() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/annotationMatching/withOtherIncomatibilities.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/multiplatform/defaultArguments")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+5
@@ -1180,6 +1180,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION by error<KtTypeAlias>(PositioningStrategy.TYPEALIAS_TYPE_REFERENCE) {
|
||||
parameter<ClassId>("typealiasedClassId")
|
||||
}
|
||||
|
||||
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning<KtElement>(PositioningStrategy.DECLARATION_NAME_ONLY) {
|
||||
parameter<Symbol>("expect")
|
||||
parameter<Symbol>("actual")
|
||||
}
|
||||
}
|
||||
|
||||
val DESTRUCTING_DECLARATION by object : DiagnosticGroup("Destructuring declaration") {
|
||||
|
||||
@@ -628,6 +628,7 @@ object FirErrors {
|
||||
val NOT_A_MULTIPLATFORM_COMPILATION by error0<PsiElement>()
|
||||
val EXPECT_ACTUAL_OPT_IN_ANNOTATION by error0<KtNamedDeclaration>(SourceElementPositioningStrategies.EXPECT_ACTUAL_MODIFIER)
|
||||
val ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION by error1<KtTypeAlias, ClassId>(SourceElementPositioningStrategies.TYPEALIAS_TYPE_REFERENCE)
|
||||
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning2<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME_ONLY)
|
||||
|
||||
// Destructuring declaration
|
||||
val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0<KtDestructuringDeclaration>()
|
||||
|
||||
+27
-4
@@ -20,17 +20,20 @@ import org.jetbrains.kotlin.fir.declarations.utils.isActual
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExpect
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isExternal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isTailRec
|
||||
import org.jetbrains.kotlin.fir.expectActualMatchingContextFactory
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.scopes.collectAllFunctions
|
||||
import org.jetbrains.kotlin.fir.scopes.getDeclaredConstructors
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.declaredMemberScope
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.coneType
|
||||
import org.jetbrains.kotlin.fir.types.toSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker
|
||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.*
|
||||
@@ -176,7 +179,9 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
|
||||
else -> {}
|
||||
}
|
||||
val expectedSingleCandidate = symbol.getSingleExpectForActualOrNull()
|
||||
// We want to report errors even if a candidate is incompatible, but it's single
|
||||
val expectedSingleCandidate = compatibilityToMembersMap[Compatible]?.singleOrNull()
|
||||
?: symbol.getSingleExpectForActualOrNull()
|
||||
if (expectedSingleCandidate != null) {
|
||||
checkIfExpectHasDefaultArgumentsAndActualizedWithTypealias(
|
||||
expectedSingleCandidate,
|
||||
@@ -185,6 +190,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
reporter,
|
||||
)
|
||||
checkOptInAnnotation(declaration, expectedSingleCandidate, context, reporter)
|
||||
checkAnnotationsMatch(expectedSingleCandidate, symbol, context, reporter)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,6 +249,23 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
)
|
||||
}
|
||||
|
||||
private fun checkAnnotationsMatch(
|
||||
expectSymbol: FirBasedSymbol<*>,
|
||||
actualSymbol: FirBasedSymbol<*>,
|
||||
context: CheckerContext,
|
||||
reporter: DiagnosticReporter
|
||||
) {
|
||||
val matchingContext = context.session.expectActualMatchingContextFactory.create(context.session, context.scopeSession)
|
||||
val incompatibility =
|
||||
AbstractExpectActualAnnotationMatchChecker.areAnnotationsCompatible(expectSymbol, actualSymbol, matchingContext) ?: return
|
||||
reporter.reportOn(
|
||||
actualSymbol.source, FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT,
|
||||
incompatibility.expectSymbol as FirBasedSymbol<*>,
|
||||
incompatibility.actualSymbol as FirBasedSymbol<*>,
|
||||
context
|
||||
)
|
||||
}
|
||||
|
||||
fun Map<out ExpectActualCompatibility<*>, *>.allStrongIncompatibilities(): Boolean {
|
||||
return keys.all { it is Incompatible && it.kind == IncompatibilityKind.STRONG }
|
||||
}
|
||||
|
||||
+10
@@ -178,4 +178,14 @@ object FirDiagnosticRenderers {
|
||||
}
|
||||
|
||||
val FUNCTIONAL_TYPE_KINDS = KtDiagnosticRenderers.COLLECTION(FUNCTIONAL_TYPE_KIND)
|
||||
|
||||
@OptIn(SymbolInternals::class)
|
||||
val SYMBOL_WITH_ANNOTATIONS = Renderer { s: FirBasedSymbol<*> ->
|
||||
FirRenderer(
|
||||
typeRenderer = ConeTypeRenderer(),
|
||||
idRenderer = ConeIdShortRenderer(),
|
||||
classMemberRenderer = null,
|
||||
bodyRenderer = null,
|
||||
).renderElementAsString(s.fir, trim = true)
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -51,6 +51,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_PROPERTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ABSTRACT_SUPER_CALL_WARNING
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACCESSOR_FOR_DELEGATED_PROPERTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ACTUAL_MISSING
|
||||
@@ -1854,6 +1855,13 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
"`actual typealias` to annotation which affects code compilation can lead to incorrect behavior. Instead, use ''{0}'' annotation directly.",
|
||||
TO_STRING
|
||||
)
|
||||
map.put(
|
||||
ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT,
|
||||
"All annotations from `expect` must be presented with same arguments on `actual`, otherwise they have no effect.\n" +
|
||||
"Expected: {0}\n" +
|
||||
"Actual: {1}",
|
||||
FirDiagnosticRenderers.SYMBOL_WITH_ANNOTATIONS, FirDiagnosticRenderers.SYMBOL_WITH_ANNOTATIONS
|
||||
)
|
||||
|
||||
// Destructuring declaration
|
||||
map.put(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION, "Initializer required for destructuring declaration")
|
||||
|
||||
+48
-4
@@ -11,12 +11,13 @@ import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.fir.FirExpectActualMatchingContext
|
||||
import org.jetbrains.kotlin.fir.FirExpectActualMatchingContextFactory
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
|
||||
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
|
||||
import org.jetbrains.kotlin.fir.declarations.collectEnumEntries
|
||||
import org.jetbrains.kotlin.fir.declarations.isAnnotationConstructor
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
|
||||
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||
import org.jetbrains.kotlin.fir.isSubstitutionOrIntersectionOverride
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.dfa.coneType
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.mpp.*
|
||||
import org.jetbrains.kotlin.name.CallableId
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.TypeCheckerState
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
@@ -311,6 +313,48 @@ class FirExpectActualMatchingContextImpl private constructor(
|
||||
override val CallableSymbolMarker.hasStableParameterNames: Boolean
|
||||
get() = asSymbol().rawStatus.hasStableParameterNames
|
||||
|
||||
override val DeclarationSymbolMarker.annotations: List<AnnotationCallInfo>
|
||||
get() = asSymbol().resolvedAnnotationsWithArguments.map(::AnnotationCallInfoImpl)
|
||||
|
||||
override fun areAnnotationArgumentsEqual(annotation1: AnnotationCallInfo, annotation2: AnnotationCallInfo): Boolean {
|
||||
fun AnnotationCallInfo.getFirAnnotation(): FirAnnotation {
|
||||
return (this as AnnotationCallInfoImpl).annotation
|
||||
}
|
||||
return areFirAnnotationsEqual(annotation1.getFirAnnotation(), annotation2.getFirAnnotation())
|
||||
}
|
||||
|
||||
private fun areFirAnnotationsEqual(annotation1: FirAnnotation, annotation2: FirAnnotation): Boolean {
|
||||
if (!areCompatibleExpectActualTypes(annotation1.typeRef.coneType, annotation2.typeRef.coneType)) {
|
||||
return false
|
||||
}
|
||||
val args1 = annotation1.argumentMapping.mapping
|
||||
val args2 = annotation2.argumentMapping.mapping
|
||||
if (args1.size != args2.size) {
|
||||
return false
|
||||
}
|
||||
return args1.all { (key, value1) ->
|
||||
val value2 = args2[key]
|
||||
value2 != null && areAnnotationArgumentsEqual(value1, value2)
|
||||
}
|
||||
}
|
||||
|
||||
private fun areAnnotationArgumentsEqual(expression1: FirExpression, expression2: FirExpression): Boolean {
|
||||
// In K2 const expression calculated in backend.
|
||||
// Because of that, we have "honest" checker at backend IR stage
|
||||
// and "only simplest case" checker in frontend, so that we have at least some reporting in the IDE.
|
||||
return when {
|
||||
expression1 is FirConstExpression<*> && expression2 is FirConstExpression<*> -> {
|
||||
expression1.value == expression2.value
|
||||
}
|
||||
else -> true
|
||||
}
|
||||
}
|
||||
|
||||
private inner class AnnotationCallInfoImpl(val annotation: FirAnnotation) : AnnotationCallInfo {
|
||||
override val classId: ClassId?
|
||||
get() = annotation.toAnnotationClassId(actualSession)
|
||||
}
|
||||
|
||||
object Factory : FirExpectActualMatchingContextFactory {
|
||||
override fun create(session: FirSession, scopeSession: ScopeSession): FirExpectActualMatchingContextImpl =
|
||||
FirExpectActualMatchingContextImpl(session, scopeSession)
|
||||
|
||||
Reference in New Issue
Block a user