From ed04b4debd1bcfdc211ab75a3253f78c3903d25c Mon Sep 17 00:00:00 2001 From: Toshiaki Kameyama Date: Thu, 22 Jun 2017 06:37:39 +0300 Subject: [PATCH] Add quick-fix for empty brackets after primary constructor So #KT-18534 Fixed --- .../jetbrains/kotlin/diagnostics/Errors.java | 2 + .../rendering/DefaultErrorMessages.java | 1 + .../kotlin/resolve/DeclarationsChecker.kt | 4 ++ .../primaryConstructorMissingBrackets.kt | 2 + .../primaryConstructorMissingBrackets.txt | 8 +++ .../checkers/DiagnosticsTestGenerated.java | 6 +++ .../quickfix/MissingConstructorBracketsFix.kt | 50 +++++++++++++++++++ .../kotlin/idea/quickfix/QuickFixRegistrar.kt | 2 + .../quickfix/implement/privateConstructor.kt | 2 +- .../missingConstructorBrackets/basic.kt | 4 ++ .../missingConstructorBrackets/basic.kt.after | 4 ++ .../idea/quickfix/QuickFixTestGenerated.java | 15 ++++++ 12 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/diagnostics/tests/modifiers/primaryConstructorMissingBrackets.kt create mode 100644 compiler/testData/diagnostics/tests/modifiers/primaryConstructorMissingBrackets.txt create mode 100644 idea/src/org/jetbrains/kotlin/idea/quickfix/MissingConstructorBracketsFix.kt create mode 100644 idea/testData/quickfix/missingConstructorBrackets/basic.kt create mode 100644 idea/testData/quickfix/missingConstructorBrackets/basic.kt.after diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index f5c4a94707a..d9927b4584c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -273,6 +273,8 @@ public interface Errors { DiagnosticFactory0 MISSING_CONSTRUCTOR_KEYWORD = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 MISSING_CONSTRUCTOR_BRACKETS = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 NON_PRIVATE_CONSTRUCTOR_IN_ENUM = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 NON_PRIVATE_CONSTRUCTOR_IN_SEALED = DiagnosticFactory0.create(ERROR); 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 f5ced899d9c..0e87d83f9ed 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -591,6 +591,7 @@ public class DefaultErrorMessages { MAP.put(ALWAYS_NULL, "The result of the expression is always null"); MAP.put(MISSING_CONSTRUCTOR_KEYWORD, "Use 'constructor' keyword after modifiers of primary constructor"); + MAP.put(MISSING_CONSTRUCTOR_BRACKETS, "Constructor requires brackets"); MAP.put(NON_PRIVATE_CONSTRUCTOR_IN_ENUM, "Constructor must be private in enum class"); MAP.put(NON_PRIVATE_CONSTRUCTOR_IN_SEALED, "Constructor must be private in sealed class"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index bea371ae3ed..bfa8280c07b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -449,6 +449,10 @@ class DeclarationsChecker( declaration.modifierList?.let { trace.report(MISSING_CONSTRUCTOR_KEYWORD.on(it)) } } + if (declaration.valueParameterList == null) { + declaration.getConstructorKeyword()?.let { trace.report(MISSING_CONSTRUCTOR_BRACKETS.on(it)) } + } + if (classOrObject !is KtClass) { trace.report(CONSTRUCTOR_IN_OBJECT.on(declaration)) } diff --git a/compiler/testData/diagnostics/tests/modifiers/primaryConstructorMissingBrackets.kt b/compiler/testData/diagnostics/tests/modifiers/primaryConstructorMissingBrackets.kt new file mode 100644 index 00000000000..63bb476265b --- /dev/null +++ b/compiler/testData/diagnostics/tests/modifiers/primaryConstructorMissingBrackets.kt @@ -0,0 +1,2 @@ +class A private constructor { +} diff --git a/compiler/testData/diagnostics/tests/modifiers/primaryConstructorMissingBrackets.txt b/compiler/testData/diagnostics/tests/modifiers/primaryConstructorMissingBrackets.txt new file mode 100644 index 00000000000..2bc9e211bc2 --- /dev/null +++ b/compiler/testData/diagnostics/tests/modifiers/primaryConstructorMissingBrackets.txt @@ -0,0 +1,8 @@ +package + +public final class A { + private constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index a5cba29ef98..8814a3ec0ee 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -12904,6 +12904,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("primaryConstructorMissingBrackets.kt") + public void testPrimaryConstructorMissingBrackets() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/primaryConstructorMissingBrackets.kt"); + doTest(fileName); + } + @TestMetadata("primaryConstructorMissingKeyword.kt") public void testPrimaryConstructorMissingKeyword() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/primaryConstructorMissingKeyword.kt"); diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/MissingConstructorBracketsFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/MissingConstructorBracketsFix.kt new file mode 100644 index 00000000000..55f5b16d12f --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/MissingConstructorBracketsFix.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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 com.intellij.psi.PsiDocumentManager +import org.jetbrains.kotlin.diagnostics.Diagnostic +import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.psi.KtPrimaryConstructor +import org.jetbrains.kotlin.psi.psiUtil.endOffset + +class MissingConstructorBracketsFix(element: KtPrimaryConstructor) : KotlinQuickFixAction(element), CleanupFix { + override fun getFamilyName(): String = text + override fun getText(): String = "Add empty brackets after primary constructor" + + override fun invoke(project: Project, editor: Editor?, file: KtFile) { + val constructor = element ?: return + val constructorKeyword = constructor.getConstructorKeyword() ?: return + if (constructor.valueParameterList != null) return + + editor?.run { + val endOffset = constructorKeyword.endOffset + document.insertString(endOffset, "()") + caretModel.moveToOffset(endOffset + 1) + PsiDocumentManager.getInstance(project).commitDocument(document) + } + } + + companion object : KotlinSingleIntentionActionFactory() { + override fun createAction(diagnostic: Diagnostic): IntentionAction? = + diagnostic.createIntentionForFirstParentOfType(::MissingConstructorBracketsFix) + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 53fabf214c2..2793ee9f6b7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -386,6 +386,8 @@ class QuickFixRegistrar : QuickFixContributor { MISSING_CONSTRUCTOR_KEYWORD.registerFactory(MissingConstructorKeywordFix) + MISSING_CONSTRUCTOR_BRACKETS.registerFactory(MissingConstructorBracketsFix) + ANONYMOUS_FUNCTION_WITH_NAME.registerFactory(RemoveNameFromFunctionExpressionFix) UNRESOLVED_REFERENCE.registerFactory(ReplaceObsoleteLabelSyntaxFix) diff --git a/idea/testData/quickfix/implement/privateConstructor.kt b/idea/testData/quickfix/implement/privateConstructor.kt index 11492b98fb6..fb3f36b4755 100644 --- a/idea/testData/quickfix/implement/privateConstructor.kt +++ b/idea/testData/quickfix/implement/privateConstructor.kt @@ -1,4 +1,4 @@ // "class org.jetbrains.kotlin.idea.intentions.CreateKotlinSubClassIntention" "false" // ACTION: Create test -abstract class Base private constructor \ No newline at end of file +abstract class Base private constructor() \ No newline at end of file diff --git a/idea/testData/quickfix/missingConstructorBrackets/basic.kt b/idea/testData/quickfix/missingConstructorBrackets/basic.kt new file mode 100644 index 00000000000..f30e2b78aba --- /dev/null +++ b/idea/testData/quickfix/missingConstructorBrackets/basic.kt @@ -0,0 +1,4 @@ +// "Add empty brackets after primary constructor" "true" + +class Fruit private constructor { +} \ No newline at end of file diff --git a/idea/testData/quickfix/missingConstructorBrackets/basic.kt.after b/idea/testData/quickfix/missingConstructorBrackets/basic.kt.after new file mode 100644 index 00000000000..d46f482cccb --- /dev/null +++ b/idea/testData/quickfix/missingConstructorBrackets/basic.kt.after @@ -0,0 +1,4 @@ +// "Add empty brackets after primary constructor" "true" + +class Fruit private constructor() { +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 3fb85a245e4..bbf02369c08 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -6741,6 +6741,21 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { } } + @TestMetadata("idea/testData/quickfix/missingConstructorBrackets") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class MissingConstructorBrackets extends AbstractQuickFixTest { + public void testAllFilesPresentInMissingConstructorBrackets() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/missingConstructorBrackets"), Pattern.compile("^([\\w\\-_]+)\\.kt$"), TargetBackend.ANY, true); + } + + @TestMetadata("basic.kt") + public void testBasic() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/missingConstructorBrackets/basic.kt"); + doTest(fileName); + } + } + @TestMetadata("idea/testData/quickfix/modifiers") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)