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 e212f37c39a..deda79970ac 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
@@ -68,7 +68,30 @@
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.compiler.ITerminalSymbols;
import org.eclipse.jdt.core.compiler.InvalidInputException;
+import org.eclipse.jdt.core.dom.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.ASTParser;
+import org.eclipse.jdt.core.dom.ASTVisitor;
+import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
+import org.eclipse.jdt.core.dom.Block;
+import org.eclipse.jdt.core.dom.CatchClause;
import org.eclipse.jdt.core.dom.CompilationUnit;
+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;
+import org.eclipse.jdt.core.dom.Javadoc;
+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.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;
@@ -497,7 +520,6 @@ public IRegion[] computeProjectionRegions(IDocument document) throws BadLocation
IRegion preRegion;
if (firstLine < captionLine) {
-// preRegion= new Region(offset + prefixEnd, contentStart - prefixEnd);
int preOffset= document.getLineOffset(firstLine);
IRegion preEndLineInfo= document.getLineInformation(captionLine);
int preEnd= preEndLineInfo.getOffset();
@@ -541,33 +563,6 @@ private int findFirstContent(final CharSequence content, int prefixEnd) {
return 0;
}
-// /**
-// * Finds the offset of the first identifier part within content
.
-// * Returns 0 if none is found.
-// *
-// * @param content the content to search
-// * @return the first index of a unicode identifier part, or zero if none can
-// * be found
-// */
-// private int findPrefixEnd(final CharSequence content) {
-// // return the index after the leading '/*' or '/**'
-// int len= content.length();
-// int i= 0;
-// while (i < len && isWhiteSpace(content.charAt(i)))
-// i++;
-// if (len >= i + 2 && content.charAt(i) == '/' && content.charAt(i + 1) == '*')
-// if (len >= i + 3 && content.charAt(i + 2) == '*')
-// return i + 3;
-// else
-// return i + 2;
-// else
-// return i;
-// }
-//
-// private boolean isWhiteSpace(char c) {
-// return c == ' ' || c == '\t';
-// }
-
/*
* @see org.eclipse.jface.text.source.projection.IProjectionPosition#computeCaptionOffset(org.eclipse.jface.text.IDocument)
*/
@@ -990,31 +985,326 @@ private void update(FoldingStructureComputationContext ctx) {
}
private void computeFoldingStructure(FoldingStructureComputationContext ctx) {
- IParent parent= (IParent) fInput;
- try {
- if (!(fInput instanceof ISourceReference))
- return;
- String source= ((ISourceReference)fInput).getSource();
- if (source == null)
- return;
+ if (fInput instanceof ICompilationUnit) {
+ processCompilationUnit((ICompilationUnit) fInput, ctx);
+ } else if (fInput instanceof ISourceReference) {
+ processSourceReference((ISourceReference) fInput, ctx);
+ }
+ }
- ctx.getScanner().setSource(source.toCharArray());
- computeFoldingStructure(parent.getChildren(), ctx);
- } catch (JavaModelException x) {
- }
+ private void processCompilationUnit(ICompilationUnit unit, FoldingStructureComputationContext ctx) {
+ try {
+ String source = unit.getSource();
+ if (source == null) {
+ return;
+ }
+
+ ctx.getScanner().setSource(source.toCharArray());
+
+ ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
+ parser.setSource(unit);
+ 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
+ }
+
+ });
+ } catch (JavaModelException e) {
+ e.printStackTrace();
+ }
}
- private void computeFoldingStructure(IJavaElement[] elements, FoldingStructureComputationContext ctx) throws JavaModelException {
- for (IJavaElement element : elements) {
- computeFoldingStructure(element, ctx);
+ private void processSourceReference(ISourceReference sourceRef, FoldingStructureComputationContext ctx) {
+ try {
+ String source = sourceRef.getSource();
+ if (source == null) {
+ return;
+ }
+
+ ctx.getScanner().setSource(source.toCharArray());
+
+ if (fInput instanceof IParent) {
+ IParent parent = (IParent) fInput;
+ computeFoldingStructure(parent.getChildren(), ctx);
+ } else {
+ computeFoldingStructure(fInput, ctx);
+ }
+ } catch (JavaModelException e) {
+ e.printStackTrace();
+ }
+ }
- if (element instanceof IParent) {
- IParent parent= (IParent) element;
- computeFoldingStructure(parent.getChildren(), ctx);
- }
- }
+ private void processMethodDeclaration(MethodDeclaration node, FoldingStructureComputationContext ctx) {
+ createFoldingRegion(node, ctx, ctx.collapseMembers());
+ if (node.getJavadoc() != null) {
+ processComment(node.getJavadoc(), ctx);
+ }
+ }
+
+ 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);
+ Statement elseStmt = node.getElseStatement();
+ if (elseStmt != null) {
+ processElseStatement(elseStmt, ctx);
+ }
+ }
+
+ private void processElseStatement(Statement elseStmt, FoldingStructureComputationContext ctx) {
+ if (elseStmt instanceof IfStatement) {
+ processIfStatement((IfStatement) elseStmt, ctx);
+ } else {
+ createFoldingRegion(elseStmt, ctx, ctx.collapseMembers());
+ processStatement(elseStmt, ctx);
+ }
+ }
+
+
+ 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());
+ }
+
+ private void createFoldingRegion(ASTNode node, FoldingStructureComputationContext ctx, boolean collapse) {
+ int start = node.getStartPosition();
+ int end = calculateEndPosition(node, ctx);
+
+ if (end <= start) {
+ return;
+ }
+
+ int length = end - start;
+ 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(collapse, null, false);
+ ctx.addProjectionRange(annotation, position);
+ }
+ }
+
+ private int calculateEndPosition(ASTNode node, FoldingStructureComputationContext ctx) {
+ int end = node.getStartPosition() + node.getLength();
+
+ try {
+ IDocument document = ctx.getDocument();
+ int endLine = document.getLineOfOffset(end - 1);
+ int lineEndOffset = document.getLineOffset(endLine) + document.getLineLength(endLine);
+
+ if (end < lineEndOffset) {
+ String remainingText = document.get(end, lineEndOffset - end).trim();
+ if (!remainingText.isEmpty()) {
+ // Additional logic if needed
+ }
+ }
+ } catch (BadLocationException e) {
+ e.printStackTrace();
+ }
+
+ return end;
+ }
+
+ protected IRegion alignRegion(IRegion region, FoldingStructureComputationContext ctx) {
+ if (region == null) {
+ return null;
+ }
+
+ IDocument document = ctx.getDocument();
+
+ try {
+ int startOffset = region.getOffset();
+ int endOffset = region.getOffset() + region.getLength();
+ int startLine = document.getLineOfOffset(startOffset);
+ int endLine = document.getLineOfOffset(endOffset - 1);
+
+ if (startLine > endLine) {
+ return null;
+ }
+
+ int alignedStartOffset = document.getLineOffset(startLine);
+ int alignedEndOffset = endOffset;
+
+ return new Region(alignedStartOffset, alignedEndOffset - alignedStartOffset);
+ } catch (BadLocationException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private void processComment(Javadoc node, FoldingStructureComputationContext ctx) {
+ int start = node.getStartPosition();
+ int length = node.getLength();
+
+ IRegion region = new Region(start, length);
+ IRegion aligned = alignRegion(region, ctx);
+
+ if (aligned != null) {
+ Position position = createCommentPosition(aligned);
+ JavaProjectionAnnotation annotation = new JavaProjectionAnnotation(ctx.collapseJavadoc(), null, true);
+ ctx.addProjectionRange(annotation, position);
+ }
+ }
+
+ protected Position createCommentPosition(IRegion aligned) {
+ return new Position(aligned.getOffset(), aligned.getLength());
}
+ private void computeFoldingStructure(IJavaElement[] elements, FoldingStructureComputationContext ctx) throws JavaModelException {
+ for (IJavaElement element : elements) {
+ computeFoldingStructure(element, ctx);
+
+ if (element instanceof IParent) {
+ IParent parent = (IParent) element;
+ computeFoldingStructure(parent.getChildren(), ctx);
+ }
+ }
+ }
+
+
/**
* Computes the folding structure for a given {@link IJavaElement java element}. Computed
* projection annotations are
@@ -1234,18 +1524,6 @@ private IRegion computeHeaderComment(FoldingStructureComputationContext ctx) thr
return null;
}
- /**
- * 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 final Position createCommentPosition(IRegion aligned) {
- return new CommentPosition(aligned.getOffset(), aligned.getLength());
- }
-
/**
* Creates a folding position that remembers its member from an
* {@link #alignRegion(IRegion, DefaultJavaFoldingStructureProvider.FoldingStructureComputationContext) aligned}
@@ -1259,47 +1537,6 @@ protected final Position createMemberPosition(IRegion aligned, IMember member) {
return new JavaElementPosition(aligned.getOffset(), aligned.getLength(), member);
}
- /**
- * 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 final IRegion alignRegion(IRegion region, FoldingStructureComputationContext ctx) {
- if (region == null)
- return null;
-
- IDocument document= ctx.getDocument();
-
- try {
-
- int start= document.getLineOfOffset(region.getOffset());
- int end= document.getLineOfOffset(region.getOffset() + region.getLength());
- if (start >= end)
- return null;
-
- int offset= document.getLineOffset(start);
- int endOffset;
- if (document.getNumberOfLines() > end + 1)
- endOffset= document.getLineOffset(end + 1);
- else
- endOffset= document.getLineOffset(end) + document.getLineLength(end);
-
- return new Region(offset, endOffset - offset);
-
- } catch (BadLocationException x) {
- // concurrent modification
- return null;
- }
- }
-
private ProjectionAnnotationModel getModel() {
return fEditor.getAdapter(ProjectionAnnotationModel.class);
}