From 58a8c0ed08d090efcb7c5c9cc4f7bdd35ecf0243 Mon Sep 17 00:00:00 2001 From: Wojciech Lopata Date: Wed, 20 Feb 2013 11:09:44 +0100 Subject: [PATCH] QuickFix for DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED --- .../jetbrains/jet/lang/psi/JetPsiFactory.java | 8 ++ .../jetbrains/jet/plugin/JetBundle.properties | 2 + .../AddSemicolonAfterFunctionCallFix.java | 76 +++++++++++++++++++ .../jet/plugin/quickfix/QuickFixes.java | 2 + .../afterDanglingFunctionLiteralArgument.kt | 8 ++ .../beforeDanglingFunctionLiteralArgument.kt | 8 ++ .../quickfix/QuickFixTestGenerated.java | 5 ++ 7 files changed, 109 insertions(+) create mode 100644 idea/src/org/jetbrains/jet/plugin/quickfix/AddSemicolonAfterFunctionCallFix.java create mode 100644 idea/testData/quickfix/expressions/afterDanglingFunctionLiteralArgument.kt create mode 100644 idea/testData/quickfix/expressions/beforeDanglingFunctionLiteralArgument.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java index d4fa6e97162..e526e2a2941 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiFactory.java @@ -73,6 +73,14 @@ public class JetPsiFactory { return property.getNode().findChildByType(JetTokens.COLON); } + @NotNull + public static PsiElement createSemicolon(Project project) { + JetProperty property = createProperty(project, "val x: Int;"); + PsiElement semicolon = property.findElementAt(10); + assert semicolon != null; + return semicolon; + } + public static PsiElement createWhiteSpace(Project project) { return createWhiteSpace(project, " "); } diff --git a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties index 4d815943e01..fdd1cf2c6a9 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties +++ b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties @@ -47,6 +47,8 @@ specify.type.explicitly.add.action.name=Specify type explicitly specify.type.explicitly.remove.action.name=Remove explicitly specified type rename.parameter.to.match.overridden.method=Rename parameter to match overridden method rename.family=Rename +add.semicolon.after.invocation=Add semicolon after invocation of ''{0}'' +add.semicolon.family=Add Semicolon add.kotlin.signature.action.family.name=Specify Custom Kotlin Signature add.kotlin.signature.action.text=Specify custom Kotlin signature diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/AddSemicolonAfterFunctionCallFix.java b/idea/src/org/jetbrains/jet/plugin/quickfix/AddSemicolonAfterFunctionCallFix.java new file mode 100644 index 00000000000..94646af3903 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/AddSemicolonAfterFunctionCallFix.java @@ -0,0 +1,76 @@ +/* + * Copyright 2010-2013 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.jet.plugin.quickfix; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.diagnostics.Diagnostic; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.plugin.JetBundle; + +public class AddSemicolonAfterFunctionCallFix extends JetIntentionAction { + JetFunctionLiteralExpression literal; + + public AddSemicolonAfterFunctionCallFix(@NotNull JetCallExpression element, @NotNull JetFunctionLiteralExpression literal) { + super(element); + this.literal = literal; + } + + @NotNull + @Override + public String getText() { + JetExpression callee = element.getCalleeExpression(); + assert callee != null; + return JetBundle.message("add.semicolon.after.invocation", callee.getText()); + } + + @NotNull + @Override + public String getFamilyName() { + return JetBundle.message("add.semicolon.family"); + } + + @Override + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + PsiElement argumentList = element.getValueArgumentList(); + assert argumentList != null; + PsiElement afterArgumentList = argumentList.getNextSibling(); + int caretOffset = editor.getCaretModel().getOffset(); + element.getParent().addRangeAfter(afterArgumentList, literal, element); + element.deleteChildRange(afterArgumentList, literal); + element.getParent().addAfter(JetPsiFactory.createSemicolon(project), element); + editor.getCaretModel().moveToOffset(caretOffset + 1); + } + + public static JetIntentionActionFactory createFactory() { + return new JetIntentionActionFactory() { + @Nullable + @Override + public JetIntentionAction createAction(Diagnostic diagnostic) { + JetCallExpression callExpression = QuickFixUtil.getParentElementOfType(diagnostic, JetCallExpression.class); + JetFunctionLiteralExpression literalExpression = QuickFixUtil.getParentElementOfType(diagnostic, JetFunctionLiteralExpression.class); + if (callExpression == null || literalExpression == null) return null; + return new AddSemicolonAfterFunctionCallFix(callExpression, literalExpression); + } + }; + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java index 92674fccc89..928a076e2c2 100644 --- a/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java +++ b/idea/src/org/jetbrains/jet/plugin/quickfix/QuickFixes.java @@ -181,5 +181,7 @@ public class QuickFixes { factories.put(ILLEGAL_ENUM_ANNOTATION, RemoveModifierFix.createRemoveModifierFromListOwnerFactory(ENUM_KEYWORD)); factories.put(NOT_AN_ANNOTATION_CLASS, MakeClassAnAnnotationClassFix.createFactory()); + + factories.put(DANGLING_FUNCTION_LITERAL_ARGUMENT_SUSPECTED, AddSemicolonAfterFunctionCallFix.createFactory()); } } diff --git a/idea/testData/quickfix/expressions/afterDanglingFunctionLiteralArgument.kt b/idea/testData/quickfix/expressions/afterDanglingFunctionLiteralArgument.kt new file mode 100644 index 00000000000..37759d163a7 --- /dev/null +++ b/idea/testData/quickfix/expressions/afterDanglingFunctionLiteralArgument.kt @@ -0,0 +1,8 @@ +// "Add semicolon after invocation of 'foo'" "true" +fun foo() {} +fun foo(x : Int) {} +fun bar() { + foo(4); + + {} +} diff --git a/idea/testData/quickfix/expressions/beforeDanglingFunctionLiteralArgument.kt b/idea/testData/quickfix/expressions/beforeDanglingFunctionLiteralArgument.kt new file mode 100644 index 00000000000..da98f8937d4 --- /dev/null +++ b/idea/testData/quickfix/expressions/beforeDanglingFunctionLiteralArgument.kt @@ -0,0 +1,8 @@ +// "Add semicolon after invocation of 'foo'" "true" +fun foo() {} +fun foo(x : Int) {} +fun bar() { + foo(4) + + {} +} diff --git a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java index 0db217b6907..cf122d87c66 100644 --- a/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/plugin/quickfix/QuickFixTestGenerated.java @@ -316,6 +316,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/quickfix/expressions"), Pattern.compile("^before(\\w+)\\.kt$"), true); } + @TestMetadata("beforeDanglingFunctionLiteralArgument.kt") + public void testDanglingFunctionLiteralArgument() throws Exception { + doTest("idea/testData/quickfix/expressions/beforeDanglingFunctionLiteralArgument.kt"); + } + @TestMetadata("beforeUnnecessaryNonNullAssertion1.kt") public void testUnnecessaryNonNullAssertion1() throws Exception { doTest("idea/testData/quickfix/expressions/beforeUnnecessaryNonNullAssertion1.kt");