diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java
index c907bf2ab6f..066ab511925 100755
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/ui/text/folding/DefaultJavaFoldingStructureProvider.java
@@ -79,7 +79,6 @@
import org.eclipse.jdt.core.dom.DoStatement;
import org.eclipse.jdt.core.dom.EnhancedForStatement;
import org.eclipse.jdt.core.dom.EnumDeclaration;
-import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.ForStatement;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.Initializer;
@@ -87,10 +86,10 @@
import org.eclipse.jdt.core.dom.LambdaExpression;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.Statement;
+import org.eclipse.jdt.core.dom.SwitchCase;
import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.SynchronizedStatement;
import org.eclipse.jdt.core.dom.TryStatement;
-import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.WhileStatement;
import org.eclipse.jdt.ui.PreferenceConstants;
@@ -99,7 +98,6 @@
import org.eclipse.jdt.internal.ui.actions.SelectionConverter;
import org.eclipse.jdt.internal.ui.javaeditor.EditorUtility;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
-import org.eclipse.jdt.internal.ui.text.DocumentCharacterIterator;
/**
* Updates the projection model of a class file or compilation unit.
@@ -331,6 +329,148 @@ private static final class Tuple {
}
}
+ private class FoldingVisitor extends ASTVisitor {
+
+ private FoldingStructureComputationContext ctx;
+
+ public FoldingVisitor(FoldingStructureComputationContext ctx) {
+ this.ctx = ctx;
+ }
+
+ @Override
+ public boolean visit(MethodDeclaration node) {
+ processMethodDeclaration(node, ctx);
+ return true;
+ }
+
+ @Override
+ public boolean visit(IfStatement node) {
+ processIfStatement(node, ctx);
+ return false;
+ }
+
+ @Override
+ public boolean visit(WhileStatement node) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ return true;
+ }
+
+ @Override
+ public boolean visit(ForStatement node) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ return true;
+ }
+
+ @Override
+ public boolean visit(EnhancedForStatement node) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ return true;
+ }
+
+ @Override
+ public boolean visit(DoStatement node) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ return true;
+ }
+
+ @Override
+ public boolean visit(TryStatement node) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ processStatement(node.getBody(), ctx);
+ for (Object catchClauseObj : node.catchClauses()) {
+ CatchClause catchClause = (CatchClause) catchClauseObj;
+ createFoldingRegion(catchClause, ctx, ctx.collapseMembers());
+ processStatement(catchClause.getBody(), ctx);
+ }
+ if (node.getFinally() != null) {
+ createFoldingRegion(node.getFinally(), ctx, ctx.collapseMembers());
+ processStatement(node.getFinally(), ctx);
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean visit(SwitchStatement node) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+
+ List> statements = node.statements();
+ int statementsSize = statements.size();
+
+ for (int i = 0; i < statementsSize; i++) {
+ Statement stmt = (Statement) statements.get(i);
+
+ if (stmt instanceof SwitchCase) {
+ SwitchCase switchCase = (SwitchCase) stmt;
+ int start = switchCase.getStartPosition();
+ int end;
+ int j = i + 1;
+ while (j < statementsSize && !(statements.get(j) instanceof SwitchCase)) {
+ j++;
+ }
+
+ if (j < statementsSize) {
+ end = ((Statement) statements.get(j)).getStartPosition();
+ } else {
+ end = node.getStartPosition() + node.getLength();
+ }
+
+ int length = end - start;
+ if (length > 0) {
+ IRegion region = new Region(start, length);
+ IRegion aligned = alignRegion(region, ctx);
+
+ if (aligned != null) {
+ Position position = new Position(aligned.getOffset(), aligned.getLength());
+ JavaProjectionAnnotation annotation = new JavaProjectionAnnotation(ctx.collapseMembers(), null, false);
+ ctx.addProjectionRange(annotation, position);
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean visit(SynchronizedStatement node) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ return true;
+ }
+
+ @Override
+ public boolean visit(LambdaExpression node) {
+ if (node.getBody() instanceof Block) {
+ createFoldingRegion(node.getBody(), ctx, ctx.collapseMembers());
+ }
+ return true;
+ }
+
+ @Override
+ public boolean visit(AnonymousClassDeclaration node) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ return true;
+ }
+
+ @Override
+ public boolean visit(EnumDeclaration node) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ return true;
+ }
+
+ @Override
+ public boolean visit(Initializer node) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ return true;
+ }
+
+ @Override
+ public boolean visit(Javadoc node) {
+ processComment(node, ctx);
+ return false;
+ }
+ }
+
/**
* Filter for annotations.
*/
@@ -492,87 +632,6 @@ private IJavaElementDelta findElement(IJavaElement target, IJavaElementDelta del
}
}
- /**
- * Projection position that will return two foldable regions: one folding away
- * the region from after the '/**' to the beginning of the content, the other
- * from after the first content line until after the comment.
- */
- private static final class CommentPosition extends Position implements IProjectionPosition {
- CommentPosition(int offset, int length) {
- super(offset, length);
- }
-
- /*
- * @see org.eclipse.jface.text.source.projection.IProjectionPosition#computeFoldingRegions(org.eclipse.jface.text.IDocument)
- */
- @Override
- public IRegion[] computeProjectionRegions(IDocument document) throws BadLocationException {
- DocumentCharacterIterator sequence= new DocumentCharacterIterator(document, offset, offset + length);
- int prefixEnd= 0;
- int contentStart= findFirstContent(sequence, prefixEnd);
-
- int firstLine= document.getLineOfOffset(offset + prefixEnd);
- int captionLine= document.getLineOfOffset(offset + contentStart);
- int lastLine= document.getLineOfOffset(offset + length);
-
- Assert.isTrue(firstLine <= captionLine, "first folded line is greater than the caption line"); //$NON-NLS-1$
- Assert.isTrue(captionLine <= lastLine, "caption line is greater than the last folded line"); //$NON-NLS-1$
-
- IRegion preRegion;
- if (firstLine < captionLine) {
- int preOffset= document.getLineOffset(firstLine);
- IRegion preEndLineInfo= document.getLineInformation(captionLine);
- int preEnd= preEndLineInfo.getOffset();
- preRegion= new Region(preOffset, preEnd - preOffset);
- } else {
- preRegion= null;
- }
-
- if (captionLine < lastLine) {
- int postOffset= document.getLineOffset(captionLine + 1);
- int postLength= offset + length - postOffset;
- if (postLength > 0) {
- IRegion postRegion= new Region(postOffset, postLength);
- if (preRegion == null)
- return new IRegion[] { postRegion };
- return new IRegion[] { preRegion, postRegion };
- }
- }
-
- if (preRegion != null)
- return new IRegion[] { preRegion };
-
- return null;
- }
-
- /**
- * Finds the offset of the first identifier part within content
.
- * Returns 0 if none is found.
- *
- * @param content the content to search
- * @param prefixEnd the end of the prefix
- * @return the first index of a unicode identifier part, or zero if none can
- * be found
- */
- private int findFirstContent(final CharSequence content, int prefixEnd) {
- int lenght= content.length();
- for (int i= prefixEnd; i < lenght; i++) {
- if (Character.isUnicodeIdentifierPart(content.charAt(i)))
- return i;
- }
- return 0;
- }
-
- /*
- * @see org.eclipse.jface.text.source.projection.IProjectionPosition#computeCaptionOffset(org.eclipse.jface.text.IDocument)
- */
- @Override
- public int computeCaptionOffset(IDocument document) throws BadLocationException {
- DocumentCharacterIterator sequence= new DocumentCharacterIterator(document, offset, offset + length);
- return findFirstContent(sequence, 0);
- }
- }
-
/**
* Projection position that will return two foldable regions: one folding away
* the lines before the one containing the simple name of the java element, one
@@ -1006,104 +1065,7 @@ private void processCompilationUnit(ICompilationUnit unit, FoldingStructureCompu
parser.setResolveBindings(true);
CompilationUnit ast = (CompilationUnit) parser.createAST(null);
- ast.accept(new ASTVisitor() {
- @Override
- public boolean visit(MethodDeclaration node) {
- processMethodDeclaration(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(FieldDeclaration node) {
- processFieldDeclaration(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(IfStatement node) {
- processIfStatement(node, ctx);
- return false; // Prevents visiting children since we handle them explicitly
- }
-
- @Override
- public boolean visit(WhileStatement node) {
- processStatement(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(ForStatement node) {
- processStatement(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(EnhancedForStatement node) {
- processStatement(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(DoStatement node) {
- processStatement(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(SwitchStatement node) {
- processStatement(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(TryStatement node) {
- processTryStatement(node, ctx);
- return false; // We handle the catch and finally blocks explicitly
- }
-
- @Override
- public boolean visit(SynchronizedStatement node) {
- processStatement(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(LambdaExpression node) {
- processLambdaExpression(node, ctx);
- return false; // Prevents visiting children since we handle them explicitly
- }
-
- @Override
- public boolean visit(TypeDeclaration node) {
- processTypeDeclaration(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(AnonymousClassDeclaration node) {
- processAnonymousClassDeclaration(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(EnumDeclaration node) {
- processEnumDeclaration(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(Initializer node) {
- processInitializer(node, ctx);
- return super.visit(node);
- }
-
- @Override
- public boolean visit(Javadoc node) {
- processComment(node, ctx);
- return false; // No need to visit children of Javadoc
- }
-
- });
+ ast.accept(new FoldingVisitor(ctx));
} catch (JavaModelException e) {
e.printStackTrace();
}
@@ -1136,35 +1098,6 @@ private void processMethodDeclaration(MethodDeclaration node, FoldingStructureCo
}
}
- private void processFieldDeclaration(FieldDeclaration node, FoldingStructureComputationContext ctx) {
- createFoldingRegion(node, ctx, ctx.collapseMembers());
- if (node.getJavadoc() != null) {
- processComment(node.getJavadoc(), ctx);
- }
- }
-
- private void processTypeDeclaration(TypeDeclaration node, FoldingStructureComputationContext ctx) {
- createFoldingRegion(node, ctx, ctx.collapseMembers());
- if (node.getJavadoc() != null) {
- processComment(node.getJavadoc(), ctx);
- }
- }
-
- private void processAnonymousClassDeclaration(AnonymousClassDeclaration node, FoldingStructureComputationContext ctx) {
- createFoldingRegion(node, ctx, ctx.collapseMembers());
- }
-
- private void processEnumDeclaration(EnumDeclaration node, FoldingStructureComputationContext ctx) {
- createFoldingRegion(node, ctx, ctx.collapseMembers());
- if (node.getJavadoc() != null) {
- processComment(node.getJavadoc(), ctx);
- }
- }
-
- private void processInitializer(Initializer node, FoldingStructureComputationContext ctx) {
- createFoldingRegion(node, ctx, ctx.collapseMembers());
- }
-
private void processIfStatement(IfStatement node, FoldingStructureComputationContext ctx) {
createFoldingRegion(node, ctx, ctx.collapseMembers());
processStatement(node.getThenStatement(), ctx);
@@ -1183,31 +1116,20 @@ private void processElseStatement(Statement elseStmt, FoldingStructureComputatio
}
}
-
- private void processTryStatement(TryStatement node, FoldingStructureComputationContext ctx) {
- processStatement(node.getBody(), ctx);
- for (Object catchClauseObj : node.catchClauses()) {
- CatchClause catchClause = (CatchClause) catchClauseObj;
- processStatement(catchClause.getBody(), ctx);
- }
- if (node.getFinally() != null) {
- processStatement(node.getFinally(), ctx);
- }
- }
-
- private void processLambdaExpression(LambdaExpression node, FoldingStructureComputationContext ctx) {
- if (node.getBody() instanceof Block) {
- createFoldingRegion(node.getBody(), ctx, ctx.collapseMembers());
- }
- }
-
private void processStatement(Statement node, FoldingStructureComputationContext ctx) {
if (node == null) {
return;
}
- createFoldingRegion(node, ctx, ctx.collapseMembers());
+ if (node instanceof Block || node instanceof IfStatement || node instanceof WhileStatement ||
+ node instanceof ForStatement || node instanceof EnhancedForStatement ||
+ node instanceof DoStatement || node instanceof SwitchStatement ||
+ node instanceof TryStatement || node instanceof SynchronizedStatement) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ }
+ node.accept(new FoldingVisitor(ctx));
}
+
private void createFoldingRegion(ASTNode node, FoldingStructureComputationContext ctx, boolean collapse) {
int start = node.getStartPosition();
int end = calculateEndPosition(node, ctx);
@@ -1215,6 +1137,12 @@ private void createFoldingRegion(ASTNode node, FoldingStructureComputationContex
if (end <= start) {
return;
}
+ if (node instanceof MethodDeclaration) {
+ Block body = ((MethodDeclaration) node).getBody();
+ if (body != null) {
+ start = body.getStartPosition();
+ }
+ }
int length = end - start;
IRegion region = new Region(start, length);
@@ -1227,6 +1155,7 @@ private void createFoldingRegion(ASTNode node, FoldingStructureComputationContex
}
}
+
private int calculateEndPosition(ASTNode node, FoldingStructureComputationContext ctx) {
int end = node.getStartPosition() + node.getLength();
@@ -1248,6 +1177,19 @@ private int calculateEndPosition(ASTNode node, FoldingStructureComputationContex
return end;
}
+ /**
+ * Aligns region
to start and end at a line offset. The region's start is
+ * decreased to the next line offset, and the end offset increased to the next line start or the
+ * end of the document. null
is returned if region
is
+ * null
itself or does not comprise at least one line delimiter, as a single line
+ * cannot be folded.
+ *
+ * @param region the region to align, may be null
+ * @param ctx the folding context
+ * @return a region equal or greater than region
that is aligned with line
+ * offsets, null
if the region is too small to be foldable (e.g. covers
+ * only one line)
+ */
protected IRegion alignRegion(IRegion region, FoldingStructureComputationContext ctx) {
if (region == null) {
return null;
@@ -1289,6 +1231,14 @@ private void processComment(Javadoc node, FoldingStructureComputationContext ctx
}
}
+ /**
+ * Creates a comment folding position from an
+ * {@link #alignRegion(IRegion, DefaultJavaFoldingStructureProvider.FoldingStructureComputationContext) aligned}
+ * region.
+ *
+ * @param aligned an aligned region
+ * @return a folding position corresponding to aligned
+ */
protected Position createCommentPosition(IRegion aligned) {
return new Position(aligned.getOffset(), aligned.getLength());
}