1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-29 19:45:01 +02:00

174597: Code folding of compound statements (Patch by Elazar Leibovich)

This commit is contained in:
Anton Leherbauer 2008-01-24 09:53:01 +00:00
parent b6c5c6fd94
commit 0a8351dce8
7 changed files with 268 additions and 27 deletions

View file

@ -1,7 +1,7 @@
/*
* header comment
*/
#define ONE
#define MULTI_LINE_MACRO(x) \
if (DBG) { \
printf(x); \
@ -14,7 +14,7 @@
#elif X
// X
#else
# if 1
# if ONE
# if 0
# if 1
//
@ -72,5 +72,39 @@ int
main(int argc,
char *argv[])
{
int MyI = 0,j = 0;
if (0==0) {
puts("Wow ");
} else {
j = j;
}
for (MyI = 0; MyI < 10; ++MyI) {
printf("%d\n",MyI);
}
while (0) {
puts("nothinghere");
}
switch (1) {
case 1:
puts("ab");
break;
case 2:
puts("cd");
default:
puts("xy");
}
do {
puts("tryagain");
} while (0);
if (MyI==0) {
return 1;
}
return 0;
}
enum E {
e1,
e2,
e3
};

View file

@ -7,6 +7,7 @@
*
* Contributors:
* Anton Leherbauer (Wind River Systems) - initial API and implementation
* Elazar Leibovich (The Open University) - extra folding test
*******************************************************************************/
package org.eclipse.cdt.ui.tests.text;
@ -80,6 +81,7 @@ public class FoldingTest extends TestCase {
IPreferenceStore store= CUIPlugin.getDefault().getPreferenceStore();
store.setValue(PreferenceConstants.EDITOR_FOLDING_ENABLED, true);
store.setValue(PreferenceConstants.EDITOR_FOLDING_STATEMENTS, true);
store.setValue(PreferenceConstants.EDITOR_FOLDING_PREPROCESSOR_BRANCHES_ENABLED, true);
store.setValue(PreferenceConstants.EDITOR_FOLDING_INACTIVE_CODE, false);
store.setValue(PreferenceConstants.EDITOR_FOLDING_HEADERS, false);
@ -119,12 +121,13 @@ public class FoldingTest extends TestCase {
assertEquals(expectedEndLine, actualEndLine);
if (exp instanceof IProjectionPosition) {
int expectedCaptionOffset= ((IProjectionPosition)exp).computeCaptionOffset(document);
int expectedCaptionLine= document.getLineOfOffset(exp.getOffset() + expectedCaptionOffset);
int actualCaptionLine= actualStartLine;
if (act instanceof IProjectionPosition) {
int actualCaptionOffset= ((IProjectionPosition)act).computeCaptionOffset(document);
assertEquals(expectedCaptionOffset, actualCaptionOffset);
} else {
assertEquals(expectedCaptionOffset, 0);
actualCaptionLine= document.getLineOfOffset(exp.getOffset() + actualCaptionOffset);
}
assertEquals(expectedCaptionLine, actualCaptionLine);
}
}
}
@ -152,7 +155,20 @@ public class FoldingTest extends TestCase {
Position position= positions[i];
int startLine= document.getLineOfOffset(position.getOffset());
int endLine= document.getLineOfOffset(position.getOffset()+position.getLength()-1);
buf.append("\tcreatePosition(" + startLine + ", " + endLine + "),\n");
int captionLine= startLine;
if (position instanceof IProjectionPosition) {
final int captionOffset = ((IProjectionPosition)position).computeCaptionOffset(document);
captionLine= document.getLineOfOffset(position.getOffset() + captionOffset);
}
buf.append("\tcreatePosition(");
buf.append(startLine);
buf.append(", ");
buf.append(endLine);
if (captionLine != startLine) {
buf.append(", ");
buf.append(captionLine);
}
buf.append("),\n");
}
buf.append("};\n");
return buf.toString();
@ -179,7 +195,7 @@ public class FoldingTest extends TestCase {
public void testInitialFolding() throws BadLocationException {
Position[] actual= getFoldingPositions();
Position[] expected= new Position[] {
createPosition(0, 2),
createPosition(0, 2, 1),
createPosition(4, 7),
createPosition(9, 12),
createPosition(10, 12),
@ -190,7 +206,7 @@ public class FoldingTest extends TestCase {
createPosition(18, 20),
createPosition(21, 25),
createPosition(22, 24),
createPosition(29, 31),
createPosition(29, 31, 30),
createPosition(34, 35),
createPosition(35, 40),
createPosition(36, 38),
@ -200,9 +216,20 @@ public class FoldingTest extends TestCase {
createPosition(57, 59),
createPosition(61, 63),
createPosition(65, 67),
createPosition(70, 75, 71),
createPosition(70, 103, 71),
createPosition(75, 76),
createPosition(77, 79),
createPosition(80, 82),
createPosition(83, 85),
createPosition(86, 94),
createPosition(87, 89),
createPosition(90, 91),
createPosition(92, 93),
createPosition(95, 97),
createPosition(99, 101),
createPosition(105, 109),
};
if (false) System.out.println(toString(actual));
// assertEquals(toString(expected), toString(actual));
assertEqualPositions(expected, actual);
}
@ -214,9 +241,9 @@ public class FoldingTest extends TestCase {
Position[] actual= getFoldingPositions();
Position[] expected= new Position[] {
createPosition(0, 2),
createPosition(0, 2, 1),
createPosition(4, 7),
createPosition(29, 31),
createPosition(29, 31, 30),
createPosition(35, 40),
createPosition(42, 46),
createPosition(48, 55),
@ -224,9 +251,20 @@ public class FoldingTest extends TestCase {
createPosition(57, 59),
createPosition(61, 63),
createPosition(65, 67),
createPosition(70, 75, 71),
createPosition(70, 103, 71),
createPosition(75, 76),
createPosition(77, 79),
createPosition(80, 82),
createPosition(83, 85),
createPosition(86, 94),
createPosition(87, 89),
createPosition(90, 91),
createPosition(92, 93),
createPosition(95, 97),
createPosition(99, 101),
createPosition(105, 109),
};
if (false) System.out.println(toString(actual));
// assertEquals(toString(expected), toString(actual));
assertEqualPositions(expected, actual);
}

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2007 QNX Software Systems and others.
* Copyright (c) 2000, 2008 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -8,6 +8,7 @@
* Contributors:
* IBM Corporation - initial API and implementation
* Anton Leherbauer (Wind River Systems)
* Elazar Leibovich (IDF) - Code folding of compound statements (bug 174597)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text.folding;
@ -74,6 +75,7 @@ public class DefaultCFoldingPreferenceBlock implements ICFoldingPreferenceBlock
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_FOLDING_HEADERS));
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_FOLDING_INACTIVE_CODE));
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_FOLDING_PREPROCESSOR_BRANCHES_ENABLED));
overlayKeys.add(new OverlayPreferenceStore.OverlayKey(OverlayPreferenceStore.BOOLEAN, PreferenceConstants.EDITOR_FOLDING_STATEMENTS));
return (OverlayKey[]) overlayKeys.toArray(new OverlayKey[overlayKeys.size()]);
}
@ -92,6 +94,7 @@ public class DefaultCFoldingPreferenceBlock implements ICFoldingPreferenceBlock
inner.setLayout(layout);
addCheckBox(inner, FoldingMessages.DefaultCFoldingPreferenceBlock_preprocessor_enabled, PreferenceConstants.EDITOR_FOLDING_PREPROCESSOR_BRANCHES_ENABLED, 1);
addCheckBox(inner, FoldingMessages.DefaultCFoldingPreferenceBlock_statements_enabled, PreferenceConstants.EDITOR_FOLDING_STATEMENTS, 1);
ControlFactory.createEmptySpace(inner);
Composite group= ControlFactory.createGroup(inner, FoldingMessages.DefaultCFoldingPreferenceBlock_title, 1);
@ -101,7 +104,7 @@ public class DefaultCFoldingPreferenceBlock implements ICFoldingPreferenceBlock
addCheckBox(group, FoldingMessages.DefaultCFoldingPreferenceBlock_methods, PreferenceConstants.EDITOR_FOLDING_METHODS, 0);
addCheckBox(group, FoldingMessages.DefaultCFoldingPreferenceBlock_structures, PreferenceConstants.EDITOR_FOLDING_STRUCTURES, 0);
addCheckBox(group, FoldingMessages.DefaultCFoldingPreferenceBlock_comments, PreferenceConstants.EDITOR_FOLDING_COMMENTS, 0);
addCheckBox(group, FoldingMessages.DefaultCFoldingPreferenceBlock_headers, PreferenceConstants.EDITOR_FOLDING_HEADERS, 0);
addCheckBox(group, FoldingMessages.DefaultCFoldingPreferenceBlock_headers, PreferenceConstants.EDITOR_FOLDING_HEADERS, 0);
fInactiveCodeFoldingCheckBox= addCheckBox(group, FoldingMessages.DefaultCFoldingPreferenceBlock_inactive_code, PreferenceConstants.EDITOR_FOLDING_INACTIVE_CODE, 0);
return inner;

View file

@ -9,6 +9,7 @@
* IBM Corporation - initial API and implementation
* Anton Leherbauer (Wind River Systems)
* Markus Schorn (Wind River Systems)
* Elazar Leibovich (IDF) - Code folding of compound statements (bug 174597)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text.folding;
@ -50,6 +51,16 @@ import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTDefaultStatement;
import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElifStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorElseStatement;
@ -58,7 +69,10 @@ import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfdefStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIfndefStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
import org.eclipse.cdt.core.model.CModelException;
import org.eclipse.cdt.core.model.CoreModel;
import org.eclipse.cdt.core.model.ICElement;
@ -647,6 +661,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
private int fMinCommentLines= 1;
private boolean fPreprocessorBranchFoldingEnabled= true;
private boolean fStatementsFoldingEnabled= false;
private boolean fCommentFoldingEnabled= true;
private ICReconcilingListener fReconilingListener;
@ -810,7 +825,8 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
fCollapseComments= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_COMMENTS);
fCollapseInactiveCode= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_INACTIVE_CODE);
fPreprocessorBranchFoldingEnabled= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_PREPROCESSOR_BRANCHES_ENABLED);
fCommentFoldingEnabled= true;
fStatementsFoldingEnabled= store.getBoolean(PreferenceConstants.EDITOR_FOLDING_STATEMENTS);
fCommentFoldingEnabled = true;
}
private void update(FoldingStructureComputationContext ctx) {
@ -1041,7 +1057,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
// ignore
}
}
if (fPreprocessorBranchFoldingEnabled) {
if (fPreprocessorBranchFoldingEnabled || fStatementsFoldingEnabled) {
IASTTranslationUnit ast= ctx.getAST();
if (ast == null) {
final ASTProvider astProvider= CUIPlugin.getDefault().getASTProvider();
@ -1080,9 +1096,129 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
}
return false;
}
private static class ModifiableRegionExtra extends ModifiableRegion {
/*
* A modifiable region with extra information about the region it holds.
* It tells us whether or not to include the last line of the region
*/
public boolean inclusive;
}
/**
* Compute folding structure of the preprocessor branches for the given AST.
* Computes folding structure for preprocessor branches for the given AST.
*
* @param ast
* @param ctx
*/
private void computeStatementFoldingStructure(IASTTranslationUnit ast, FoldingStructureComputationContext ctx) {
final Stack iral = new Stack();
ast.accept(new ASTVisitor() {
{
shouldVisitStatements = true;
}
public int visit(IASTStatement statement) {
// if it's not part of the displayed - file, we don't need it
if (!statement.isPartOfTranslationUnitFile())
return PROCESS_SKIP;// we neither need its descendants
try {
ModifiableRegionExtra mr;
IASTFileLocation fl;
if (statement instanceof IASTIfStatement) {
IASTIfStatement ifstmt = (IASTIfStatement) statement;
IASTStatement tmp;
mr = new ModifiableRegionExtra();
tmp = ifstmt.getThenClause();
if (tmp==null) return PROCESS_CONTINUE;
fl = tmp.getFileLocation();
mr.setLength(fl.getNodeLength());
mr.setOffset(fl.getNodeOffset());
mr.inclusive = false;
tmp = ifstmt.getElseClause();
if (tmp==null) {
mr.inclusive = true;
iral.push(mr);
return PROCESS_CONTINUE;
}
iral.push(mr);
mr = new ModifiableRegionExtra();
fl = tmp.getFileLocation();
mr.setLength(fl.getNodeLength());
mr.setOffset(fl.getNodeOffset());
mr.inclusive = true;
iral.push(mr);
}
mr = new ModifiableRegionExtra();
mr.inclusive = true;
if (statement instanceof IASTDoStatement)
mr.inclusive = false;
if (statement instanceof IASTSwitchStatement) {
IASTStatement switchstmt = ((IASTSwitchStatement)statement).getBody();
if (switchstmt instanceof IASTCompoundStatement) {
IASTStatement[] stmts = ((IASTCompoundStatement)switchstmt).getStatements();
boolean pushedMR = false;
for (int i = 0; i < stmts.length; i++) {
IASTStatement tmpstmt = stmts[i];
ModifiableRegionExtra tmpmr;
if (!(tmpstmt instanceof IASTCaseStatement || tmpstmt instanceof IASTDefaultStatement)) {
if (!pushedMR) return PROCESS_SKIP;
IASTFileLocation tmpfl = tmpstmt.getFileLocation();
tmpmr = (ModifiableRegionExtra) iral.peek();
tmpmr.setLength(tmpfl.getNodeLength()+tmpfl.getNodeOffset()-tmpmr.getOffset());
if (tmpstmt instanceof IASTBreakStatement) pushedMR = false;
continue;
}
IASTFileLocation tmpfl;
tmpmr = new ModifiableRegionExtra();
tmpmr.inclusive = true;
if (tmpstmt instanceof IASTCaseStatement) {
IASTCaseStatement casestmt = (IASTCaseStatement) tmpstmt;
tmpfl = casestmt.getExpression().getFileLocation();
tmpmr.setOffset(tmpfl.getNodeOffset());
tmpmr.setLength(tmpfl.getNodeLength());
} else if (tmpstmt instanceof IASTDefaultStatement) {
IASTDefaultStatement defstmt = (IASTDefaultStatement) tmpstmt;
tmpfl = defstmt.getFileLocation();
tmpmr.setOffset(tmpfl.getNodeOffset()+tmpfl.getNodeLength());
tmpmr.setLength(0);
}
iral.push(tmpmr);
pushedMR = true;
}
}
}
if (statement instanceof IASTForStatement ||
statement instanceof IASTWhileStatement ||
statement instanceof IASTDoStatement ||
statement instanceof IASTSwitchStatement) {
fl = statement.getFileLocation();
mr.setLength(fl.getNodeLength());
mr.setOffset(fl.getNodeOffset());
iral.push(mr);
}
return PROCESS_CONTINUE;
} catch (Throwable e) {
CCorePlugin.log(e);
return PROCESS_CONTINUE;
}
}
});
while (!iral.empty()) {
ModifiableRegionExtra mr = (ModifiableRegionExtra) iral.pop();
IRegion aligned = alignRegion(mr, ctx,mr.inclusive);
if (aligned != null) {
Position alignedPos= new Position(aligned.getOffset(), aligned.getLength());
ctx.addProjectionRange(new CProjectionAnnotation(false, computeKey(mr, ctx), false), alignedPos);
}
}
}
/**
* Compute folding structure of things related to the AST tree. Currently it
* computes the folding structure for: preprocessor branches for the given
* AST. Also, it computes statements folding (if/else do/while for and
* switch)
*
* @param ast
* @param ctx
@ -1095,22 +1231,38 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
if (fileName == null) {
return;
}
List branches= new ArrayList();
if (fStatementsFoldingEnabled)
computeStatementFoldingStructure(ast, ctx);
if (fPreprocessorBranchFoldingEnabled)
computePreprocessorFoldingStructure(ast, ctx, fileName);
}
/**
* Computes folding structure for preprocessor branches for the given AST.
*
* @param ast
* @param ctx
* @param fileName
*/
private void computePreprocessorFoldingStructure(IASTTranslationUnit ast,
FoldingStructureComputationContext ctx, String fileName) {
List branches = new ArrayList();
Stack branchStack = new Stack();
IASTPreprocessorStatement[] preprocStmts = ast.getAllPreprocessorStatements();
for (int i = 0; i < preprocStmts.length; i++) {
IASTPreprocessorStatement statement = preprocStmts[i];
if (!fileName.equals(statement.getContainingFilename())) {
if (!statement.isPartOfTranslationUnitFile()) {
// preprocessor directive is from a different file
continue;
}
IASTNodeLocation[] nodeLocations = statement.getNodeLocations();
if (nodeLocations.length != 1) {
IASTNodeLocation stmtLocation= statement.getFileLocation();
if (stmtLocation == null) {
continue;
}
IASTNodeLocation stmtLocation= nodeLocations[0];
if (statement instanceof IASTPreprocessorIfStatement) {
IASTPreprocessorIfStatement ifStmt = (IASTPreprocessorIfStatement)statement;
branchStack.push(new Branch(stmtLocation.getNodeOffset(), ifStmt.taken()));
@ -1311,6 +1463,7 @@ public class DefaultCFoldingStructureProvider implements ICFoldingStructureProvi
case ICElement.C_STRUCT:
case ICElement.C_CLASS:
case ICElement.C_UNION:
case ICElement.C_ENUMERATION:
case ICElement.C_TEMPLATE_STRUCT:
case ICElement.C_TEMPLATE_CLASS:
case ICElement.C_TEMPLATE_UNION:

View file

@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2000, 2006 QNX Software Systems and others.
* Copyright (c) 2000, 2008 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@ -7,6 +7,7 @@
*
* Contributors:
* IBM Corporation - initial API and implementation
* Elazar Leibovich (IDF) - Code folding of compound statements (bug 174597)
*******************************************************************************/
package org.eclipse.cdt.internal.ui.text.folding;
@ -30,6 +31,7 @@ public final class FoldingMessages extends NLS {
public static String DefaultCFoldingPreferenceBlock_inactive_code;
public static String DefaultCFoldingPreferenceBlock_preprocessor_enabled;
public static String EmptyCFoldingPreferenceBlock_emptyCaption;
public static String DefaultCFoldingPreferenceBlock_statements_enabled;
static {
NLS.initializeMessages(BUNDLE_NAME, FoldingMessages.class);

View file

@ -1,5 +1,5 @@
###############################################################################
# Copyright (c) 2000, 2007 IBM Corporation and others.
# Copyright (c) 2000, 2008 IBM Corporation and others.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
@ -8,6 +8,7 @@
# Contributors:
# IBM Corporation - initial API and implementation
# Anton Leherbauer (Wind River Systems)
# Elazar Leibovich (IDF) - Code folding of compound statements (bug 174597)
###############################################################################
@ -20,5 +21,6 @@ DefaultCFoldingPreferenceBlock_comments= &Comments
DefaultCFoldingPreferenceBlock_headers= &Header Comments
DefaultCFoldingPreferenceBlock_inactive_code= &Inactive Preprocessor Branches
DefaultCFoldingPreferenceBlock_preprocessor_enabled= Enable folding of preprocessor branches (#if/#endif)
DefaultCFoldingPreferenceBlock_statements_enabled= Enable folding of control flow statements (if/else, do/while, for, switch)
EmptyCFoldingPreferenceBlock_emptyCaption=

View file

@ -10,6 +10,7 @@
* QNX Software System
* Anton Leherbauer (Wind River Systems)
* Sergey Prigogin (Google)
* Elazar Leibovich (IDF) - Code folding of compound statements (bug 174597)
*******************************************************************************/
package org.eclipse.cdt.ui;
@ -812,6 +813,14 @@ public class PreferenceConstants {
*/
public static final String EDITOR_FOLDING_STRUCTURES= "editor_folding_default_structures"; //$NON-NLS-1$
/**
* A named preference that stores the value for statements folding (if/else, do/while, for, switch statements)
* <p>
* Value is of type <code>Boolean</code>.
* </p>
*/
public static final String EDITOR_FOLDING_STATEMENTS = "editor_folding_statements"; //$NON-NLS-1$
/**
* A named preference that stores the value for functions folding for the default folding provider.
* <p>