[FE, IR] Store PsiElement for mismatched annotation's actual target
There is IDE quick fix which suggests to copy mismatched annotation from `expect` to `actual` (see KTIJ-26633). It needs to find `actual` PsiElement where to add annotation. Before previous commit, it was easy - just get source of `Incompatibility.actualSymbol`. After previous commit, the problem might be in value parameter, while `actualSymbol` would contain function symbol. This is solved by adding new field `Incompatibility.actualAnnotationTargetElement`. `SourceElementMarker` introduced, because it's needed to be used in abstract checker. Existing `DeclarationSymbolMarker` doesn't fit because in next PR for this issue annotations set on types will be reported, and types are not declarations. ^KT-60671
This commit is contained in:
committed by
Space Team
parent
5c95f69aef
commit
420dceb7d8
+8
@@ -214,6 +214,14 @@ internal object FirToKtConversionCreator {
|
|||||||
"org.jetbrains.kotlin.psi"
|
"org.jetbrains.kotlin.psi"
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
KtSourceElement::class to HLFunctionCallConversion(
|
||||||
|
"({0} as? KtPsiSourceElement)?.psi",
|
||||||
|
PsiElement::class.createType(nullable = true),
|
||||||
|
importsToAdd = listOf(
|
||||||
|
"org.jetbrains.kotlin.psi",
|
||||||
|
"org.jetbrains.kotlin.KtPsiSourceElement"
|
||||||
|
)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
private val typeMapping: Map<KClass<*>, HLFunctionCallConversion> = mapOf(
|
private val typeMapping: Map<KClass<*>, HLFunctionCallConversion> = mapOf(
|
||||||
|
|||||||
+2
-1
@@ -3717,7 +3717,8 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
ActualAnnotationsNotMatchExpectImpl(
|
ActualAnnotationsNotMatchExpectImpl(
|
||||||
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
||||||
firSymbolBuilder.buildSymbol(firDiagnostic.b),
|
firSymbolBuilder.buildSymbol(firDiagnostic.b),
|
||||||
firDiagnostic.c,
|
(firDiagnostic.c as? KtPsiSourceElement)?.psi,
|
||||||
|
firDiagnostic.d,
|
||||||
firDiagnostic as KtPsiDiagnostic,
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
|
|||||||
+1
@@ -2601,6 +2601,7 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = ActualAnnotationsNotMatchExpect::class
|
override val diagnosticClass get() = ActualAnnotationsNotMatchExpect::class
|
||||||
val expectSymbol: KtSymbol
|
val expectSymbol: KtSymbol
|
||||||
val actualSymbol: KtSymbol
|
val actualSymbol: KtSymbol
|
||||||
|
val actualAnnotationTargetSourceElement: PsiElement?
|
||||||
val incompatibilityType: ExpectActualAnnotationsIncompatibilityType<FirAnnotation>
|
val incompatibilityType: ExpectActualAnnotationsIncompatibilityType<FirAnnotation>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -3133,6 +3133,7 @@ internal class ActualTypealiasToSpecialAnnotationImpl(
|
|||||||
internal class ActualAnnotationsNotMatchExpectImpl(
|
internal class ActualAnnotationsNotMatchExpectImpl(
|
||||||
override val expectSymbol: KtSymbol,
|
override val expectSymbol: KtSymbol,
|
||||||
override val actualSymbol: KtSymbol,
|
override val actualSymbol: KtSymbol,
|
||||||
|
override val actualAnnotationTargetSourceElement: PsiElement?,
|
||||||
override val incompatibilityType: ExpectActualAnnotationsIncompatibilityType<FirAnnotation>,
|
override val incompatibilityType: ExpectActualAnnotationsIncompatibilityType<FirAnnotation>,
|
||||||
firDiagnostic: KtPsiDiagnostic,
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
token: KtLifetimeToken,
|
token: KtLifetimeToken,
|
||||||
|
|||||||
+3
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
|||||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||||
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
import org.jetbrains.kotlin.fir.FirModuleData
|
import org.jetbrains.kotlin.fir.FirModuleData
|
||||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
|
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
import org.jetbrains.kotlin.fir.declarations.FirFunction
|
||||||
@@ -41,6 +42,7 @@ import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Inco
|
|||||||
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
|
import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.util.PrivateForInline
|
import org.jetbrains.kotlin.util.PrivateForInline
|
||||||
|
import java.util.Optional
|
||||||
import kotlin.properties.PropertyDelegateProvider
|
import kotlin.properties.PropertyDelegateProvider
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
|
|
||||||
@@ -1268,6 +1270,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning<KtElement>(PositioningStrategy.DECLARATION_NAME_ONLY) {
|
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning<KtElement>(PositioningStrategy.DECLARATION_NAME_ONLY) {
|
||||||
parameter<Symbol>("expectSymbol")
|
parameter<Symbol>("expectSymbol")
|
||||||
parameter<Symbol>("actualSymbol")
|
parameter<Symbol>("actualSymbol")
|
||||||
|
parameter<KtSourceElement?>("actualAnnotationTargetSourceElement")
|
||||||
parameter<ExpectActualAnnotationsIncompatibilityType<FirAnnotation>>("incompatibilityType")
|
parameter<ExpectActualAnnotationsIncompatibilityType<FirAnnotation>>("incompatibilityType")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -662,7 +662,7 @@ object FirErrors {
|
|||||||
val NOT_A_MULTIPLATFORM_COMPILATION by error0<PsiElement>()
|
val NOT_A_MULTIPLATFORM_COMPILATION by error0<PsiElement>()
|
||||||
val EXPECT_ACTUAL_OPT_IN_ANNOTATION by error0<KtNamedDeclaration>(SourceElementPositioningStrategies.EXPECT_ACTUAL_MODIFIER)
|
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_TYPEALIAS_TO_SPECIAL_ANNOTATION by error1<KtTypeAlias, ClassId>(SourceElementPositioningStrategies.TYPEALIAS_TYPE_REFERENCE)
|
||||||
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning3<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>, ExpectActualAnnotationsIncompatibilityType<FirAnnotation>>(SourceElementPositioningStrategies.DECLARATION_NAME_ONLY)
|
val ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT by warning4<KtElement, FirBasedSymbol<*>, FirBasedSymbol<*>, KtSourceElement?, ExpectActualAnnotationsIncompatibilityType<FirAnnotation>>(SourceElementPositioningStrategies.DECLARATION_NAME_ONLY)
|
||||||
val OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY by error0<PsiElement>()
|
val OPTIONAL_DECLARATION_OUTSIDE_OF_ANNOTATION_ENTRY by error0<PsiElement>()
|
||||||
val OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE by error0<PsiElement>()
|
val OPTIONAL_DECLARATION_USAGE_IN_NON_COMMON_SOURCE by error0<PsiElement>()
|
||||||
val OPTIONAL_EXPECTATION_NOT_ON_EXPECTED by error0<PsiElement>()
|
val OPTIONAL_EXPECTATION_NOT_ON_EXPECTED by error0<PsiElement>()
|
||||||
|
|||||||
+17
-10
@@ -8,10 +8,9 @@ package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
|||||||
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
import org.jetbrains.kotlin.KtFakeSourceElementKind
|
||||||
import org.jetbrains.kotlin.config.LanguageFeature
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
import org.jetbrains.kotlin.diagnostics.*
|
||||||
import org.jetbrains.kotlin.diagnostics.SourceElementPositioningStrategies
|
|
||||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.getModifierList
|
import org.jetbrains.kotlin.fir.analysis.checkers.getModifierList
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
@@ -35,7 +34,8 @@ import org.jetbrains.kotlin.name.StandardClassIds
|
|||||||
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker
|
import org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames
|
import org.jetbrains.kotlin.resolve.checkers.OptInNames
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.*
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Compatible
|
||||||
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.isCompatibleOrWeaklyIncompatible
|
import org.jetbrains.kotlin.resolve.multiplatform.isCompatibleOrWeaklyIncompatible
|
||||||
|
|
||||||
@Suppress("DuplicatedCode")
|
@Suppress("DuplicatedCode")
|
||||||
@@ -276,6 +276,7 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(InternalDiagnosticFactoryMethod::class)
|
||||||
private fun checkAnnotationsMatch(
|
private fun checkAnnotationsMatch(
|
||||||
expectSymbol: FirBasedSymbol<*>,
|
expectSymbol: FirBasedSymbol<*>,
|
||||||
actualSymbol: FirBasedSymbol<*>,
|
actualSymbol: FirBasedSymbol<*>,
|
||||||
@@ -286,12 +287,18 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
|||||||
val matchingContext = context.session.expectActualMatchingContextFactory.create(context.session, context.scopeSession)
|
val matchingContext = context.session.expectActualMatchingContextFactory.create(context.session, context.scopeSession)
|
||||||
val incompatibility =
|
val incompatibility =
|
||||||
AbstractExpectActualAnnotationMatchChecker.areAnnotationsCompatible(expectSymbol, actualSymbol, matchingContext) ?: return
|
AbstractExpectActualAnnotationMatchChecker.areAnnotationsCompatible(expectSymbol, actualSymbol, matchingContext) ?: return
|
||||||
reporter.reportOn(
|
val actualAnnotationTargetSourceElement = (incompatibility.actualAnnotationTargetElement as FirSourceElement).element
|
||||||
actualSymbol.source, FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT,
|
|
||||||
incompatibility.expectSymbol as FirBasedSymbol<*>,
|
reporter.report(
|
||||||
incompatibility.actualSymbol as FirBasedSymbol<*>,
|
FirErrors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT.on(
|
||||||
incompatibility.type.mapAnnotationType { it.annotationSymbol as FirAnnotation },
|
actualSymbol.source.requireNotNull(),
|
||||||
context
|
incompatibility.expectSymbol as FirBasedSymbol<*>,
|
||||||
|
incompatibility.actualSymbol as FirBasedSymbol<*>,
|
||||||
|
actualAnnotationTargetSourceElement,
|
||||||
|
incompatibility.type.mapAnnotationType { it.annotationSymbol as FirAnnotation },
|
||||||
|
positioningStrategy = null,
|
||||||
|
),
|
||||||
|
context,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -2005,10 +2005,11 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
|||||||
)
|
)
|
||||||
map.put(
|
map.put(
|
||||||
ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT,
|
ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT,
|
||||||
"{2}.\n" +
|
"{3}.\n" +
|
||||||
"All annotations from expect ''{0}'' must be present with the same arguments on actual ''{1}'', otherwise they might behave incorrectly.",
|
"All annotations from expect ''{0}'' must be present with the same arguments on actual ''{1}'', otherwise they might behave incorrectly.",
|
||||||
FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.SYMBOL_RENDERER,
|
FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.SYMBOL_RENDERER,
|
||||||
FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.SYMBOL_RENDERER,
|
FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.SYMBOL_RENDERER,
|
||||||
|
NOT_RENDERED,
|
||||||
FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.INCOMPATIBILITY,
|
FirExpectActualAnnotationIncompatibilityDiagnosticRenderers.INCOMPATIBILITY,
|
||||||
)
|
)
|
||||||
map.put(
|
map.put(
|
||||||
|
|||||||
+3
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.name.ClassId
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualCollectionArgumentsCompatibilityCheckStrategy
|
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualCollectionArgumentsCompatibilityCheckStrategy
|
||||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo
|
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo
|
||||||
|
import org.jetbrains.kotlin.mpp.SourceElementMarker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames
|
import org.jetbrains.kotlin.resolve.checkers.OptInNames
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
@@ -480,6 +481,8 @@ class FirExpectActualMatchingContextImpl private constructor(
|
|||||||
return mapping?.get(actualMember to expectClass) ?: emptyMap()
|
return mapping?.get(actualMember to expectClass) ?: emptyMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun DeclarationSymbolMarker.getSourceElement(): SourceElementMarker = FirSourceElement(asSymbol().source)
|
||||||
|
|
||||||
object Factory : FirExpectActualMatchingContextFactory {
|
object Factory : FirExpectActualMatchingContextFactory {
|
||||||
override fun create(
|
override fun create(
|
||||||
session: FirSession, scopeSession: ScopeSession,
|
session: FirSession, scopeSession: ScopeSession,
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.KtSourceElement
|
||||||
|
import org.jetbrains.kotlin.mpp.SourceElementMarker
|
||||||
|
|
||||||
|
class FirSourceElement(val element: KtSourceElement?) : SourceElementMarker
|
||||||
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.resolve.calls.tower.CandidateApplicability;
|
|||||||
import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier;
|
import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier;
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.BuilderLambdaLabelingInfo;
|
import org.jetbrains.kotlin.resolve.calls.util.BuilderLambdaLabelingInfo;
|
||||||
import org.jetbrains.kotlin.resolve.deprecation.DescriptorBasedDeprecationInfo;
|
import org.jetbrains.kotlin.resolve.deprecation.DescriptorBasedDeprecationInfo;
|
||||||
|
import org.jetbrains.kotlin.resolve.multiplatform.ClassicSourceElement;
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualAnnotationsIncompatibilityType;
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualAnnotationsIncompatibilityType;
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible;
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible;
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMemberDiff;
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualMemberDiff;
|
||||||
@@ -42,10 +43,7 @@ import org.jetbrains.kotlin.types.KotlinType;
|
|||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.diagnostics.ClassicPositioningStrategies.ACTUAL_DECLARATION_NAME;
|
import static org.jetbrains.kotlin.diagnostics.ClassicPositioningStrategies.ACTUAL_DECLARATION_NAME;
|
||||||
import static org.jetbrains.kotlin.diagnostics.ClassicPositioningStrategies.INCOMPATIBLE_DECLARATION;
|
import static org.jetbrains.kotlin.diagnostics.ClassicPositioningStrategies.INCOMPATIBLE_DECLARATION;
|
||||||
@@ -875,9 +873,9 @@ public interface Errors {
|
|||||||
DiagnosticFactory0<KtNamedDeclaration> EXPECT_ACTUAL_OPT_IN_ANNOTATION = DiagnosticFactory0.create(ERROR, EXPECT_ACTUAL_MODIFIER);
|
DiagnosticFactory0<KtNamedDeclaration> EXPECT_ACTUAL_OPT_IN_ANNOTATION = DiagnosticFactory0.create(ERROR, EXPECT_ACTUAL_MODIFIER);
|
||||||
DiagnosticFactory1<KtTypeAlias, ClassId> ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION =
|
DiagnosticFactory1<KtTypeAlias, ClassId> ACTUAL_TYPEALIAS_TO_SPECIAL_ANNOTATION =
|
||||||
DiagnosticFactory1.create(ERROR, TYPEALIAS_TYPE_REFERENCE);
|
DiagnosticFactory1.create(ERROR, TYPEALIAS_TYPE_REFERENCE);
|
||||||
DiagnosticFactory3<KtNamedDeclaration, DeclarationDescriptor, DeclarationDescriptor,
|
DiagnosticFactory4<KtNamedDeclaration, DeclarationDescriptor, DeclarationDescriptor, Optional<SourceElement>,
|
||||||
ExpectActualAnnotationsIncompatibilityType<AnnotationDescriptor>> ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT =
|
ExpectActualAnnotationsIncompatibilityType<AnnotationDescriptor>> ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT =
|
||||||
DiagnosticFactory3.create(WARNING, DECLARATION_NAME_ONLY);
|
DiagnosticFactory4.create(WARNING, DECLARATION_NAME_ONLY);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -444,10 +444,11 @@ public class DefaultErrorMessages {
|
|||||||
"`actual typealias` to annotation which affects code compilation can lead to incorrect behavior. Instead, use ''{0}'' annotation directly.",
|
"`actual typealias` to annotation which affects code compilation can lead to incorrect behavior. Instead, use ''{0}'' annotation directly.",
|
||||||
TO_STRING);
|
TO_STRING);
|
||||||
MAP.put(ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT,
|
MAP.put(ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT,
|
||||||
"{2}.\n" +
|
"{3}.\n" +
|
||||||
"All annotations from expect `{0}` must be present with the same arguments on actual `{1}`, otherwise they might behave incorrectly.",
|
"All annotations from expect `{0}` must be present with the same arguments on actual `{1}`, otherwise they might behave incorrectly.",
|
||||||
ExpectActualAnnotationIncompatibilityDiagnosticRenderers.DESCRIPTOR_RENDERER,
|
ExpectActualAnnotationIncompatibilityDiagnosticRenderers.DESCRIPTOR_RENDERER,
|
||||||
ExpectActualAnnotationIncompatibilityDiagnosticRenderers.DESCRIPTOR_RENDERER,
|
ExpectActualAnnotationIncompatibilityDiagnosticRenderers.DESCRIPTOR_RENDERER,
|
||||||
|
NOT_RENDERED,
|
||||||
ExpectActualAnnotationIncompatibilityDiagnosticRenderers.INCOMPATIBILITY);
|
ExpectActualAnnotationIncompatibilityDiagnosticRenderers.INCOMPATIBILITY);
|
||||||
|
|
||||||
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
|
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
|
||||||
|
|||||||
@@ -69,6 +69,9 @@ object Renderers {
|
|||||||
element.toString()
|
element.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
val NOT_RENDERED = Renderer<Any?> { _ -> "" }
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
val NAME = Renderer<Named> { it.name.asString() }
|
val NAME = Renderer<Named> { it.name.asString() }
|
||||||
|
|
||||||
|
|||||||
+3
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.resolve.source.KotlinSourceElement
|
|||||||
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
|
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
private val implicitlyActualizedAnnotationFqn = StandardClassIds.Annotations.ImplicitlyActualizedByJvmDeclaration.asSingleFqName()
|
private val implicitlyActualizedAnnotationFqn = StandardClassIds.Annotations.ImplicitlyActualizedByJvmDeclaration.asSingleFqName()
|
||||||
|
|
||||||
@@ -514,11 +515,13 @@ class ExpectedActualDeclarationChecker(
|
|||||||
val matchingContext = ClassicExpectActualMatchingContext(actualDescriptor.module)
|
val matchingContext = ClassicExpectActualMatchingContext(actualDescriptor.module)
|
||||||
val incompatibility =
|
val incompatibility =
|
||||||
AbstractExpectActualAnnotationMatchChecker.areAnnotationsCompatible(expectDescriptor, actualDescriptor, matchingContext) ?: return
|
AbstractExpectActualAnnotationMatchChecker.areAnnotationsCompatible(expectDescriptor, actualDescriptor, matchingContext) ?: return
|
||||||
|
val actualAnnotationTargetSourceElement = (incompatibility.actualAnnotationTargetElement as ClassicSourceElement).element
|
||||||
context.trace.report(
|
context.trace.report(
|
||||||
Errors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT.on(
|
Errors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT.on(
|
||||||
reportOn,
|
reportOn,
|
||||||
incompatibility.expectSymbol as DeclarationDescriptor,
|
incompatibility.expectSymbol as DeclarationDescriptor,
|
||||||
incompatibility.actualSymbol as DeclarationDescriptor,
|
incompatibility.actualSymbol as DeclarationDescriptor,
|
||||||
|
Optional.ofNullable(actualAnnotationTargetSourceElement),
|
||||||
incompatibility.type.mapAnnotationType { it.annotationSymbol as AnnotationDescriptor }
|
incompatibility.type.mapAnnotationType { it.annotationSymbol as AnnotationDescriptor }
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
+6
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualCollectionArgumentsCompatibilityCheckStrategy
|
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualCollectionArgumentsCompatibilityCheckStrategy
|
||||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
|
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo
|
import org.jetbrains.kotlin.resolve.calls.mpp.ExpectActualMatchingContext.AnnotationCallInfo
|
||||||
|
import org.jetbrains.kotlin.mpp.SourceElementMarker
|
||||||
import org.jetbrains.kotlin.resolve.checkers.OptInNames
|
import org.jetbrains.kotlin.resolve.checkers.OptInNames
|
||||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
@@ -523,4 +524,9 @@ internal abstract class IrExpectActualMatchingContext(
|
|||||||
actualMember: DeclarationSymbolMarker,
|
actualMember: DeclarationSymbolMarker,
|
||||||
checkClassScopesCompatibility: Boolean,
|
checkClassScopesCompatibility: Boolean,
|
||||||
): Map<out DeclarationSymbolMarker, ExpectActualCompatibility<*>> = error("Should not be called")
|
): Map<out DeclarationSymbolMarker, ExpectActualCompatibility<*>> = error("Should not be called")
|
||||||
|
|
||||||
|
// It's a stub, because not needed anywhere
|
||||||
|
private object IrSourceElementStub : SourceElementMarker
|
||||||
|
|
||||||
|
override fun DeclarationSymbolMarker.getSourceElement(): SourceElementMarker = IrSourceElementStub
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -38,6 +38,13 @@ object AbstractExpectActualAnnotationMatchChecker {
|
|||||||
*/
|
*/
|
||||||
val expectSymbol: DeclarationSymbolMarker,
|
val expectSymbol: DeclarationSymbolMarker,
|
||||||
val actualSymbol: DeclarationSymbolMarker,
|
val actualSymbol: DeclarationSymbolMarker,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link to source code element (possibly holding null, if no source) from actual declaration
|
||||||
|
* where mismatched actual annotation is set (or should be set if it is missing).
|
||||||
|
* Needed for the implementation of IDE intention.
|
||||||
|
*/
|
||||||
|
val actualAnnotationTargetElement: SourceElementMarker,
|
||||||
val type: IncompatibilityType<ExpectActualMatchingContext.AnnotationCallInfo>,
|
val type: IncompatibilityType<ExpectActualMatchingContext.AnnotationCallInfo>,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -122,7 +129,7 @@ object AbstractExpectActualAnnotationMatchChecker {
|
|||||||
return expectParams.zip(actualParams).firstNotNullOfOrNull { (expectParam, actualParam) ->
|
return expectParams.zip(actualParams).firstNotNullOfOrNull { (expectParam, actualParam) ->
|
||||||
areAnnotationsSetOnDeclarationsCompatible(expectParam, actualParam)?.let {
|
areAnnotationsSetOnDeclarationsCompatible(expectParam, actualParam)?.let {
|
||||||
// Write containing declarations into diagnostic
|
// Write containing declarations into diagnostic
|
||||||
Incompatibility(expectSymbol, actualSymbol, it.type)
|
Incompatibility(expectSymbol, actualSymbol, actualParam.getSourceElement(), it.type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,6 +157,7 @@ object AbstractExpectActualAnnotationMatchChecker {
|
|||||||
return Incompatibility(
|
return Incompatibility(
|
||||||
expectSymbol,
|
expectSymbol,
|
||||||
actualSymbol,
|
actualSymbol,
|
||||||
|
actualSymbol.getSourceElement(),
|
||||||
IncompatibilityType.MissingOnActual(expectAnnotation)
|
IncompatibilityType.MissingOnActual(expectAnnotation)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -163,7 +171,7 @@ object AbstractExpectActualAnnotationMatchChecker {
|
|||||||
// In the case of repeatable annotations, we can't choose on which to report
|
// In the case of repeatable annotations, we can't choose on which to report
|
||||||
IncompatibilityType.MissingOnActual(expectAnnotation)
|
IncompatibilityType.MissingOnActual(expectAnnotation)
|
||||||
}
|
}
|
||||||
return Incompatibility(expectSymbol, actualSymbol, incompatibilityType)
|
return Incompatibility(expectSymbol, actualSymbol, actualSymbol.getSourceElement(), incompatibilityType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|||||||
+2
@@ -213,4 +213,6 @@ interface ExpectActualMatchingContext<T : DeclarationSymbolMarker> : TypeSystemC
|
|||||||
actualMember: DeclarationSymbolMarker,
|
actualMember: DeclarationSymbolMarker,
|
||||||
checkClassScopesCompatibility: Boolean,
|
checkClassScopesCompatibility: Boolean,
|
||||||
): Map<out DeclarationSymbolMarker, ExpectActualCompatibility<*>>
|
): Map<out DeclarationSymbolMarker, ExpectActualCompatibility<*>>
|
||||||
|
|
||||||
|
fun DeclarationSymbolMarker.getSourceElement(): SourceElementMarker
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -442,4 +442,8 @@ class ClassicExpectActualMatchingContext(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun DeclarationSymbolMarker.getSourceElement(): SourceElementMarker {
|
||||||
|
return ClassicSourceElement((asDescriptor() as? DeclarationDescriptorWithSource)?.source)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+11
@@ -0,0 +1,11 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.multiplatform
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||||
|
import org.jetbrains.kotlin.mpp.SourceElementMarker
|
||||||
|
|
||||||
|
class ClassicSourceElement(val element: SourceElement?) : SourceElementMarker
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.mpp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common interface, which stores a link to a source element of declaration or type reference (or null, if no source).
|
||||||
|
* The idea is similar to [DeclarationSymbolMarker], but it doesn't fit, because
|
||||||
|
* sources of type references also must be supported, which are not declarations.
|
||||||
|
* Used in [org.jetbrains.kotlin.resolve.calls.mpp.AbstractExpectActualAnnotationMatchChecker].
|
||||||
|
*/
|
||||||
|
interface SourceElementMarker
|
||||||
Reference in New Issue
Block a user