From c674398043320313200c6d834da74591dfe5189a Mon Sep 17 00:00:00 2001 From: peter Date: Sun, 6 Oct 2013 20:14:41 +0200 Subject: [PATCH] IDEA-74901 Fold simple property accessors inline --- .../impl/JavaCodeFoldingSettingsBase.java | 2 +- .../folding/impl/JavaFoldingBuilderBase.java | 59 +++++++++++++++++-- .../folding/JavaFoldingTest.groovy | 38 ++++++++++++ 3 files changed, 94 insertions(+), 5 deletions(-) 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 ebbf55e2eee6..c092b5398a81 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 @@ -4,7 +4,7 @@ import com.intellij.codeInsight.folding.CodeFoldingSettings; import com.intellij.codeInsight.folding.JavaCodeFoldingSettings; public class JavaCodeFoldingSettingsBase extends JavaCodeFoldingSettings { - @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ACCESSORS = false; + @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ACCESSORS = true; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_INNER_CLASSES = false; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ANONYMOUS_CLASSES = false; @SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ANNOTATIONS = false; 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 cbaedbeb93d4..d29436834d4e 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 @@ -71,7 +71,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem private static boolean isSimplePropertyAccessor(PsiMethod method) { PsiCodeBlock body = method.getBody(); - if (body == null) return false; + if (body == null || body.getLBrace() == null || body.getRBrace() == null) return false; PsiStatement[] statements = body.getStatements(); if (statements.length == 0) return false; PsiStatement statement = statements[0]; @@ -515,7 +515,10 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem if (child instanceof PsiMethod) { PsiMethod method = (PsiMethod)child; - addToFold(list, method, document, true); + boolean accessor = isSimplePropertyAccessor(method) && addInlineAccessorFolding(list, method); + if (!accessor) { + addToFold(list, method, document, true); + } addAnnotationsToFold(method.getModifierList(), list, document); if (foldJavaDocs) { @@ -526,7 +529,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem } PsiCodeBlock body = method.getBody(); - if (body != null) { + if (body != null && !accessor) { addCodeBlockFolds(body, list, processedComments, document, quick); } } @@ -560,6 +563,48 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem } } + private static boolean addInlineAccessorFolding(List descriptorList, PsiMethod accessor) { + if (!JavaCodeFoldingSettings.getInstance().isCollapseAccessors()) { + return false; + } + + PsiCodeBlock body = accessor.getBody(); + assert body != null; + if (body.getStatements().length > 1) { + return false; + } + + PsiStatement statement = body.getStatements()[0]; + if (statement.textContains('\n')) { + return false; + } + + FoldingGroup group = FoldingGroup.newGroup("simple property accessor"); + int paramListEnd = accessor.getParameterList().getTextRange().getEndOffset(); + int statementStart = statement.getTextRange().getStartOffset(); + PsiJavaToken lBrace = body.getLBrace(); + assert lBrace != null; + descriptorList.add(new FoldingDescriptor(lBrace.getNode(), new TextRange(paramListEnd, statementStart), group) { + @Nullable + @Override + public String getPlaceholderText() { + return " { "; + } + }); + + int statementEnd = statement.getTextRange().getEndOffset(); + PsiJavaToken rBrace = body.getRBrace(); + assert rBrace != null; + descriptorList.add(new FoldingDescriptor(rBrace.getNode(), new TextRange(statementEnd, body.getTextRange().getEndOffset()), group) { + @Nullable + @Override + public String getPlaceholderText() { + return " }"; + } + }); + return true; + } + @Override protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) { return getPlaceholderText(SourceTreeToPsiMap.treeElementToPsi(node)); @@ -569,9 +614,15 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem protected boolean isRegionCollapsedByDefault(@NotNull ASTNode node) { final PsiElement element = SourceTreeToPsiMap.treeElementToPsi(node); JavaCodeFoldingSettings settings = JavaCodeFoldingSettings.getInstance(); - if (element instanceof PsiNewExpression || element instanceof PsiJavaToken) { + if (element instanceof PsiNewExpression || element instanceof PsiJavaToken && + element.getParent() instanceof PsiAnonymousClass) { return settings.isCollapseLambdas(); } + if (element instanceof PsiJavaToken && + element.getParent() instanceof PsiCodeBlock && + element.getParent().getParent() instanceof PsiMethod) { + return settings.isCollapseAccessors(); + } if (element instanceof PsiReferenceParameterList) { return settings.isCollapseConstructorGenericParameters(); } 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 76e465e6952e..1e03eeb15b66 100644 --- a/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy +++ b/java/java-tests/testSrc/com/intellij/codeInsight/folding/JavaFoldingTest.groovy @@ -24,6 +24,10 @@ import com.intellij.openapi.editor.FoldRegion import com.intellij.openapi.editor.ex.FoldingModelEx 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.PsiMethod +import com.intellij.psi.search.GlobalSearchScope import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase /** @@ -427,6 +431,40 @@ class Test { myFixture.doHighlighting() } + public void "test simple property accessors in one line"() { + configure """class Foo { + int field; + + int getField() + { + return field; + } + + void setField(int f) { + field = f; + } + +}""" + PsiClass fooClass = JavaPsiFacade.getInstance(project).findClass('Foo', GlobalSearchScope.allScope(project)) + def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset } + assert regions.size() == 4 + + Closure checkAccessorFolding = { FoldRegion region1, FoldRegion region2, PsiMethod method -> + assert region1.startOffset == method.parameterList.textRange.endOffset + assert region1.endOffset == method.body.statements[0].textRange.startOffset + assert region1.placeholderText == ' { ' + + assert region2.startOffset == method.body.statements[0].textRange.endOffset + assert region2.endOffset == method.textRange.endOffset + assert region2.placeholderText == ' }' + assert region1.group == region2.group + } + + checkAccessorFolding(regions[0], regions[1], fooClass.methods[0]) + checkAccessorFolding(regions[2], regions[3], fooClass.methods[1]) + + } + private def changeFoldRegions(Closure op) { myFixture.editor.foldingModel.runBatchFoldingOperationDoNotCollapseCaret(op) }