mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[kotlin] Ported ReplaceJvmFieldWithConstFix to K2
Also fixed not taking into account nullable types in MayBeConstantInspection to align with the behavior of the quick-fix. ^KTIJ-29535 fixed GitOrigin-RevId: 5a97bc73b328ef1e3cd840d9f96ba0299c8acc57
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3dafa1eaf2
commit
0e7e9fba23
+2
@@ -440,6 +440,8 @@ class KotlinK2QuickFixRegistrar : KotlinQuickFixRegistrar() {
|
||||
registerFactory(DeprecationFixFactory.deprecatedAliasWarning)
|
||||
|
||||
registerFactory(ChangeMemberFunctionSignatureFixFactory.nothingToOverrideFixFactory)
|
||||
|
||||
registerFactory(ReplaceJvmFieldWithConstFixFactory.inapplicableJvmField)
|
||||
}
|
||||
|
||||
private val optIn = KtQuickFixesListBuilder.registerPsiQuickFix {
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.kotlin.idea.k2.codeinsight.fixes
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.KaSession
|
||||
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KaFirDiagnostic
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.applicators.fixes.KotlinQuickFixFactory
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.checkMayBeConstantByFields
|
||||
import org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
|
||||
object ReplaceJvmFieldWithConstFixFactory {
|
||||
private fun KaSession.createQuickFix(annotation: KtAnnotationEntry): ReplaceJvmFieldWithConstFix? {
|
||||
val property = annotation.getParentOfType<KtProperty>(false) ?: return null
|
||||
val initializer = property.initializer ?: return null
|
||||
if (!property.checkMayBeConstantByFields()) return null
|
||||
|
||||
val returnType = property.returnType
|
||||
if (returnType.isMarkedNullable) return null
|
||||
if (!returnType.isPrimitive && !returnType.isStringType) return null
|
||||
|
||||
if (initializer.evaluate() == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return ReplaceJvmFieldWithConstFix(annotation)
|
||||
}
|
||||
|
||||
val inapplicableJvmField = KotlinQuickFixFactory.ModCommandBased { diagnostic: KaFirDiagnostic.InapplicableJvmField ->
|
||||
listOfNotNull(createQuickFix(diagnostic.psi))
|
||||
}
|
||||
}
|
||||
+57
@@ -10046,7 +10046,64 @@ public abstract class HighLevelQuickFixTestGenerated extends AbstractHighLevelQu
|
||||
}
|
||||
}
|
||||
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
@TestMetadata("../../../idea/tests/testData/quickfix/replaceJvmFieldWithConst")
|
||||
public static class ReplaceJvmFieldWithConst extends AbstractHighLevelQuickFixTest {
|
||||
@java.lang.Override
|
||||
@org.jetbrains.annotations.NotNull
|
||||
public final KotlinPluginMode getPluginMode() {
|
||||
return KotlinPluginMode.K2;
|
||||
}
|
||||
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
@TestMetadata("class.kt")
|
||||
public void testClass() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/replaceJvmFieldWithConst/class.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("companionInInterface.kt")
|
||||
public void testCompanionInInterface() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/replaceJvmFieldWithConst/companionInInterface.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("getter.kt")
|
||||
public void testGetter() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/replaceJvmFieldWithConst/getter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nonConstantInitializer.kt")
|
||||
public void testNonConstantInitializer() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/replaceJvmFieldWithConst/nonConstantInitializer.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nullable.kt")
|
||||
public void testNullable() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/replaceJvmFieldWithConst/nullable.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("object.kt")
|
||||
public void testObject() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/replaceJvmFieldWithConst/object.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("stringTemplateWithConstants.kt")
|
||||
public void testStringTemplateWithConstants() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/replaceJvmFieldWithConst/stringTemplateWithConstants.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("stringTemplateWithVal.kt")
|
||||
public void testStringTemplateWithVal() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/replaceJvmFieldWithConst/stringTemplateWithVal.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("toplevel.kt")
|
||||
public void testToplevel() throws Exception {
|
||||
runTest("../../../idea/tests/testData/quickfix/replaceJvmFieldWithConst/toplevel.kt");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
+4
-5
@@ -11,19 +11,17 @@ import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.base.KaConstantValue
|
||||
import org.jetbrains.kotlin.analysis.api.components.KaDiagnosticCheckerFilter
|
||||
import org.jetbrains.kotlin.analysis.api.fir.diagnostics.KaFirDiagnostic
|
||||
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.CleanupFix
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.*
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.inspections.MayBeConstantInspectionBase
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.checkMayBeConstantByFields
|
||||
import org.jetbrains.kotlin.idea.codeinsight.utils.replaceReferencesToGetterByReferenceToField
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.inspections.MayBeConstantInspectionBase
|
||||
import org.jetbrains.kotlin.idea.codeinsights.impl.base.inspections.matchStatus
|
||||
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteActionIfPhysical
|
||||
import org.jetbrains.kotlin.idea.util.findAnnotation
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
@@ -38,7 +36,7 @@ class MayBeConstantInspection : MayBeConstantInspectionBase() {
|
||||
|
||||
val initializer = initializer
|
||||
analyze(this) {
|
||||
if (!hasPrimitiveOrStringType()) return Status.NONE
|
||||
if (!hasNonNullablePrimitiveOrStringType()) return Status.NONE
|
||||
}
|
||||
|
||||
val withJvmField = findAnnotation(ClassId.fromString(JVM_FIELD_CLASS_ID)) != null
|
||||
@@ -60,8 +58,9 @@ class MayBeConstantInspection : MayBeConstantInspectionBase() {
|
||||
}
|
||||
|
||||
context(KaSession)
|
||||
private fun KtProperty.hasPrimitiveOrStringType(): Boolean {
|
||||
private fun KtProperty.hasNonNullablePrimitiveOrStringType(): Boolean {
|
||||
val type = this.returnType
|
||||
if (type.isMarkedNullable) return false
|
||||
return type.isPrimitive || type.isStringType
|
||||
}
|
||||
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// Copyright 2000-2024 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.modcommand.ActionContext
|
||||
import com.intellij.modcommand.ModPsiUpdater
|
||||
import com.intellij.modcommand.PsiUpdateModCommandAction
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
|
||||
class ReplaceJvmFieldWithConstFix(annotation: KtAnnotationEntry) : PsiUpdateModCommandAction<KtAnnotationEntry>(annotation) {
|
||||
override fun getFamilyName(): String = KotlinBundle.message("replace.jvmfield.with.const")
|
||||
|
||||
override fun invoke(
|
||||
context: ActionContext,
|
||||
element: KtAnnotationEntry,
|
||||
updater: ModPsiUpdater
|
||||
) {
|
||||
val property = element.getParentOfType<KtProperty>(false) ?: return
|
||||
element.delete()
|
||||
property.addModifier(KtTokens.CONST_KEYWORD)
|
||||
}
|
||||
}
|
||||
@@ -645,7 +645,7 @@ class QuickFixRegistrar : QuickFixContributor {
|
||||
|
||||
ILLEGAL_INLINE_PARAMETER_MODIFIER.registerFactory(AddInlineToFunctionFix)
|
||||
|
||||
INAPPLICABLE_JVM_FIELD.registerFactory(ReplaceJvmFieldWithConstFix, RemoveAnnotationFix.JvmField)
|
||||
INAPPLICABLE_JVM_FIELD.registerFactory(ReplaceJvmFieldWithConstFixFactory, RemoveAnnotationFix.JvmField)
|
||||
|
||||
CONFLICTING_OVERLOADS.registerFactory(ChangeSuspendInHierarchyFix)
|
||||
|
||||
|
||||
-56
@@ -1,56 +0,0 @@
|
||||
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix
|
||||
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.base.resources.KotlinBundle
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.codeinsight.api.classic.quickfixes.KotlinQuickFixAction
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.resolve.checkers.ConstModifierChecker
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
|
||||
class ReplaceJvmFieldWithConstFix(annotation: KtAnnotationEntry) : KotlinQuickFixAction<KtAnnotationEntry>(annotation) {
|
||||
override fun getText(): String = KotlinBundle.message("replace.jvmfield.with.const")
|
||||
|
||||
override fun getFamilyName(): String = text
|
||||
|
||||
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
|
||||
val property = element?.getParentOfType<KtProperty>(false) ?: return
|
||||
element?.delete()
|
||||
property.addModifier(KtTokens.CONST_KEYWORD)
|
||||
}
|
||||
|
||||
companion object : KotlinSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val annotation = diagnostic.psiElement as? KtAnnotationEntry ?: return null
|
||||
val property = annotation.getParentOfType<KtProperty>(false) ?: return null
|
||||
val propertyDescriptor = property.descriptor as? PropertyDescriptor ?: return null
|
||||
if (!ConstModifierChecker.canBeConst(property, property, propertyDescriptor)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val initializer = property.initializer ?: return null
|
||||
if (!initializer.isConstantExpression()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return ReplaceJvmFieldWithConstFix(annotation)
|
||||
}
|
||||
|
||||
private fun KtExpression.isConstantExpression() =
|
||||
ConstantExpressionEvaluator.getConstant(this, analyze(BodyResolveMode.PARTIAL))?.let { !it.usesNonConstValAsConstant } ?: false
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
// Copyright 2000-2024 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.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
|
||||
import org.jetbrains.kotlin.resolve.checkers.ConstModifierChecker
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
|
||||
internal object ReplaceJvmFieldWithConstFixFactory : KotlinSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val annotation = diagnostic.psiElement as? KtAnnotationEntry ?: return null
|
||||
val property = annotation.getParentOfType<KtProperty>(false) ?: return null
|
||||
val propertyDescriptor = property.descriptor as? PropertyDescriptor ?: return null
|
||||
if (!ConstModifierChecker.canBeConst(property, property, propertyDescriptor)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val initializer = property.initializer ?: return null
|
||||
if (!initializer.isConstantExpression()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return ReplaceJvmFieldWithConstFix(annotation).asIntention()
|
||||
}
|
||||
|
||||
private fun KtExpression.isConstantExpression() =
|
||||
ConstantExpressionEvaluator.getConstant(this, analyze(BodyResolveMode.PARTIAL))?.let { !it.usesNonConstValAsConstant } ?: false
|
||||
}
|
||||
+2
-1
@@ -6,4 +6,5 @@ interface IFace {
|
||||
<caret>@JvmField val a = "Lorem ipsum"
|
||||
}
|
||||
}
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
+2
-1
@@ -6,4 +6,5 @@ interface IFace {
|
||||
const val a = "Lorem ipsum"
|
||||
}
|
||||
}
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
@@ -4,4 +4,5 @@ object Foo {
|
||||
<caret>@JvmField private val a = "Lorem ipsum"
|
||||
}
|
||||
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
+2
-1
@@ -4,4 +4,5 @@ object Foo {
|
||||
private const val a = "Lorem ipsum"
|
||||
}
|
||||
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
+2
-1
@@ -2,4 +2,5 @@
|
||||
// WITH_STDLIB
|
||||
const val three = 3
|
||||
<caret>@JvmField private val text = "${2 + three}"
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
+2
-1
@@ -2,4 +2,5 @@
|
||||
// WITH_STDLIB
|
||||
const val three = 3
|
||||
private const val text = "${2 + three}"
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
@@ -1,4 +1,5 @@
|
||||
// "Replace '@JvmField' with 'const'" "true"
|
||||
// WITH_STDLIB
|
||||
<caret>@JvmField private val number: Int = 42
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
+2
-1
@@ -1,4 +1,5 @@
|
||||
// "Replace '@JvmField' with 'const'" "true"
|
||||
// WITH_STDLIB
|
||||
private const val number: Int = 42
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
// FUS_K2_QUICKFIX_NAME: org.jetbrains.kotlin.idea.quickfix.ReplaceJvmFieldWithConstFix
|
||||
+1
-1
@@ -179,7 +179,7 @@ internal fun MutableTWorkspace.generateK2FixTests() {
|
||||
model("$idea/quickfix/renameToUnderscore", pattern = pattern, isIgnored = true)
|
||||
model("$idea/quickfix/renameUnresolvedReference", pattern = pattern, isIgnored = true)
|
||||
model("$idea/quickfix/reorderParameters", pattern = pattern)
|
||||
model("$idea/quickfix/replaceJvmFieldWithConst", pattern = pattern, isIgnored = true)
|
||||
model("$idea/quickfix/replaceJvmFieldWithConst", pattern = pattern)
|
||||
model("$idea/quickfix/restrictedRetentionForExpressionAnnotation", pattern = pattern, isIgnored = true)
|
||||
model("$idea/quickfix/simplifyComparison", pattern = pattern)
|
||||
model("$idea/quickfix/smartCastImpossibleInIfThen", pattern = pattern, isIgnored = true)
|
||||
|
||||
Reference in New Issue
Block a user