IDEA-120750 Fold single-statement methods into one line

This commit is contained in:
peter
2014-02-13 20:25:36 +01:00
parent b1d4696980
commit 2ba17e9aa7
6 changed files with 57 additions and 37 deletions
@@ -27,6 +27,7 @@ import com.intellij.openapi.options.BeanConfigurable;
public class JavaCodeFoldingOptionsProvider extends BeanConfigurable<JavaCodeFoldingSettings> implements CodeFoldingOptionsProvider {
public JavaCodeFoldingOptionsProvider() {
super(JavaCodeFoldingSettings.getInstance());
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"));
checkBox("COLLAPSE_ANONYMOUS_CLASSES", ApplicationBundle.message("checkbox.collapse.anonymous.classes"));
@@ -39,6 +39,8 @@ public abstract class JavaCodeFoldingSettings {
public abstract boolean isCollapseAccessors();
public abstract void setCollapseAccessors(boolean value);
public abstract boolean isCollapseOneLineMethods();
public abstract boolean isCollapseInnerClasses();
public abstract void setCollapseInnerClasses(boolean value);
@@ -4,7 +4,8 @@ import com.intellij.codeInsight.folding.CodeFoldingSettings;
import com.intellij.codeInsight.folding.JavaCodeFoldingSettings;
public class JavaCodeFoldingSettingsBase extends JavaCodeFoldingSettings {
@SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ACCESSORS = true;
@SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ACCESSORS = false;
@SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ONE_LINE_METHODS = true;
@SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_INNER_CLASSES = false;
@SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ANONYMOUS_CLASSES = false;
@SuppressWarnings({"WeakerAccess"}) public boolean COLLAPSE_ANNOTATIONS = false;
@@ -63,6 +64,10 @@ public class JavaCodeFoldingSettingsBase extends JavaCodeFoldingSettings {
public void setCollapseAccessors(boolean value) {
COLLAPSE_ACCESSORS = value;
}
@Override
public boolean isCollapseOneLineMethods() {
return COLLAPSE_ONE_LINE_METHODS;
}
@Override
public boolean isCollapseInnerClasses() {
@@ -81,11 +81,6 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
PsiStatement[] statements = body.getStatements();
if (statements.length == 0) return false;
if (!areOnAdjacentLines(body.getLBrace(), statements[0]) || !areOnAdjacentLines(statements[statements.length - 1], body.getRBrace())) {
//the user might intend to type at an empty line
return false;
}
PsiStatement statement = statements[0];
if (PropertyUtil.isSimplePropertyGetter(method)) {
if (statement instanceof PsiReturnStatement) {
@@ -533,8 +528,8 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
if (child instanceof PsiMethod) {
PsiMethod method = (PsiMethod)child;
boolean accessor = isSimplePropertyAccessor(method) && addInlineAccessorFolding(list, method);
if (!accessor) {
boolean oneLiner = addOneLineMethodFolding(list, method);
if (!oneLiner) {
addToFold(list, method, document, true);
}
addAnnotationsToFold(method.getModifierList(), list, document);
@@ -547,7 +542,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
}
PsiCodeBlock body = method.getBody();
if (body != null && !accessor) {
if (body != null && !oneLiner) {
addCodeBlockFolds(body, list, processedComments, document, quick);
}
}
@@ -581,23 +576,33 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
}
}
private static boolean addInlineAccessorFolding(List<FoldingDescriptor> descriptorList, PsiMethod accessor) {
if (!JavaCodeFoldingSettings.getInstance().isCollapseAccessors()) {
private static boolean addOneLineMethodFolding(List<FoldingDescriptor> descriptorList, PsiMethod method) {
if (!JavaCodeFoldingSettings.getInstance().isCollapseOneLineMethods()) {
return false;
}
PsiCodeBlock body = accessor.getBody();
assert body != null;
if (body.getStatements().length > 1) {
PsiCodeBlock body = method.getBody();
if (body == null) {
return false;
}
PsiJavaToken lBrace = body.getLBrace();
PsiJavaToken rBrace = body.getRBrace();
PsiStatement[] statements = body.getStatements();
if (lBrace == null || rBrace == null || statements.length != 1) {
return false;
}
PsiStatement statement = body.getStatements()[0];
PsiStatement statement = statements[0];
if (statement.textContains('\n')) {
return false;
}
int leftStart = accessor.getParameterList().getTextRange().getEndOffset();
if (!areOnAdjacentLines(body.getLBrace(), statement) || !areOnAdjacentLines(statement, body.getRBrace())) {
//the user might intend to type at an empty line
return false;
}
int leftStart = method.getParameterList().getTextRange().getEndOffset();
int leftEnd = statement.getTextRange().getStartOffset();
int rightStart = statement.getTextRange().getEndOffset();
int rightEnd = body.getTextRange().getEndOffset();
@@ -605,9 +610,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
return false;
}
FoldingGroup group = FoldingGroup.newGroup("simple property accessor");
PsiJavaToken lBrace = body.getLBrace();
assert lBrace != null;
FoldingGroup group = FoldingGroup.newGroup("one-liner");
descriptorList.add(new FoldingDescriptor(lBrace.getNode(), new TextRange(leftStart, leftEnd), group) {
@Nullable
@Override
@@ -616,8 +619,6 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
}
});
PsiJavaToken rBrace = body.getRBrace();
assert rBrace != null;
descriptorList.add(new FoldingDescriptor(rBrace.getNode(), new TextRange(rightStart, rightEnd), group) {
@Nullable
@Override
@@ -627,7 +628,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
});
return true;
}
@Override
protected String getLanguagePlaceholderText(@NotNull ASTNode node, @NotNull TextRange range) {
return getPlaceholderText(SourceTreeToPsiMap.treeElementToPsi(node));
@@ -644,7 +645,7 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
if (element instanceof PsiJavaToken &&
element.getParent() instanceof PsiCodeBlock &&
element.getParent().getParent() instanceof PsiMethod) {
return settings.isCollapseAccessors();
return settings.isCollapseOneLineMethods();
}
if (element instanceof PsiReferenceParameterList) {
return settings.isCollapseConstructorGenericParameters();
@@ -654,9 +655,6 @@ public abstract class JavaFoldingBuilderBase extends CustomFoldingBuilder implem
return settings.isCollapseImports();
}
else if (element instanceof PsiMethod || element instanceof PsiClassInitializer || element instanceof PsiCodeBlock) {
if (!settings.isCollapseAccessors() && !settings.isCollapseMethods()) {
return false;
}
if (element instanceof PsiMethod && isSimplePropertyAccessor((PsiMethod)element)) {
return settings.isCollapseAccessors();
}
@@ -481,17 +481,6 @@ class Test {
def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset }
assert regions.size() == 6
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])
@@ -499,6 +488,30 @@ class Test {
assert regions[5].placeholderText == '{...}'
}
static 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
}
public void "test fold one-line methods"() {
configure """class Foo {
int someMethod() {
return 0;
}
}"""
PsiClass fooClass = JavaPsiFacade.getInstance(project).findClass('Foo', GlobalSearchScope.allScope(project))
def regions = myFixture.editor.foldingModel.allFoldRegions.sort { it.startOffset }
assert regions.size() == 2
checkAccessorFolding(regions[0], regions[1], fooClass.methods[0])
}
private def changeFoldRegions(Closure op) {
myFixture.editor.foldingModel.runBatchFoldingOperationDoNotCollapseCaret(op)
}
@@ -348,6 +348,7 @@ checkbox.collapse.i18n.messages=<html>I18n strings</html>
checkbox.collapse.annotations=<html>Annotations</html>
checkbox.collapse.inner.classes=Inner classes
checkbox.collapse.simple.property.accessors=<html>Simple property accessors<html>
checkbox.collapse.one.line.methods=<html>One-line methods<html>
checkbox.collapse.method.bodies=Method bodies
checkbox.collapse.javadoc.comments=Documentation comments
checkbox.collapse.title.imports=Imports