From a497dd1d31d7643fde7248b3d32bbb312015ef2a Mon Sep 17 00:00:00 2001 From: Mark Punzalan Date: Wed, 9 Jun 2021 08:36:54 +0000 Subject: [PATCH] FIR IDE: Enable add accessor intentions in plugin. --- .../generators/tests/idea/GenerateTests.kt | 1 + .../fir/intentions/HLAddAccessorIntentions.kt | 79 +++ .../intentions/HLIntentionTestGenerated.java | 547 +++++++++++++----- .../idea/api/applicator/HLApplicatorInput.kt | 2 + .../AbstractAddAccessorsIntention.kt | 65 ++- idea/resources-fir/META-INF/firIntentions.xml | 15 + .../addPropertyAccessors/both/.firIntention | 1 + .../addPropertyAccessors/both/expect.kt | 6 + .../addPropertyAccessors/getter/.firIntention | 1 + .../addPropertyAccessors/getter/const.kt | 4 + .../getter/{header.kt => expect.kt} | 0 .../addPropertyAccessors/setter/.firIntention | 1 + .../addPropertyAccessors/setter/expect.kt | 6 + .../addPropertyAccessors/varHasGetter.kt | 3 +- .../varHasGetter.kt.after | 3 +- .../addPropertyAccessors/varHasSetter.kt | 3 +- .../varHasSetter.kt.after | 3 +- .../intentions/IntentionTestGenerated.java | 25 +- 18 files changed, 576 insertions(+), 189 deletions(-) create mode 100644 idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/intentions/HLAddAccessorIntentions.kt create mode 100644 idea/testData/intentions/addPropertyAccessors/both/.firIntention create mode 100644 idea/testData/intentions/addPropertyAccessors/both/expect.kt create mode 100644 idea/testData/intentions/addPropertyAccessors/getter/.firIntention create mode 100644 idea/testData/intentions/addPropertyAccessors/getter/const.kt rename idea/testData/intentions/addPropertyAccessors/getter/{header.kt => expect.kt} (100%) create mode 100644 idea/testData/intentions/addPropertyAccessors/setter/.firIntention create mode 100644 idea/testData/intentions/addPropertyAccessors/setter/expect.kt diff --git a/generators/idea-generator/tests/org/jetbrains/kotlin/generators/tests/idea/GenerateTests.kt b/generators/idea-generator/tests/org/jetbrains/kotlin/generators/tests/idea/GenerateTests.kt index 3e7d4e12629..d0e5a8ce9bc 100644 --- a/generators/idea-generator/tests/org/jetbrains/kotlin/generators/tests/idea/GenerateTests.kt +++ b/generators/idea-generator/tests/org/jetbrains/kotlin/generators/tests/idea/GenerateTests.kt @@ -1197,6 +1197,7 @@ fun main(args: Array) { testClass { val pattern = "^([\\w\\-_]+)\\.(kt|kts)$" + model("intentions/addPropertyAccessors", pattern = pattern) model("intentions/specifyTypeExplicitly", pattern = pattern) } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/intentions/HLAddAccessorIntentions.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/intentions/HLAddAccessorIntentions.kt new file mode 100644 index 00000000000..3527e7950af --- /dev/null +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/fir/intentions/HLAddAccessorIntentions.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2021 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.idea.fir.intentions + +import com.intellij.codeInsight.intention.LowPriorityAction +import org.jetbrains.kotlin.idea.api.applicator.HLApplicator +import org.jetbrains.kotlin.idea.api.applicator.HLApplicatorInput +import org.jetbrains.kotlin.idea.api.applicator.applicator +import org.jetbrains.kotlin.idea.fir.api.AbstractHLIntention +import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicabilityRange +import org.jetbrains.kotlin.idea.fir.api.applicator.HLApplicatorInputProvider +import org.jetbrains.kotlin.idea.fir.api.applicator.inputProvider +import org.jetbrains.kotlin.idea.fir.applicators.ApplicabilityRanges +import org.jetbrains.kotlin.idea.frontend.api.symbols.KtPropertySymbol +import org.jetbrains.kotlin.idea.intentions.AbstractAddAccessorsIntention +import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.load.java.JvmAbi +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.psi.psiUtil.containingClass +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject +import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier + +abstract class HLAddAccessorIntention(private val addGetter: Boolean, private val addSetter: Boolean) : + AbstractHLIntention(KtProperty::class) { + // TODO: Copy and test range from AddAccessorIntentions.applicabilityRange + override val applicabilityRange: HLApplicabilityRange = ApplicabilityRanges.SELF + + override val applicator: HLApplicator = applicator { + applyTo { ktProperty, _, _, editor -> + AbstractAddAccessorsIntention.applyTo(ktProperty, editor, addGetter, addSetter) + } + familyAndActionName(AbstractAddAccessorsIntention.createFamilyName(addGetter, addSetter)) + } + + override val inputProvider: HLApplicatorInputProvider = inputProvider { ktProperty -> + val symbol = ktProperty.getVariableSymbol() as? KtPropertySymbol ?: return@inputProvider null + if (symbol.containsAnnotation(JVM_FIELD_CLASS_ID)) return@inputProvider null + + HLApplicatorInput.Empty + } + + companion object { + private val JVM_FIELD_CLASS_ID = ClassId.topLevel(JvmAbi.JVM_FIELD_ANNOTATION_FQ_NAME) + + private fun applicator(addGetter: Boolean, addSetter: Boolean): HLApplicator = applicator { + familyAndActionName(AbstractAddAccessorsIntention.createFamilyName(addGetter, addSetter)) + + isApplicableByPsi { ktProperty -> + if (ktProperty.isLocal || ktProperty.hasDelegate() || + ktProperty.containingClass()?.isInterface() == true || + ktProperty.containingClassOrObject?.hasExpectModifier() == true || + ktProperty.hasModifier(KtTokens.ABSTRACT_KEYWORD) || + ktProperty.hasModifier(KtTokens.LATEINIT_KEYWORD) || + ktProperty.hasModifier(KtTokens.CONST_KEYWORD) + ) { + return@isApplicableByPsi false + } + + if (ktProperty.typeReference == null && !ktProperty.hasInitializer()) return@isApplicableByPsi false + if (addSetter && (!ktProperty.isVar || ktProperty.setter != null)) return@isApplicableByPsi false + if (addGetter && ktProperty.getter != null) return@isApplicableByPsi false + + true + } + + applyTo { ktProperty, _, _, editor -> + AbstractAddAccessorsIntention.applyTo(ktProperty, editor, addGetter, addSetter) + } + } + } +} + +class HLAddGetterAndSetterIntention : HLAddAccessorIntention(addGetter = true, addSetter = true), LowPriorityAction +class HLAddGetterIntention : HLAddAccessorIntention(addGetter = true, addSetter = false) +class HLAddSetterIntention : HLAddAccessorIntention(addGetter = false, addSetter = true) \ No newline at end of file diff --git a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/fir/intentions/HLIntentionTestGenerated.java b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/fir/intentions/HLIntentionTestGenerated.java index f012123fdeb..d936abb89ff 100644 --- a/idea/idea-fir/tests/org/jetbrains/kotlin/idea/fir/intentions/HLIntentionTestGenerated.java +++ b/idea/idea-fir/tests/org/jetbrains/kotlin/idea/fir/intentions/HLIntentionTestGenerated.java @@ -17,190 +17,445 @@ import java.util.regex.Pattern; /** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") -@TestMetadata("idea/testData/intentions/specifyTypeExplicitly") -@TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) public class HLIntentionTestGenerated extends AbstractHLIntentionTest { - private void runTest(String testDataFilePath) throws Exception { - KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + @TestMetadata("idea/testData/intentions/addPropertyAccessors") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AddPropertyAccessors extends AbstractHLIntentionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + public void testAllFilesPresentInAddPropertyAccessors() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/addPropertyAccessors"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true); + } + + @TestMetadata("idea/testData/intentions/addPropertyAccessors/both") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Both extends AbstractHLIntentionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("abstract.kt") + public void testAbstract() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/abstract.kt"); + } + + public void testAllFilesPresentInBoth() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/addPropertyAccessors/both"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true); + } + + @TestMetadata("delegate.kt") + public void testDelegate() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/delegate.kt"); + } + + @TestMetadata("expect.kt") + public void testExpect() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/expect.kt"); + } + + @TestMetadata("hasAccessor.kt") + public void testHasAccessor() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/hasAccessor.kt"); + } + + @TestMetadata("hasGetter.kt") + public void testHasGetter() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/hasGetter.kt"); + } + + @TestMetadata("hasSetter.kt") + public void testHasSetter() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/hasSetter.kt"); + } + + @TestMetadata("jvmField.kt") + public void testJvmField() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/jvmField.kt"); + } + + @TestMetadata("lateinit.kt") + public void testLateinit() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/lateinit.kt"); + } + + @TestMetadata("local.kt") + public void testLocal() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/local.kt"); + } + + @TestMetadata("noType.kt") + public void testNoType() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/noType.kt"); + } + + @TestMetadata("top.kt") + public void testTop() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/top.kt"); + } + + @TestMetadata("val.kt") + public void testVal() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/val.kt"); + } + + @TestMetadata("var.kt") + public void testVar() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/var.kt"); + } + } + + @TestMetadata("idea/testData/intentions/addPropertyAccessors/getter") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Getter extends AbstractHLIntentionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("abstract.kt") + public void testAbstract() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/abstract.kt"); + } + + public void testAllFilesPresentInGetter() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/addPropertyAccessors/getter"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true); + } + + @TestMetadata("const.kt") + public void testConst() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/const.kt"); + } + + @TestMetadata("delegate.kt") + public void testDelegate() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/delegate.kt"); + } + + @TestMetadata("expect.kt") + public void testExpect() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/expect.kt"); + } + + @TestMetadata("hasAccessor.kt") + public void testHasAccessor() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/hasAccessor.kt"); + } + + @TestMetadata("hasGetter.kt") + public void testHasGetter() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/hasGetter.kt"); + } + + @TestMetadata("hasSetter.kt") + public void testHasSetter() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/hasSetter.kt"); + } + + @TestMetadata("jvmField.kt") + public void testJvmField() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/jvmField.kt"); + } + + @TestMetadata("lateinit.kt") + public void testLateinit() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/lateinit.kt"); + } + + @TestMetadata("local.kt") + public void testLocal() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/local.kt"); + } + + @TestMetadata("noType.kt") + public void testNoType() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/noType.kt"); + } + + @TestMetadata("top.kt") + public void testTop() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/top.kt"); + } + + @TestMetadata("val.kt") + public void testVal() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/val.kt"); + } + + @TestMetadata("var.kt") + public void testVar() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/var.kt"); + } + } + + @TestMetadata("idea/testData/intentions/addPropertyAccessors/setter") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class Setter extends AbstractHLIntentionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } + + @TestMetadata("abstract.kt") + public void testAbstract() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/abstract.kt"); + } + + public void testAllFilesPresentInSetter() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/addPropertyAccessors/setter"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true); + } + + @TestMetadata("delegate.kt") + public void testDelegate() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/delegate.kt"); + } + + @TestMetadata("expect.kt") + public void testExpect() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/expect.kt"); + } + + @TestMetadata("hasAccessor.kt") + public void testHasAccessor() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/hasAccessor.kt"); + } + + @TestMetadata("hasGetter.kt") + public void testHasGetter() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/hasGetter.kt"); + } + + @TestMetadata("hasSetter.kt") + public void testHasSetter() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/hasSetter.kt"); + } + + @TestMetadata("jvmField.kt") + public void testJvmField() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/jvmField.kt"); + } + + @TestMetadata("lateinit.kt") + public void testLateinit() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/lateinit.kt"); + } + + @TestMetadata("local.kt") + public void testLocal() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/local.kt"); + } + + @TestMetadata("noType.kt") + public void testNoType() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/noType.kt"); + } + + @TestMetadata("top.kt") + public void testTop() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/top.kt"); + } + + @TestMetadata("val.kt") + public void testVal() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/val.kt"); + } + + @TestMetadata("var.kt") + public void testVar() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/var.kt"); + } + } } - public void testAllFilesPresentInSpecifyTypeExplicitly() throws Exception { - KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/specifyTypeExplicitly"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true); - } + @TestMetadata("idea/testData/intentions/specifyTypeExplicitly") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class SpecifyTypeExplicitly extends AbstractHLIntentionTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, this, testDataFilePath); + } - @TestMetadata("anonymousObject.kt") - public void testAnonymousObject() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/anonymousObject.kt"); - } + public void testAllFilesPresentInSpecifyTypeExplicitly() throws Exception { + KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/specifyTypeExplicitly"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true); + } - @TestMetadata("backticked.kt") - public void testBackticked() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/backticked.kt"); - } + @TestMetadata("anonymousObject.kt") + public void testAnonymousObject() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/anonymousObject.kt"); + } - @TestMetadata("badCaretPosition.kt") - public void testBadCaretPosition() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/badCaretPosition.kt"); - } + @TestMetadata("backticked.kt") + public void testBackticked() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/backticked.kt"); + } - @TestMetadata("classNameClashing.kt") - public void testClassNameClashing() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/classNameClashing.kt"); - } + @TestMetadata("badCaretPosition.kt") + public void testBadCaretPosition() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/badCaretPosition.kt"); + } - @TestMetadata("constructor.kt") - public void testConstructor() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/constructor.kt"); - } + @TestMetadata("classNameClashing.kt") + public void testClassNameClashing() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/classNameClashing.kt"); + } - @TestMetadata("destructuringInLambda.kt") - public void testDestructuringInLambda() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/destructuringInLambda.kt"); - } + @TestMetadata("constructor.kt") + public void testConstructor() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/constructor.kt"); + } - @TestMetadata("enumType.kt") - public void testEnumType() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/enumType.kt"); - } + @TestMetadata("destructuringInLambda.kt") + public void testDestructuringInLambda() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/destructuringInLambda.kt"); + } - @TestMetadata("forAsExpression.kt") - public void testForAsExpression() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/forAsExpression.kt"); - } + @TestMetadata("enumType.kt") + public void testEnumType() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/enumType.kt"); + } - @TestMetadata("functionType.kt") - public void testFunctionType() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/functionType.kt"); - } + @TestMetadata("forAsExpression.kt") + public void testForAsExpression() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/forAsExpression.kt"); + } - @TestMetadata("genericClass.kt") - public void testGenericClass() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/genericClass.kt"); - } + @TestMetadata("functionType.kt") + public void testFunctionType() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/functionType.kt"); + } - @TestMetadata("genericClassWithTypeParameters.kt") - public void testGenericClassWithTypeParameters() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/genericClassWithTypeParameters.kt"); - } + @TestMetadata("genericClass.kt") + public void testGenericClass() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/genericClass.kt"); + } - @TestMetadata("genericClassWithTypeParameters2.kt") - public void testGenericClassWithTypeParameters2() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/genericClassWithTypeParameters2.kt"); - } + @TestMetadata("genericClassWithTypeParameters.kt") + public void testGenericClassWithTypeParameters() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/genericClassWithTypeParameters.kt"); + } - @TestMetadata("genericFunction.kt") - public void testGenericFunction() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/genericFunction.kt"); - } + @TestMetadata("genericClassWithTypeParameters2.kt") + public void testGenericClassWithTypeParameters2() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/genericClassWithTypeParameters2.kt"); + } - @TestMetadata("innerTypeParameter.kt") - public void testInnerTypeParameter() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/innerTypeParameter.kt"); - } + @TestMetadata("genericFunction.kt") + public void testGenericFunction() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/genericFunction.kt"); + } - @TestMetadata("innerTypeParameter2.kt") - public void testInnerTypeParameter2() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/innerTypeParameter2.kt"); - } + @TestMetadata("innerTypeParameter.kt") + public void testInnerTypeParameter() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/innerTypeParameter.kt"); + } - @TestMetadata("lambdaParam.kt") - public void testLambdaParam() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/lambdaParam.kt"); - } + @TestMetadata("innerTypeParameter2.kt") + public void testInnerTypeParameter2() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/innerTypeParameter2.kt"); + } - @TestMetadata("localClass.kt") - public void testLocalClass() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/localClass.kt"); - } + @TestMetadata("lambdaParam.kt") + public void testLambdaParam() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/lambdaParam.kt"); + } - @TestMetadata("localClassInSecondTypeParameter.kt") - public void testLocalClassInSecondTypeParameter() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/localClassInSecondTypeParameter.kt"); - } + @TestMetadata("localClass.kt") + public void testLocalClass() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/localClass.kt"); + } - @TestMetadata("localClassInSecondTypeParameter2.kt") - public void testLocalClassInSecondTypeParameter2() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/localClassInSecondTypeParameter2.kt"); - } + @TestMetadata("localClassInSecondTypeParameter.kt") + public void testLocalClassInSecondTypeParameter() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/localClassInSecondTypeParameter.kt"); + } - @TestMetadata("localClassInSecondTypeParameter3.kt") - public void testLocalClassInSecondTypeParameter3() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/localClassInSecondTypeParameter3.kt"); - } + @TestMetadata("localClassInSecondTypeParameter2.kt") + public void testLocalClassInSecondTypeParameter2() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/localClassInSecondTypeParameter2.kt"); + } - @TestMetadata("localClassInTypeParameter.kt") - public void testLocalClassInTypeParameter() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/localClassInTypeParameter.kt"); - } + @TestMetadata("localClassInSecondTypeParameter3.kt") + public void testLocalClassInSecondTypeParameter3() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/localClassInSecondTypeParameter3.kt"); + } - @TestMetadata("loopParameter.kt") - public void testLoopParameter() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/loopParameter.kt"); - } + @TestMetadata("localClassInTypeParameter.kt") + public void testLocalClassInTypeParameter() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/localClassInTypeParameter.kt"); + } - @TestMetadata("outClass.kt") - public void testOutClass() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/outClass.kt"); - } + @TestMetadata("loopParameter.kt") + public void testLoopParameter() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/loopParameter.kt"); + } - @TestMetadata("outClass2.kt") - public void testOutClass2() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/outClass2.kt"); - } + @TestMetadata("outClass.kt") + public void testOutClass() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/outClass.kt"); + } - @TestMetadata("outClass3.kt") - public void testOutClass3() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/outClass3.kt"); - } + @TestMetadata("outClass2.kt") + public void testOutClass2() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/outClass2.kt"); + } - @TestMetadata("overriddenAsNull.kt") - public void testOverriddenAsNull() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/overriddenAsNull.kt"); - } + @TestMetadata("outClass3.kt") + public void testOutClass3() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/outClass3.kt"); + } - @TestMetadata("overrideNotNullFunction.kt") - public void testOverrideNotNullFunction() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt"); - } + @TestMetadata("overriddenAsNull.kt") + public void testOverriddenAsNull() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/overriddenAsNull.kt"); + } - @TestMetadata("overrideNotNullProperty.kt") - public void testOverrideNotNullProperty() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt"); - } + @TestMetadata("overrideNotNullFunction.kt") + public void testOverrideNotNullFunction() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/overrideNotNullFunction.kt"); + } - @TestMetadata("overrideNullableFunction.kt") - public void testOverrideNullableFunction() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt"); - } + @TestMetadata("overrideNotNullProperty.kt") + public void testOverrideNotNullProperty() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/overrideNotNullProperty.kt"); + } - @TestMetadata("overrideNullableProperty.kt") - public void testOverrideNullableProperty() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt"); - } + @TestMetadata("overrideNullableFunction.kt") + public void testOverrideNullableFunction() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/overrideNullableFunction.kt"); + } - @TestMetadata("propertyTypeFromGetter.kt") - public void testPropertyTypeFromGetter() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/propertyTypeFromGetter.kt"); - } + @TestMetadata("overrideNullableProperty.kt") + public void testOverrideNullableProperty() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/overrideNullableProperty.kt"); + } - @TestMetadata("publicMember.kt") - public void testPublicMember() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/publicMember.kt"); - } + @TestMetadata("propertyTypeFromGetter.kt") + public void testPropertyTypeFromGetter() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/propertyTypeFromGetter.kt"); + } - @TestMetadata("stringRedefined.kt") - public void testStringRedefined() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/stringRedefined.kt"); - } + @TestMetadata("publicMember.kt") + public void testPublicMember() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/publicMember.kt"); + } - @TestMetadata("typeAlreadyProvided.kt") - public void testTypeAlreadyProvided() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/typeAlreadyProvided.kt"); - } + @TestMetadata("stringRedefined.kt") + public void testStringRedefined() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/stringRedefined.kt"); + } - @TestMetadata("unitType.kt") - public void testUnitType() throws Exception { - runTest("idea/testData/intentions/specifyTypeExplicitly/unitType.kt"); + @TestMetadata("typeAlreadyProvided.kt") + public void testTypeAlreadyProvided() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/typeAlreadyProvided.kt"); + } + + @TestMetadata("unitType.kt") + public void testUnitType() throws Exception { + runTest("idea/testData/intentions/specifyTypeExplicitly/unitType.kt"); + } } } diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/api/applicator/HLApplicatorInput.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/api/applicator/HLApplicatorInput.kt index 0bc0ea379ab..9d458b0a595 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/api/applicator/HLApplicatorInput.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/api/applicator/HLApplicatorInput.kt @@ -23,4 +23,6 @@ import com.intellij.psi.PsiElement */ interface HLApplicatorInput { fun isValidFor(psi: PsiElement): Boolean = true + + companion object Empty : HLApplicatorInput } diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/intentions/AbstractAddAccessorsIntention.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/intentions/AbstractAddAccessorsIntention.kt index e2304d42ffb..6dc12bb56bc 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/intentions/AbstractAddAccessorsIntention.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/intentions/AbstractAddAccessorsIntention.kt @@ -18,39 +18,44 @@ abstract class AbstractAddAccessorsIntention( ) : SelfTargetingRangeIntention(KtProperty::class.java, createFamilyName(addGetter, addSetter)) { override fun applyTo(element: KtProperty, editor: Editor?) { - val hasInitializer = element.hasInitializer() - val psiFactory = KtPsiFactory(element) - if (addGetter) { - val expression = if (hasInitializer) psiFactory.createExpression("field") else psiFactory.createBlock("TODO()") - val getter = psiFactory.createPropertyGetter(expression) - val added = if (element.setter != null) { - element.addBefore(getter, element.setter) - } else { - element.add(getter) + applyTo(element, editor, addGetter, addSetter) + } + + companion object { + fun applyTo(element: KtProperty, editor: Editor?, addGetter: Boolean, addSetter: Boolean) { + val hasInitializer = element.hasInitializer() + val psiFactory = KtPsiFactory(element) + if (addGetter) { + val expression = if (hasInitializer) psiFactory.createExpression("field") else psiFactory.createBlock("TODO()") + val getter = psiFactory.createPropertyGetter(expression) + val added = if (element.setter != null) { + element.addBefore(getter, element.setter) + } else { + element.add(getter) + } + if (!hasInitializer) { + (added as? KtPropertyAccessor)?.bodyBlockExpression?.statements?.firstOrNull()?.let { + editor?.caretModel?.moveToOffset(it.startOffset) + } + } } - if (!hasInitializer) { - (added as? KtPropertyAccessor)?.bodyBlockExpression?.statements?.firstOrNull()?.let { - editor?.caretModel?.moveToOffset(it.startOffset) + if (addSetter) { + val expression = if (hasInitializer) psiFactory.createBlock("field = value") else psiFactory.createEmptyBody() + val setter = psiFactory.createPropertySetter(expression) + val added = element.add(setter) + if (!hasInitializer && !addGetter) { + (added as? KtPropertyAccessor)?.bodyBlockExpression?.lBrace?.let { + editor?.caretModel?.moveToOffset(it.startOffset + 1) + } } } } - if (addSetter) { - val expression = if (hasInitializer) psiFactory.createBlock("field = value") else psiFactory.createEmptyBody() - val setter = psiFactory.createPropertySetter(expression) - val added = element.add(setter) - if (!hasInitializer && !addGetter) { - (added as? KtPropertyAccessor)?.bodyBlockExpression?.lBrace?.let { - editor?.caretModel?.moveToOffset(it.startOffset + 1) - } - } + + fun createFamilyName(addGetter: Boolean, addSetter: Boolean): () -> String = when { + addGetter && addSetter -> KotlinBundle.lazyMessage("text.add.getter.and.setter") + addGetter -> KotlinBundle.lazyMessage("text.add.getter") + addSetter -> KotlinBundle.lazyMessage("text.add.setter") + else -> throw AssertionError("At least one from (addGetter, addSetter) should be true") } } -} - -private fun createFamilyName(addGetter: Boolean, addSetter: Boolean): () -> String = when { - addGetter && addSetter -> KotlinBundle.lazyMessage("text.add.getter.and.setter") - addGetter -> KotlinBundle.lazyMessage("text.add.getter") - addSetter -> KotlinBundle.lazyMessage("text.add.setter") - else -> throw AssertionError("At least one from (addGetter, addSetter) should be true") -} - +} \ No newline at end of file diff --git a/idea/resources-fir/META-INF/firIntentions.xml b/idea/resources-fir/META-INF/firIntentions.xml index bf2c30a3cc0..1d0c861bed2 100644 --- a/idea/resources-fir/META-INF/firIntentions.xml +++ b/idea/resources-fir/META-INF/firIntentions.xml @@ -4,5 +4,20 @@ org.jetbrains.kotlin.idea.fir.intentions.declarations.HLSpecifyExplicitTypeForCallableDeclarationIntention Kotlin + + + org.jetbrains.kotlin.idea.fir.intentions.HLAddGetterAndSetterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.fir.intentions.HLAddGetterIntention + Kotlin + + + + org.jetbrains.kotlin.idea.fir.intentions.HLAddSetterIntention + Kotlin + \ No newline at end of file diff --git a/idea/testData/intentions/addPropertyAccessors/both/.firIntention b/idea/testData/intentions/addPropertyAccessors/both/.firIntention new file mode 100644 index 00000000000..5b97955eaed --- /dev/null +++ b/idea/testData/intentions/addPropertyAccessors/both/.firIntention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.fir.intentions.HLAddGetterAndSetterIntention \ No newline at end of file diff --git a/idea/testData/intentions/addPropertyAccessors/both/expect.kt b/idea/testData/intentions/addPropertyAccessors/both/expect.kt new file mode 100644 index 00000000000..e9df0b49a32 --- /dev/null +++ b/idea/testData/intentions/addPropertyAccessors/both/expect.kt @@ -0,0 +1,6 @@ +// SKIP_ERRORS_BEFORE +// SKIP_ERRORS_AFTER +// IS_APPLICABLE: false +expect class Header { + var x: Int +} \ No newline at end of file diff --git a/idea/testData/intentions/addPropertyAccessors/getter/.firIntention b/idea/testData/intentions/addPropertyAccessors/getter/.firIntention new file mode 100644 index 00000000000..131c0948e42 --- /dev/null +++ b/idea/testData/intentions/addPropertyAccessors/getter/.firIntention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.fir.intentions.HLAddGetterIntention \ No newline at end of file diff --git a/idea/testData/intentions/addPropertyAccessors/getter/const.kt b/idea/testData/intentions/addPropertyAccessors/getter/const.kt new file mode 100644 index 00000000000..a52612d4b15 --- /dev/null +++ b/idea/testData/intentions/addPropertyAccessors/getter/const.kt @@ -0,0 +1,4 @@ +// IS_APPLICABLE: false +class Test { + const val x = 1 +} \ No newline at end of file diff --git a/idea/testData/intentions/addPropertyAccessors/getter/header.kt b/idea/testData/intentions/addPropertyAccessors/getter/expect.kt similarity index 100% rename from idea/testData/intentions/addPropertyAccessors/getter/header.kt rename to idea/testData/intentions/addPropertyAccessors/getter/expect.kt diff --git a/idea/testData/intentions/addPropertyAccessors/setter/.firIntention b/idea/testData/intentions/addPropertyAccessors/setter/.firIntention new file mode 100644 index 00000000000..1d492e08f6f --- /dev/null +++ b/idea/testData/intentions/addPropertyAccessors/setter/.firIntention @@ -0,0 +1 @@ +org.jetbrains.kotlin.idea.fir.intentions.HLAddSetterIntention \ No newline at end of file diff --git a/idea/testData/intentions/addPropertyAccessors/setter/expect.kt b/idea/testData/intentions/addPropertyAccessors/setter/expect.kt new file mode 100644 index 00000000000..e9df0b49a32 --- /dev/null +++ b/idea/testData/intentions/addPropertyAccessors/setter/expect.kt @@ -0,0 +1,6 @@ +// SKIP_ERRORS_BEFORE +// SKIP_ERRORS_AFTER +// IS_APPLICABLE: false +expect class Header { + var x: Int +} \ No newline at end of file diff --git a/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt b/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt index d91c32e0687..ead42a039e3 100644 --- a/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt +++ b/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt @@ -4,5 +4,4 @@ class Test { get() { return 1 } -} -/* IGNORE_FIR */ +} \ No newline at end of file diff --git a/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt.after b/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt.after index d04b7db1c47..8153f5e1411 100644 --- a/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt.after +++ b/idea/testData/quickfix/addPropertyAccessors/varHasGetter.kt.after @@ -5,5 +5,4 @@ class Test { return 1 } set(value) {} -} -/* IGNORE_FIR */ +} \ No newline at end of file diff --git a/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt b/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt index 3abcf474b92..1b4835daa07 100644 --- a/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt +++ b/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt @@ -3,5 +3,4 @@ class Test { var x: Int set(value) {} -} -/* IGNORE_FIR */ +} \ No newline at end of file diff --git a/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt.after b/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt.after index 223378051d8..bfc6afd8468 100644 --- a/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt.after +++ b/idea/testData/quickfix/addPropertyAccessors/varHasSetter.kt.after @@ -6,5 +6,4 @@ class Test { TODO() } set(value) {} -} -/* IGNORE_FIR */ +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 8c4da8784d9..ebb92e60720 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -1626,6 +1626,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest { runTest("idea/testData/intentions/addPropertyAccessors/both/delegate.kt"); } + @TestMetadata("expect.kt") + public void testExpect() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/both/expect.kt"); + } + @TestMetadata("hasAccessor.kt") public void testHasAccessor() throws Exception { runTest("idea/testData/intentions/addPropertyAccessors/both/hasAccessor.kt"); @@ -1694,11 +1699,21 @@ public class IntentionTestGenerated extends AbstractIntentionTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/intentions/addPropertyAccessors/getter"), Pattern.compile("^([\\w\\-_]+)\\.(kt|kts)$"), null, true); } + @TestMetadata("const.kt") + public void testConst() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/const.kt"); + } + @TestMetadata("delegate.kt") public void testDelegate() throws Exception { runTest("idea/testData/intentions/addPropertyAccessors/getter/delegate.kt"); } + @TestMetadata("expect.kt") + public void testExpect() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/getter/expect.kt"); + } + @TestMetadata("hasAccessor.kt") public void testHasAccessor() throws Exception { runTest("idea/testData/intentions/addPropertyAccessors/getter/hasAccessor.kt"); @@ -1714,11 +1729,6 @@ public class IntentionTestGenerated extends AbstractIntentionTest { runTest("idea/testData/intentions/addPropertyAccessors/getter/hasSetter.kt"); } - @TestMetadata("header.kt") - public void testHeader() throws Exception { - runTest("idea/testData/intentions/addPropertyAccessors/getter/header.kt"); - } - @TestMetadata("jvmField.kt") public void testJvmField() throws Exception { runTest("idea/testData/intentions/addPropertyAccessors/getter/jvmField.kt"); @@ -1777,6 +1787,11 @@ public class IntentionTestGenerated extends AbstractIntentionTest { runTest("idea/testData/intentions/addPropertyAccessors/setter/delegate.kt"); } + @TestMetadata("expect.kt") + public void testExpect() throws Exception { + runTest("idea/testData/intentions/addPropertyAccessors/setter/expect.kt"); + } + @TestMetadata("hasAccessor.kt") public void testHasAccessor() throws Exception { runTest("idea/testData/intentions/addPropertyAccessors/setter/hasAccessor.kt");