mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[Kotlin] Fix quick fixes in IDE for annotations on actual after changes in compiler
Now checker supports annotations on type parameters, value parameters, getters. After the change actual PsiElement, where annotation must be added, is stored in `actualAnnotationTargetElement` field of diagnostic. Corresponding tests were added. ^KT-60671 ^KTIJ-26762 GitOrigin-RevId: 021ff6d8640a2a1cadab13943f699c03b5ff3347
This commit is contained in:
committed by
intellij-monorepo-bot
parent
8bafbe14c8
commit
b0c12d52e2
+1
@@ -41,6 +41,7 @@ internal object ActualAnnotationsNotMatchExpectFixFactory {
|
||||
expectDeclaration,
|
||||
actualDeclaration,
|
||||
expectAnnotationEntry,
|
||||
diagnostic.actualAnnotationTargetSourceElement,
|
||||
mappedIncompatibilityType,
|
||||
annotationClassIdProvider = { expectAnnotationEntry.getAnnotationClassId() }
|
||||
)
|
||||
|
||||
+15
@@ -139,6 +139,11 @@ public abstract class HighLevelQuickFixMultiModuleTestGenerated extends Abstract
|
||||
runTest("../idea/tests/testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualConstExpression/");
|
||||
}
|
||||
|
||||
@TestMetadata("copyToActualGetter")
|
||||
public void testCopyToActualGetter() throws Exception {
|
||||
runTest("../idea/tests/testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualGetter/");
|
||||
}
|
||||
|
||||
@TestMetadata("copyToActualNoArg")
|
||||
public void testCopyToActualNoArg() throws Exception {
|
||||
runTest("../idea/tests/testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualNoArg/");
|
||||
@@ -159,6 +164,16 @@ public abstract class HighLevelQuickFixMultiModuleTestGenerated extends Abstract
|
||||
runTest("../idea/tests/testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualSingleArg/");
|
||||
}
|
||||
|
||||
@TestMetadata("copyToActualTypeParameter")
|
||||
public void testCopyToActualTypeParameter() throws Exception {
|
||||
runTest("../idea/tests/testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualTypeParameter/");
|
||||
}
|
||||
|
||||
@TestMetadata("copyToActualValueParameter")
|
||||
public void testCopyToActualValueParameter() throws Exception {
|
||||
runTest("../idea/tests/testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualValueParameter/");
|
||||
}
|
||||
|
||||
@TestMetadata("copyToActualWithImport")
|
||||
public void testCopyToActualWithImport() throws Exception {
|
||||
runTest("../idea/tests/testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualWithImport/");
|
||||
|
||||
+9
-7
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.base.psi.callableIdIfNotLocal
|
||||
import org.jetbrains.kotlin.idea.base.psi.classIdIfNonLocal
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
@@ -8,10 +9,7 @@ import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.KotlinQuickF
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.QuickFixActionBase
|
||||
import org.jetbrains.kotlin.idea.inspections.RemoveAnnotationFix
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualAnnotationsIncompatibilityType
|
||||
|
||||
object ActualAnnotationsNotMatchExpectFixFactoryCommon {
|
||||
@@ -27,6 +25,7 @@ object ActualAnnotationsNotMatchExpectFixFactoryCommon {
|
||||
expectDeclaration: KtNamedDeclaration,
|
||||
actualDeclaration: KtNamedDeclaration,
|
||||
expectAnnotationEntry: KtAnnotationEntry,
|
||||
actualAnnotationTargetElement: PsiElement?,
|
||||
incompatibilityType: ExpectActualAnnotationsIncompatibilityType<KtAnnotationEntry?>,
|
||||
annotationClassIdProvider: () -> ClassId?,
|
||||
): List<KotlinQuickFixAction<*>> {
|
||||
@@ -40,7 +39,7 @@ object ActualAnnotationsNotMatchExpectFixFactoryCommon {
|
||||
}
|
||||
|
||||
if (actualAnnotationEntry == null) {
|
||||
val copyFromExpect = createCopyFromExpectToActualFix(expectAnnotationEntry, actualDeclaration, annotationClassIdProvider)
|
||||
val copyFromExpect = createCopyFromExpectToActualFix(expectAnnotationEntry, actualAnnotationTargetElement, annotationClassIdProvider)
|
||||
return listOfNotNull(copyFromExpect)
|
||||
}
|
||||
|
||||
@@ -59,12 +58,15 @@ object ActualAnnotationsNotMatchExpectFixFactoryCommon {
|
||||
}
|
||||
|
||||
private fun createCopyFromExpectToActualFix(
|
||||
expectAnnotationEntry: KtAnnotationEntry, actualDeclaration: KtNamedDeclaration, annotationClassIdProvider: () -> ClassId?
|
||||
expectAnnotationEntry: KtAnnotationEntry, actualAnnotationTargetElement: PsiElement?, annotationClassIdProvider: () -> ClassId?
|
||||
): KotlinQuickFixAction<*>? {
|
||||
if (actualAnnotationTargetElement !is KtModifierListOwner) {
|
||||
return null
|
||||
}
|
||||
val annotationClassId = annotationClassIdProvider.invoke() ?: return null
|
||||
|
||||
return CopyAnnotationFromExpectToActualFix(
|
||||
actualDeclaration,
|
||||
actualAnnotationTargetElement,
|
||||
expectAnnotationEntry,
|
||||
annotationClassId,
|
||||
)
|
||||
|
||||
+5
-5
@@ -10,13 +10,13 @@ import org.jetbrains.kotlin.idea.util.addAnnotation
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtModifierListOwner
|
||||
|
||||
internal class CopyAnnotationFromExpectToActualFix(
|
||||
actualDeclaration: KtNamedDeclaration,
|
||||
actualElement: KtModifierListOwner,
|
||||
@SafeFieldForPreview private val expectAnnotationEntry: KtAnnotationEntry,
|
||||
@SafeFieldForPreview private val annotationClassId: ClassId,
|
||||
) : KotlinQuickFixAction<KtNamedDeclaration>(actualDeclaration) {
|
||||
) : KotlinQuickFixAction<KtModifierListOwner>(actualElement) {
|
||||
|
||||
private val expectAnnotationShortName: String = expectAnnotationEntry.shortName?.toString() ?: "<unknown>"
|
||||
|
||||
@@ -27,9 +27,9 @@ internal class CopyAnnotationFromExpectToActualFix(
|
||||
override fun getFamilyName(): String = text
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val actualDeclaration = element ?: return
|
||||
val actualElement = element ?: return
|
||||
val innerText = expectAnnotationEntry.valueArguments.joinToString { it.asElement().text }
|
||||
actualDeclaration.addAnnotation(annotationClassId, innerText.takeIf { it.isNotEmpty() }, searchForExistingEntry = false)
|
||||
actualElement.addAnnotation(annotationClassId, innerText.takeIf { it.isNotEmpty() }, searchForExistingEntry = false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -6,6 +6,7 @@ import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.calls.singleConstructorCallOrNull
|
||||
import org.jetbrains.kotlin.analysis.api.calls.symbol
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
|
||||
@@ -19,11 +20,12 @@ import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtNamedDeclaration
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualAnnotationsIncompatibilityType
|
||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||
import java.util.*
|
||||
|
||||
internal object ActualAnnotationsNotMatchExpectFixFactory : KotlinIntentionActionsFactory() {
|
||||
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
|
||||
val castedDiagnostic = DiagnosticFactory.cast(diagnostic, Errors.ACTUAL_ANNOTATIONS_NOT_MATCH_EXPECT)
|
||||
val incompatibilityType = castedDiagnostic.c
|
||||
val incompatibilityType = castedDiagnostic.d
|
||||
|
||||
val expectAnnotationEntry = incompatibilityType.expectAnnotation.source.getPsi() as? KtAnnotationEntry
|
||||
?: return emptyList()
|
||||
@@ -32,13 +34,15 @@ internal object ActualAnnotationsNotMatchExpectFixFactory : KotlinIntentionActio
|
||||
ActualAnnotationsNotMatchExpectFixFactoryCommon.createRemoveAnnotationFromExpectFix(expectAnnotationEntry)
|
||||
|
||||
return listOfNotNull(removeAnnotationFix) +
|
||||
createCopyAndReplaceAnnotationFixes(expectAnnotationEntry, castedDiagnostic.a, castedDiagnostic.b, incompatibilityType)
|
||||
createCopyAndReplaceAnnotationFixes(expectAnnotationEntry, castedDiagnostic.a, castedDiagnostic.b,
|
||||
castedDiagnostic.c, incompatibilityType)
|
||||
}
|
||||
|
||||
private fun createCopyAndReplaceAnnotationFixes(
|
||||
expectAnnotationEntry: KtAnnotationEntry,
|
||||
expectDeclarationDescriptor: DeclarationDescriptor,
|
||||
actualDeclarationDescriptor: DeclarationDescriptor,
|
||||
actualAnnotationTargetSourceElement: Optional<SourceElement>,
|
||||
incompatibilityType: ExpectActualAnnotationsIncompatibilityType<AnnotationDescriptor>,
|
||||
): List<QuickFixActionBase<*>> {
|
||||
val expectDeclaration = expectDeclarationDescriptor.toSourceElement.getPsi() as? KtNamedDeclaration ?: return emptyList()
|
||||
@@ -51,6 +55,7 @@ internal object ActualAnnotationsNotMatchExpectFixFactory : KotlinIntentionActio
|
||||
expectDeclaration,
|
||||
actualDeclaration,
|
||||
expectAnnotationEntry,
|
||||
actualAnnotationTargetSourceElement.orElse(null)?.getPsi(),
|
||||
mappedIncompatibilityType,
|
||||
annotationClassIdProvider = { getAnnotationClassId(expectAnnotationEntry) }
|
||||
)
|
||||
|
||||
+15
@@ -139,6 +139,11 @@ public abstract class QuickFixMultiModuleTestGenerated extends AbstractQuickFixM
|
||||
runTest("testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualConstExpression/");
|
||||
}
|
||||
|
||||
@TestMetadata("copyToActualGetter")
|
||||
public void testCopyToActualGetter() throws Exception {
|
||||
runTest("testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualGetter/");
|
||||
}
|
||||
|
||||
@TestMetadata("copyToActualNoArg")
|
||||
public void testCopyToActualNoArg() throws Exception {
|
||||
runTest("testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualNoArg/");
|
||||
@@ -159,6 +164,16 @@ public abstract class QuickFixMultiModuleTestGenerated extends AbstractQuickFixM
|
||||
runTest("testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualSingleArg/");
|
||||
}
|
||||
|
||||
@TestMetadata("copyToActualTypeParameter")
|
||||
public void testCopyToActualTypeParameter() throws Exception {
|
||||
runTest("testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualTypeParameter/");
|
||||
}
|
||||
|
||||
@TestMetadata("copyToActualValueParameter")
|
||||
public void testCopyToActualValueParameter() throws Exception {
|
||||
runTest("testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualValueParameter/");
|
||||
}
|
||||
|
||||
@TestMetadata("copyToActualWithImport")
|
||||
public void testCopyToActualWithImport() throws Exception {
|
||||
runTest("testData/multiModuleQuickFix/actualAnnotationsNotMatchExpect/copyToActualWithImport/");
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// DISABLE-ERRORS
|
||||
@Target(AnnotationTarget.PROPERTY_GETTER)
|
||||
annotation class Ann
|
||||
|
||||
expect val foo: Any?
|
||||
@Ann get
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
MODULE common { platform=[JVM, JS, Native]; root=common }
|
||||
MODULE jvm { platform=[JVM]; root=jvm }
|
||||
|
||||
common -> STDLIB_COMMON { kind=DEPENDENCY }
|
||||
jvm -> common { kind=DEPENDS_ON }
|
||||
jvm -> STDLIB_JVM { kind=DEPENDENCY }
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Copy mismatched annotation 'Ann' from expect to actual declaration (may change semantics)" "true"
|
||||
// DISABLE-ERRORS
|
||||
// FIR_COMPARISON
|
||||
|
||||
actual val foo<caret>: Any?
|
||||
get() = null
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Copy mismatched annotation 'Ann' from expect to actual declaration (may change semantics)" "true"
|
||||
// DISABLE-ERRORS
|
||||
// FIR_COMPARISON
|
||||
|
||||
actual val foo: Any?
|
||||
@Ann
|
||||
get() = null
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// DISABLE-ERRORS
|
||||
@Target(AnnotationTarget.TYPE_PARAMETER)
|
||||
annotation class Ann
|
||||
|
||||
expect fun <@Ann T> foo()
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
MODULE common { platform=[JVM, JS, Native]; root=common }
|
||||
MODULE jvm { platform=[JVM]; root=jvm }
|
||||
|
||||
common -> STDLIB_COMMON { kind=DEPENDENCY }
|
||||
jvm -> common { kind=DEPENDS_ON }
|
||||
jvm -> STDLIB_JVM { kind=DEPENDENCY }
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Copy mismatched annotation 'Ann' from expect to actual declaration (may change semantics)" "true"
|
||||
// DISABLE-ERRORS
|
||||
// FIR_COMPARISON
|
||||
|
||||
actual fun <T> foo<caret>() {}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Copy mismatched annotation 'Ann' from expect to actual declaration (may change semantics)" "true"
|
||||
// DISABLE-ERRORS
|
||||
// FIR_COMPARISON
|
||||
|
||||
actual fun <@Ann T> foo() {}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// DISABLE-ERRORS
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
annotation class Ann
|
||||
|
||||
expect fun foo(@Ann p: Any)
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
MODULE common { platform=[JVM, JS, Native]; root=common }
|
||||
MODULE jvm { platform=[JVM]; root=jvm }
|
||||
|
||||
common -> STDLIB_COMMON { kind=DEPENDENCY }
|
||||
jvm -> common { kind=DEPENDS_ON }
|
||||
jvm -> STDLIB_JVM { kind=DEPENDENCY }
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Copy mismatched annotation 'Ann' from expect to actual declaration (may change semantics)" "true"
|
||||
// DISABLE-ERRORS
|
||||
// FIR_COMPARISON
|
||||
|
||||
actual fun foo<caret>(p: Any) {}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Copy mismatched annotation 'Ann' from expect to actual declaration (may change semantics)" "true"
|
||||
// DISABLE-ERRORS
|
||||
// FIR_COMPARISON
|
||||
|
||||
actual fun foo(@Ann p: Any) {}
|
||||
Reference in New Issue
Block a user