From 9b0f15137f90620a0bbbc71c99ab1fc3f8fcc4ee Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Mon, 18 Sep 2017 11:29:28 +0300 Subject: [PATCH] Expect/actual: introduce DEPRECATED_MODIFIER instead of ..._FOR_TARGET --- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../kotlin/resolve/ModifiersChecker.kt | 21 ++++++++++------- .../tests/multiplatform/deprecated/header.kt | 20 ++++++++-------- .../tests/multiplatform/incompatibles.kt | 10 ++++---- .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 2 +- .../idea/quickfix/ReplaceModifierFix.kt | 23 +++++-------------- 7 files changed, 37 insertions(+), 41 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index afb08e2ee47..a00a3080871 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -199,6 +199,7 @@ public interface Errors { DiagnosticFactory2 REDUNDANT_MODIFIER = DiagnosticFactory2.create(WARNING); DiagnosticFactory2 WRONG_MODIFIER_TARGET = DiagnosticFactory2.create(ERROR); DiagnosticFactory2 DEPRECATED_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING); + DiagnosticFactory2 DEPRECATED_MODIFIER = DiagnosticFactory2.create(WARNING); DiagnosticFactory2 REDUNDANT_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING); DiagnosticFactory2 WRONG_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(ERROR); DiagnosticFactory2 DEPRECATED_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(WARNING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index bc7955fd995..8895bd3b90b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -142,6 +142,7 @@ public class DefaultErrorMessages { MAP.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING); MAP.put(WRONG_MODIFIER_TARGET, "Modifier ''{0}'' is not applicable to ''{1}''", TO_STRING, TO_STRING); MAP.put(DEPRECATED_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is deprecated for ''{1}''", TO_STRING, TO_STRING); + MAP.put(DEPRECATED_MODIFIER, "Modifier ''{0}'' is deprecated, use ''{1}'' instead", TO_STRING, TO_STRING); MAP.put(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", TO_STRING, TO_STRING); MAP.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", TO_STRING, TO_STRING); MAP.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", TO_STRING, TO_STRING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt index 574f7efa1ff..639d0f03018 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.kt @@ -109,9 +109,11 @@ object ModifierCheckerCore { ) // NOTE: deprecated targets must be possible! - private val deprecatedTargetMap = mapOf>( - HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS), - IMPL_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, MEMBER_FUNCTION, TOP_LEVEL_PROPERTY, MEMBER_PROPERTY, CONSTRUCTOR, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS, TYPEALIAS) + private val deprecatedTargetMap = mapOf>() + + private val deprecatedModifierMap = mapOf( + HEADER_KEYWORD to EXPECT_KEYWORD, + IMPL_KEYWORD to ACTUAL_KEYWORD ) // NOTE: redundant targets must be possible! @@ -279,13 +281,16 @@ object ModifierCheckerCore { trace.report(Errors.WRONG_MODIFIER_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this")) return false } + val deprecatedModifierReplacement = deprecatedModifierMap[modifier] val deprecatedTargets = deprecatedTargetMap[modifier] ?: emptySet() val redundantTargets = redundantTargetMap[modifier] ?: emptySet() - if (actualTargets.any { it in deprecatedTargets }) { - trace.report(Errors.DEPRECATED_MODIFIER_FOR_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this")) - } - else if (actualTargets.any { it in redundantTargets }) { - trace.report(Errors.REDUNDANT_MODIFIER_FOR_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this")) + when { + deprecatedModifierReplacement != null -> + trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement)) + actualTargets.any { it in deprecatedTargets } -> + trace.report(Errors.DEPRECATED_MODIFIER_FOR_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this")) + actualTargets.any { it in redundantTargets } -> + trace.report(Errors.REDUNDANT_MODIFIER_FOR_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this")) } return true } diff --git a/compiler/testData/diagnostics/tests/multiplatform/deprecated/header.kt b/compiler/testData/diagnostics/tests/multiplatform/deprecated/header.kt index 11d171efb86..98560e4c320 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/deprecated/header.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/deprecated/header.kt @@ -2,29 +2,29 @@ // MODULE: m1-common // FILE: common.kt -header class My +header class My -header fun foo(): Int +header fun foo(): Int -header val x: String +header val x: String -header object O +header object O -header enum class E { +header enum class E { FIRST } // MODULE: m2-jvm(m1-common) // FILE: jvm.kt -impl class My +impl class My -impl fun foo() = 42 +impl fun foo() = 42 -impl val x get() = "Hello" +impl val x get() = "Hello" -impl object O +impl object O -impl enum class E { +impl enum class E { FIRST } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/multiplatform/incompatibles.kt b/compiler/testData/diagnostics/tests/multiplatform/incompatibles.kt index 92abdfa6363..91bab1b0acc 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/incompatibles.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/incompatibles.kt @@ -1,13 +1,13 @@ // !LANGUAGE: +MultiPlatformProjects -header impl class First +header impl class First -header expect class Second +header expect class Second -header actual class Third +header actual class Third -impl expect class Fourth +impl expect class Fourth -impl actual class Fifth +impl actual class Fifth expect actual class Sixth \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 22d155675b7..37e50c29920 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -130,7 +130,7 @@ class QuickFixRegistrar : QuickFixContributor { removeModifierFactory) REDUNDANT_MODIFIER_IN_GETTER.registerFactory(removeRedundantModifierFactory) WRONG_MODIFIER_TARGET.registerFactory(removeModifierFactory) - DEPRECATED_MODIFIER_FOR_TARGET.registerFactory(ReplaceModifierFix) + DEPRECATED_MODIFIER.registerFactory(ReplaceModifierFix) REDUNDANT_MODIFIER_FOR_TARGET.registerFactory(removeModifierFactory) WRONG_MODIFIER_CONTAINING_DECLARATION.registerFactory(removeModifierFactory) REPEATED_MODIFIER.registerFactory(removeModifierFactory) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceModifierFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceModifierFix.kt index 5a271096f06..d9b77698eda 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceModifierFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ReplaceModifierFix.kt @@ -29,38 +29,27 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType class ReplaceModifierFix( element: KtModifierListOwner, - private val modifier: KtModifierKeywordToken + private val replacement: KtModifierKeywordToken ) : KotlinQuickFixAction(element), CleanupFix { - private val text = when (modifier) { - KtTokens.HEADER_KEYWORD -> "Replace with 'expect'" - KtTokens.IMPL_KEYWORD -> "Replace with 'actual'" - else -> "Replace modifier (?)" - } + private val text = "Replace with '${replacement.value}'" override fun getText() = text override fun getFamilyName() = "Replace modifier" override fun invoke(project: Project, editor: Editor?, file: KtFile) { - val element = element ?: return - when (modifier) { - KtTokens.HEADER_KEYWORD -> { - element.addModifier(KtTokens.EXPECT_KEYWORD) - } - KtTokens.IMPL_KEYWORD -> { - element.addModifier(KtTokens.ACTUAL_KEYWORD) - } - } + element?.addModifier(replacement) } companion object : KotlinSingleIntentionActionFactory() { override fun createAction(diagnostic: Diagnostic): IntentionAction? { - val deprecatedModifier = Errors.DEPRECATED_MODIFIER_FOR_TARGET.cast(diagnostic) + val deprecatedModifier = Errors.DEPRECATED_MODIFIER.cast(diagnostic) val modifier = deprecatedModifier.a + val replacement = deprecatedModifier.b val modifierListOwner = deprecatedModifier.psiElement.getParentOfType(strict = true) ?: return null return when (modifier) { - KtTokens.HEADER_KEYWORD, KtTokens.IMPL_KEYWORD -> ReplaceModifierFix(modifierListOwner, modifier) + KtTokens.HEADER_KEYWORD, KtTokens.IMPL_KEYWORD -> ReplaceModifierFix(modifierListOwner, replacement) else -> null } }