diff --git a/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java b/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java index 7657ea05396d..7a9aed06479c 100644 --- a/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java +++ b/java/java-impl/src/com/intellij/application/options/editor/JavaCodeFoldingOptionsProvider.java @@ -27,6 +27,7 @@ import com.intellij.openapi.options.BeanConfigurable; public class JavaCodeFoldingOptionsProvider extends BeanConfigurable implements CodeFoldingOptionsProvider { public JavaCodeFoldingOptionsProvider() { super(JavaCodeFoldingSettings.getInstance()); + checkBox("INLINE_PARAMETER_NAMES_FOR_LITERAL_CALL_ARGUMENTS", ApplicationBundle.message("checkbox.collapse.boolean.parameters")); checkBox("COLLAPSE_ONE_LINE_METHODS", ApplicationBundle.message("checkbox.collapse.one.line.methods")); checkBox("COLLAPSE_ACCESSORS", ApplicationBundle.message("checkbox.collapse.simple.property.accessors")); checkBox("COLLAPSE_INNER_CLASSES", ApplicationBundle.message("checkbox.collapse.inner.classes")); diff --git a/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java b/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java index 360b9832431d..5e45853f2f0f 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/folding/JavaCodeFoldingSettings.java @@ -64,4 +64,7 @@ public abstract class JavaCodeFoldingSettings { public abstract boolean isCollapseEndOfLineComments(); public abstract void setCollapseEndOfLineComments(boolean value); + + public abstract boolean isInlineParameterNamesForLiteralCallArguments(); + public abstract void setInlineParameterNamesForLiteralCallArguments(boolean value); } diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java index ee3ff0c3ffd8..647a1e45ac13 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaCodeFoldingSettingsBase.java @@ -14,6 +14,7 @@ public class JavaCodeFoldingSettingsBase extends JavaCodeFoldingSettings { @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_I18N_MESSAGES = true; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_SUPPRESS_WARNINGS = true; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_END_OF_LINE_COMMENTS = false; + @SuppressWarnings({"WeakerAccess"}) public boolean INLINE_PARAMETER_NAMES_FOR_LITERAL_CALL_ARGUMENTS = true; @Override public boolean isCollapseImports() { @@ -148,4 +149,14 @@ public class JavaCodeFoldingSettingsBase extends JavaCodeFoldingSettings { public void setCollapseEndOfLineComments(boolean value) { COLLAPSE_END_OF_LINE_COMMENTS = value; } + + @Override + public boolean isInlineParameterNamesForLiteralCallArguments() { + return INLINE_PARAMETER_NAMES_FOR_LITERAL_CALL_ARGUMENTS; + } + + @Override + public void setInlineParameterNamesForLiteralCallArguments(boolean value) { + INLINE_PARAMETER_NAMES_FOR_LITERAL_CALL_ARGUMENTS = value; + } } diff --git a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java index 15d40f1baf4b..e165ba718467 100644 --- a/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java +++ b/java/java-psi-impl/src/com/intellij/codeInsight/folding/impl/JavaFoldingBuilderBase.java @@ -703,6 +703,12 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem else if (element instanceof PsiComment) { return settings.isCollapseEndOfLineComments(); } + else if (element instanceof PsiLiteralExpression + && element.getParent() instanceof PsiExpressionList + && (element.getParent().getParent() instanceof PsiCallExpression + || element.getParent().getParent() instanceof PsiAnonymousClass)) { + return settings.isInlineParameterNamesForLiteralCallArguments(); + } else { LOG.error("Unknown element:" + element); return false; @@ -725,6 +731,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem public void visitMethodCallExpression(PsiMethodCallExpression expression) { if (!dumb) { addMethodGenericParametersFolding(expression, foldElements, document, quick); + inlineLiteralArgumentsNames(expression, foldElements, quick); } super.visitMethodCallExpression(expression); @@ -734,6 +741,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem public void visitNewExpression(PsiNewExpression expression) { if (!dumb) { addGenericParametersFolding(expression, foldElements, document, quick); + inlineLiteralArgumentsNames(expression, foldElements, quick); } super.visitNewExpression(expression); @@ -747,6 +755,50 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem }); } + private static void inlineLiteralArgumentsNames(@NotNull PsiCallExpression expression, + @NotNull List foldElements, + boolean quick) + { + if (quick || !JavaCodeFoldingSettings.getInstance().isInlineParameterNamesForLiteralCallArguments()) { + return; + } + PsiExpressionList callArgumentsList = expression.getArgumentList(); + if (callArgumentsList == null) { + return; + } + + PsiExpression[] callArguments = callArgumentsList.getExpressions(); + if (callArguments.length > 1) { + PsiParameter[] parameters = null; + boolean isResolved = false; + + for (int i = 0; i < callArguments.length; i++) { + PsiExpression callArgument = callArguments[i]; + + if (callArgument instanceof PsiLiteralExpression) { + if (!isResolved) { + PsiMethod method = expression.resolveMethod(); + isResolved = true; + if (method == null) { + return; + } + parameters = method.getParameterList().getParameters(); + if (parameters.length != callArguments.length) { + return; + } + } + + PsiParameter methodParam = parameters[i]; + if (PsiType.NULL.equals(callArgument.getType()) || methodParam.getType().equals(callArgument.getType())) { + TextRange range = callArgument.getTextRange(); + String placeholderText = methodParam.getName() + ": " + callArgument.getText(); + foldElements.add(new NamedFoldingDescriptor(callArgument, range.getStartOffset(), range.getEndOffset(), null, placeholderText)); + } + } + } + } + } + private boolean addClosureFolding(final PsiClass aClass, final Document document, final List foldElements, @NotNull Set processedComments, final boolean quick) { if (!JavaCodeFoldingSettings.getInstance().isCollapseLambdas()) { diff --git a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy index 41d72f7e9a0e..0f7abd0d0498 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -27,6 +27,7 @@ import com.intellij.openapi.editor.impl.FoldingModelImpl import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass +import com.intellij.psi.PsiLiteralExpression import com.intellij.psi.PsiMethod import com.intellij.psi.search.GlobalSearchScope import com.intellij.testFramework.LightProjectDescriptor @@ -592,6 +593,147 @@ class Test { assert regions[0].placeholderText == '{...}' } + public void "test insert boolean literal argument name"() { + def text = """class Groo { + + public void test() { + boolean testNow = System.currentTimeMillis() > 34000; + int times = 1; + float pi = 4; + String title = "Testing..." + char ch = 'q' + File file; + + configure(true, false, 555, 3.141f, "Huge Title", 'c', null); + configure(testNow, shouldIgnoreRoots(), fourteen, pi, title, c, file); + } + + pubic void configure(boolean testNow, boolean shouldIgnoreRoots, int times, float pi, String title, char terminate, File file) { + System.out.println(); + System.out.println(); + } + +}""" + configure text + PsiClass fooClass = JavaPsiFacade.getInstance(project).findClass('Groo', GlobalSearchScope.allScope(project)) + + def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } + assert regions.size() == 9 + + def literals = fooClass.methods[0].body.statements[6].children[0].children[1].children.findAll { it instanceof PsiLiteralExpression } + def parameters = fooClass.methods[1].parameterList.parameters + + for (int i = 0; i < literals.size(); i++) { + def currentElement = literals[i] + def correspondingFolding = regions[i + 1] + assert correspondingFolding.startOffset == currentElement.textRange.startOffset && correspondingFolding.endOffset == currentElement.textRange.endOffset + assert correspondingFolding.placeholderText == parameters[i].name + ": " + currentElement.text + } + } + + public void "test do not inline name if setter"() { + def text = """class Groo { + + public void test() { + setTestNow(false); + System.out.println(""); + } + + pubic void setTestNow(boolean testNow) { + System.out.println(""); + System.out.println(""); + } + +}""" + configure text + def regions = myFixture.editor.foldingModel.allFoldRegions + assert regions.size() == 2 + } + + public void "test do not collapse varargs"() { + def text = """ +public class VarArgTest { + + public void main() { + System.out.println("AAA"); + testBooleanVarargs(13, false); + } + + public boolean testBooleanVarargs(int test, boolean... booleans) { + int temp = test; + return false; + } +} +""" + configure text + def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } + assert regions.size() == 3 + checkRangeOffsetByPositionInText(regions[1], text, "13") + assert regions[1].placeholderText == "test: 13" + } + + public void "test inline constructor literal arguments names"() { + def text = """ +public class Test { + + public void main() { + System.out.println("AAA"); + Checker r = new Checker(true, false) { + @Override + void test() { + } + }; + } + + abstract class Checker { + Checker(boolean applyToFirst, boolean applyToSecond) {} + abstract void test(); + } +} +""" + configure text + def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } + assert regions.length == 6 + + assert regions[1].placeholderText == "applyToFirst: true" + assert regions[2].placeholderText == "applyToSecond: false" + + checkRangeOffsetByPositionInText(regions[1], text, "true") + checkRangeOffsetByPositionInText(regions[2], text, "false") + } + + public void "test inline anonymous class constructor literal arguments names"() { + def text = """ +public class Test { + + Test(int counter, boolean shouldTest) { + System.out.println(); + System.out.println(); + } + + public static void main() { + System.out.println(); + Test t = new Test(10, false); + } + +} +""" + configure text + def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } + assert regions.length == 4 + + assert regions[2].placeholderText == "counter: 10" + assert regions[3].placeholderText == "shouldTest: false" + + checkRangeOffsetByPositionInText(regions[2], text, "10") + checkRangeOffsetByPositionInText(regions[3], text, "false") + } + + private static def checkRangeOffsetByPositionInText(FoldRegion region, String text, String foldElement) { + assert region.startOffset == text.indexOf(foldElement) && region.endOffset == text.indexOf(foldElement) + foldElement.length() + } + + private def changeFoldRegions(Closure op) { myFixture.editor.foldingModel.runBatchFoldingOperationDoNotCollapseCaret(op) } diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index aed4eb47ec9e..f747cdbe92b2 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -350,6 +350,7 @@ checkbox.collapse.annotations=Annotations checkbox.collapse.inner.classes=Inner classes checkbox.collapse.simple.property.accessors=Simple property accessors checkbox.collapse.one.line.methods=One-line methods +checkbox.collapse.boolean.parameters=Inline parameter names for literal call arguments checkbox.collapse.method.bodies=Method bodies checkbox.collapse.javadoc.comments=Documentation comments checkbox.collapse.title.imports=Imports