1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 17:56:01 +02:00

Bugs 277624 and 277625.

This commit is contained in:
Sergey Prigogin 2009-05-28 09:13:11 +00:00
parent 8d86fb4a8f
commit ef3dcbc656
7 changed files with 207 additions and 102 deletions

View file

@ -10,11 +10,10 @@ const SimpleStruct simpleStruct =
#define SIZEOF( A, B ) sizeof( A.B ) #define SIZEOF( A, B ) sizeof( A.B )
#define FOREVER \ #define FOREVER \
for(;;)\ for(;;)\
{\ {\
\ \
} }
}
const OtherStruct array[] = const OtherStruct array[] =
{ {

View file

@ -14,7 +14,6 @@ const SimpleStruct simpleStruct =
{\ {\
\ \
} }
}
const OtherStruct array[] = const OtherStruct array[] =
{ {

View file

@ -177,24 +177,24 @@ public class CAutoIndentTest extends AbstractAutoEditTest {
public void testDefaultAutoIndent() throws BadLocationException { public void testDefaultAutoIndent() throws BadLocationException {
AutoEditTester tester = createAutoEditTester(); //$NON-NLS-1$ AutoEditTester tester = createAutoEditTester(); //$NON-NLS-1$
tester.type(" initial indent=3\n"); //$NON-NLS-1$ tester.type(" initial indent=5\n"); //$NON-NLS-1$
assertEquals(1, tester.getCaretLine()); assertEquals(1, tester.getCaretLine());
assertEquals(3, tester.getCaretColumn()); assertEquals(5, tester.getCaretColumn());
tester.type("indent=3\n"); //$NON-NLS-1$ tester.type("indent=5\n"); //$NON-NLS-1$
assertEquals(2, tester.getCaretLine()); assertEquals(2, tester.getCaretLine());
assertEquals(3, tester.getCaretColumn()); assertEquals(5, tester.getCaretColumn());
tester.backspace();
tester.type("indent=4\n"); //$NON-NLS-1$
assertEquals(3, tester.getCaretLine());
assertEquals(4, tester.getCaretColumn());
tester.backspace();
tester.backspace(); tester.backspace();
tester.type("indent=2\n"); //$NON-NLS-1$ tester.type("indent=2\n"); //$NON-NLS-1$
assertEquals(3, tester.getCaretLine());
assertEquals(2, tester.getCaretColumn());
tester.backspace();
tester.backspace();
tester.type("indent=0\n"); //$NON-NLS-1$
assertEquals(4, tester.getCaretLine()); assertEquals(4, tester.getCaretLine());
assertEquals(0, tester.getCaretColumn()); assertEquals(2, tester.getCaretColumn());
tester.type("\n"); //$NON-NLS-1$ tester.type("\n"); //$NON-NLS-1$
assertEquals(5, tester.getCaretLine()); assertEquals(5, tester.getCaretLine());
assertEquals(0, tester.getCaretColumn()); assertEquals(2, tester.getCaretColumn());
} }
public void testCCommentAutoIndent() throws BadLocationException { public void testCCommentAutoIndent() throws BadLocationException {

View file

@ -27,8 +27,6 @@ import org.eclipse.cdt.internal.formatter.DefaultCodeFormatterOptions;
import org.eclipse.cdt.internal.ui.editor.CDocumentSetupParticipant; import org.eclipse.cdt.internal.ui.editor.CDocumentSetupParticipant;
import org.eclipse.cdt.internal.ui.editor.IndentUtil; import org.eclipse.cdt.internal.ui.editor.IndentUtil;
import org.eclipse.cdt.internal.ui.text.CHeuristicScanner;
import org.eclipse.cdt.internal.ui.text.CIndenter;
/** /**
* Tests for the CIndenter. * Tests for the CIndenter.
@ -61,8 +59,11 @@ public class CIndenterTest extends BaseUITestCase {
IDocument document= new Document(before); IDocument document= new Document(before);
String expected= contents[1].toString(); String expected= contents[1].toString();
new CDocumentSetupParticipant().setup(document); new CDocumentSetupParticipant().setup(document);
CIndenter indenter= new CIndenter(document, new CHeuristicScanner(document)); int numLines = document.getNumberOfLines();
IndentUtil.indentLines(document, new LineRange(0, document.getNumberOfLines()), null, null); if (document.getLineLength(numLines - 1) == 0) {
numLines--; // Exclude an empty line at the end.
}
IndentUtil.indentLines(document, new LineRange(0, numLines), null, null);
assertEquals(expected, document.get()); assertEquals(expected, document.get());
} }
@ -300,7 +301,7 @@ public class CIndenterTest extends BaseUITestCase {
DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED); DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED);
assertIndenterResult(); assertIndenterResult();
} }
//// a comment //// a comment
//class MyClass : public Base //class MyClass : public Base
//{ //{
@ -351,25 +352,124 @@ public class CIndenterTest extends BaseUITestCase {
//x = //x =
// 0; // 0;
public void _testWrappedAssignment_277624_1() throws Exception { public void testWrappedAssignment_277624_1() throws Exception {
assertIndenterResult(); assertIndenterResult();
} }
//{
//a = 0;
//x = 2 + //x = 2 +
//2 +
//2; //2;
//x = 2 + //{
// 2; // a = 0;
public void _testWrappedAssignment_277624_2() throws Exception { // x = 2 +
// 2 +
// 2;
public void testWrappedAssignment_277624_2() throws Exception {
assertIndenterResult(); assertIndenterResult();
} }
//if (1 > 0) {
//double d = a * b /
//c;
//if (1 > 0) {
// double d = a * b /
// c;
public void testWrappedAssignment_277624_3() throws Exception {
assertIndenterResult();
}
//for (int i = 0; //for (int i = 0;
//i < 2; i++) //i < 2; i++)
//for (int i = 0; //for (int i = 0;
// i < 2; i++) // i < 2; i++)
public void _testWrappedFor_277625() throws Exception { public void testWrappedFor_277625_1() throws Exception {
assertIndenterResult();
}
//for (int i = 0; i < 2;
//i++)
//for (int i = 0; i < 2;
// i++)
public void testWrappedFor_277625_2() throws Exception {
assertIndenterResult();
}
//for (int i = 0;
//i < 2;
//i++)
//{
//for (int i = 0;
// i < 2;
// i++)
//{
public void testWrappedFor_277625_3() throws Exception {
assertIndenterResult();
}
//;
//for (hash_map<Node*, double>::const_iterator it = container_.begin();
//it != container_.end(); ++it) {
//;
//for (hash_map<Node*, double>::const_iterator it = container_.begin();
// it != container_.end(); ++it) {
public void testWrappedFor_277625_4() throws Exception {
assertIndenterResult();
}
///* comment */
//#define MACRO(a, b) \
//value
///* comment */
//#define MACRO(a, b) \
// value
public void testWrappedDefine() throws Exception {
assertIndenterResult();
}
//std::string
// func();
//std::string
//func();
public void testFunctionDeclaration_1() throws Exception {
assertIndenterResult();
}
//;
//std::string
// func();
//;
//std::string
//func();
public void testFunctionDeclaration_2() throws Exception {
assertIndenterResult();
}
//map<int, char*>::iterator
// func();
//map<int, char*>::iterator
//func();
public void testFunctionDeclaration_3() throws Exception {
assertIndenterResult();
}
//template <class T, class U = A<T> >
// class B {
//template <class T, class U = A<T> >
//class B {
public void testTemplateClass() throws Exception {
assertIndenterResult(); assertIndenterResult();
} }

View file

@ -64,9 +64,8 @@ public class IndentActionTest extends TestCase {
} }
} }
private static final Class THIS= IndentActionTest.class;
public static Test suite() { public static Test suite() {
return new IndentTestSetup(new TestSuite(THIS)); return new IndentTestSetup(new TestSuite(IndentActionTest.class));
} }
private CEditor fEditor; private CEditor fEditor;

View file

@ -590,7 +590,8 @@ public final class IndentUtil {
* @return the indent, or <code>null</code> if not computable * @return the indent, or <code>null</code> if not computable
* @throws BadLocationException * @throws BadLocationException
*/ */
public static String computePreprocessorIndent(IDocument document, int line, ITypedRegion partition) throws BadLocationException { public static String computePreprocessorIndent(IDocument document, int line, ITypedRegion partition)
throws BadLocationException {
int ppFirstLine= document.getLineOfOffset(partition.getOffset()); int ppFirstLine= document.getLineOfOffset(partition.getOffset());
if (line == ppFirstLine) { if (line == ppFirstLine) {
return ""; //$NON-NLS-1$ return ""; //$NON-NLS-1$
@ -598,7 +599,7 @@ public final class IndentUtil {
CHeuristicScanner ppScanner= new CHeuristicScanner(document, ICPartitions.C_PARTITIONING, partition.getType()); CHeuristicScanner ppScanner= new CHeuristicScanner(document, ICPartitions.C_PARTITIONING, partition.getType());
CIndenter ppIndenter= new CIndenter(document, ppScanner); CIndenter ppIndenter= new CIndenter(document, ppScanner);
if (line == ppFirstLine + 1) { if (line == ppFirstLine + 1) {
return ppIndenter.createReusingIndent(new StringBuilder(), 1).toString(); return ppIndenter.createReusingIndent(new StringBuilder(), ppIndenter.getContinuationLineIndent()).toString();
} }
StringBuilder computed= ppIndenter.computeIndentation(document.getLineOffset(line), false); StringBuilder computed= ppIndenter.computeIndentation(document.getLineOffset(line), false);
if (computed != null) { if (computed != null) {

View file

@ -1,11 +1,11 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2000, 2009 IBM Corporation and others. * Copyright (c) 2000, 2009 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials * All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0 * are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at * which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html * http://www.eclipse.org/legal/epl-v10.html
* *
* Contributors: * Contributors:
* IBM Corporation - initial API and implementation * IBM Corporation - initial API and implementation
* Sergey Prigogin (Google) * Sergey Prigogin (Google)
* Anton Leherbauer (Wind River Systems) * Anton Leherbauer (Wind River Systems)
@ -67,7 +67,7 @@ public final class CIndenter {
final boolean prefIndentBracesForMethods; final boolean prefIndentBracesForMethods;
final boolean prefIndentBracesForTypes; final boolean prefIndentBracesForTypes;
final int prefContinuationIndent; final int prefContinuationIndent;
final boolean prefHasGenerics; final boolean prefHasTemplates;
final String prefTabChar; final String prefTabChar;
private final ICProject fProject; private final ICProject fProject;
@ -115,7 +115,7 @@ public final class CIndenter {
prefIndentBracesForArrays= prefIndentBracesForArrays(); prefIndentBracesForArrays= prefIndentBracesForArrays();
prefIndentBracesForMethods= prefIndentBracesForMethods(); prefIndentBracesForMethods= prefIndentBracesForMethods();
prefIndentBracesForTypes= prefIndentBracesForTypes(); prefIndentBracesForTypes= prefIndentBracesForTypes();
prefHasGenerics= hasGenerics(); prefHasTemplates= hasTemplates();
prefTabChar= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR); prefTabChar= getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR);
} }
@ -197,7 +197,7 @@ public final class CIndenter {
} }
private int prefAssignmentIndent() { private int prefAssignmentIndent() {
return prefBlockIndent(); return prefContinuationIndent();
} }
private int prefSimpleIndent() { private int prefSimpleIndent() {
@ -337,7 +337,7 @@ public final class CIndenter {
return 2; // sensible default return 2; // sensible default
} }
private boolean hasGenerics() { private boolean hasTemplates() {
return true; return true;
} }
} }
@ -669,6 +669,14 @@ public final class CIndenter {
return buffer; return buffer;
} }
/**
* Returns relative indent of continuation lines.
* @return a number of indentation units.
*/
public int getContinuationLineIndent() {
return fPrefs.prefContinuationIndent;
}
/** /**
* Returns the reference position regarding to indentation for <code>offset</code>, * Returns the reference position regarding to indentation for <code>offset</code>,
* or <code>NOT_FOUND</code>. This method calls * or <code>NOT_FOUND</code>. This method calls
@ -731,8 +739,8 @@ public final class CIndenter {
*/ */
public int findReferencePosition(int offset, int nextToken) { public int findReferencePosition(int offset, int nextToken) {
boolean danglingElse= false; boolean danglingElse= false;
boolean unindent= false; boolean cancelIndent= false; // If set to true, fIndent is ignored.
boolean indent= false; int extraIndent= 0; // Can be either positive or negative.
boolean matchBrace= false; boolean matchBrace= false;
boolean matchParen= false; boolean matchParen= false;
boolean matchCase= false; boolean matchCase= false;
@ -770,16 +778,18 @@ public final class CIndenter {
break; break;
case Symbols.TokenLBRACE: // for opening-brace-on-new-line style case Symbols.TokenLBRACE: // for opening-brace-on-new-line style
if (bracelessBlockStart) if (bracelessBlockStart) {
unindent= !fPrefs.prefIndentBracesForBlocks; extraIndent= fPrefs.prefIndentBracesForBlocks ? 0 : -1;
else if (prevToken == Symbols.TokenCOLON && !fPrefs.prefIndentBracesForBlocks) } else if (prevToken == Symbols.TokenCOLON && !fPrefs.prefIndentBracesForBlocks) {
unindent= true; extraIndent= -1;
else if ((prevToken == Symbols.TokenEQUAL || prevToken == Symbols.TokenRBRACKET) && !fPrefs.prefIndentBracesForArrays) } else if ((prevToken == Symbols.TokenEQUAL || prevToken == Symbols.TokenRBRACKET) &&
unindent= true; !fPrefs.prefIndentBracesForArrays) {
else if (prevToken == Symbols.TokenRPAREN && fPrefs.prefIndentBracesForMethods) cancelIndent= true;
indent= true; } else if (prevToken == Symbols.TokenRPAREN && fPrefs.prefIndentBracesForMethods) {
else if (prevToken == Symbols.TokenIDENT && fPrefs.prefIndentBracesForTypes) extraIndent= 1;
indent= true; } else if (prevToken == Symbols.TokenIDENT && fPrefs.prefIndentBracesForTypes) {
extraIndent= 1;
}
break; break;
case Symbols.TokenRBRACE: // closing braces get unindented case Symbols.TokenRBRACE: // closing braces get unindented
@ -799,12 +809,15 @@ public final class CIndenter {
danglingElse= false; danglingElse= false;
} }
int ref= findReferencePosition(offset, danglingElse, matchBrace, matchParen, matchCase, matchAccessSpecifier); int ref= findReferencePosition(offset, danglingElse, matchBrace, matchParen, matchCase,
if (unindent) matchAccessSpecifier);
fIndent--; if (cancelIndent) {
if (indent) { fIndent = 0;
} else if (extraIndent > 0) {
fAlign= CHeuristicScanner.NOT_FOUND; fAlign= CHeuristicScanner.NOT_FOUND;
fIndent++; fIndent += extraIndent;
} else {
fIndent += extraIndent;
} }
return ref; return ref;
} }
@ -1138,6 +1151,7 @@ public final class CIndenter {
final int READ_IDENT= 2; final int READ_IDENT= 2;
int mayBeMethodBody= NOTHING; int mayBeMethodBody= NOTHING;
boolean isTypeBody= false; boolean isTypeBody= false;
int startLine = fLine;
while (true) { while (true) {
int prevToken= fToken; int prevToken= fToken;
nextToken(); nextToken();
@ -1167,11 +1181,23 @@ public final class CIndenter {
} }
} }
if (fToken == Symbols.TokenSEMICOLON && fLine == startLine) {
// Skip semicolons on the same line. Otherwise we may never reach beginning of a 'for'
// statement.
continue;
}
switch (fToken) { switch (fToken) {
// scope introduction through: LPAREN, LBRACE, LBRACKET // scope introduction through: LPAREN, LBRACE, LBRACKET
// search stop on SEMICOLON, RBRACE, COLON, EOF // search stop on SEMICOLON, RBRACE, COLON, EOF
// -> the next token is the start of the statement (i.e. previousPos when backward scanning) // -> the next token is the start of the statement (i.e. previousPos when backward scanning)
case Symbols.TokenLPAREN: case Symbols.TokenLPAREN:
if (peekToken() == Symbols.TokenFOR) {
nextToken(); // Consume 'for'
fIndent = fPrefs.prefContinuationIndent;
return fPosition;
}
//$FALL-THROUGH$
case Symbols.TokenLBRACE: case Symbols.TokenLBRACE:
case Symbols.TokenLBRACKET: case Symbols.TokenLBRACKET:
case Symbols.TokenSEMICOLON: case Symbols.TokenSEMICOLON:
@ -1215,7 +1241,6 @@ public final class CIndenter {
else else
return pos; return pos;
case Symbols.TokenRBRACKET: case Symbols.TokenRBRACKET:
case Symbols.TokenGREATERTHAN:
pos= fPreviousPos; pos= fPreviousPos;
if (skipScope()) if (skipScope())
break; break;
@ -1352,7 +1377,6 @@ public final class CIndenter {
case Symbols.TokenRPAREN: case Symbols.TokenRPAREN:
case Symbols.TokenRBRACKET: case Symbols.TokenRBRACKET:
case Symbols.TokenRBRACE: case Symbols.TokenRBRACE:
case Symbols.TokenGREATERTHAN:
skipScope(); skipScope();
break; break;
@ -1403,7 +1427,6 @@ public final class CIndenter {
case Symbols.TokenRPAREN: case Symbols.TokenRPAREN:
case Symbols.TokenRBRACKET: case Symbols.TokenRBRACKET:
case Symbols.TokenRBRACE: case Symbols.TokenRBRACE:
case Symbols.TokenGREATERTHAN:
skipScope(); skipScope();
break; break;
@ -1427,6 +1450,7 @@ public final class CIndenter {
private int skipToPreviousListItemOrListStart() { private int skipToPreviousListItemOrListStart() {
int startLine= fLine; int startLine= fLine;
int startPosition= fPosition; int startPosition= fPosition;
boolean seenEqual = fToken == Symbols.TokenEQUAL;
while (true) { while (true) {
nextToken(); nextToken();
@ -1435,7 +1459,12 @@ public final class CIndenter {
try { try {
int lineOffset= fDocument.getLineOffset(startLine); int lineOffset= fDocument.getLineOffset(startLine);
int bound= Math.min(fDocument.getLength(), startPosition + 1); int bound= Math.min(fDocument.getLength(), startPosition + 1);
fAlign= fScanner.findNonWhitespaceForwardInAnyPartition(lineOffset, bound); if ((fToken == Symbols.TokenSEMICOLON || fToken == Symbols.TokenRBRACE ||
fToken == Symbols.TokenLBRACE) && seenEqual) {
fIndent = fPrefs.prefContinuationIndent;
} else {
fAlign= fScanner.findNonWhitespaceForwardInAnyPartition(lineOffset, bound);
}
} catch (BadLocationException e) { } catch (BadLocationException e) {
// ignore and return just the position // ignore and return just the position
} }
@ -1447,7 +1476,6 @@ public final class CIndenter {
case Symbols.TokenRPAREN: case Symbols.TokenRPAREN:
case Symbols.TokenRBRACKET: case Symbols.TokenRBRACKET:
case Symbols.TokenRBRACE: case Symbols.TokenRBRACE:
case Symbols.TokenGREATERTHAN:
skipScope(); skipScope();
break; break;
@ -1468,7 +1496,14 @@ public final class CIndenter {
} }
return fPosition; return fPosition;
case Symbols.TokenEQUAL:
seenEqual = true;
break;
case Symbols.TokenEOF: case Symbols.TokenEOF:
if (seenEqual) {
fIndent = fPrefs.prefContinuationIndent;
}
return 0; return 0;
} }
} }
@ -1492,16 +1527,13 @@ public final class CIndenter {
case Symbols.TokenRBRACE: case Symbols.TokenRBRACE:
return skipScope(Symbols.TokenLBRACE, Symbols.TokenRBRACE); return skipScope(Symbols.TokenLBRACE, Symbols.TokenRBRACE);
case Symbols.TokenGREATERTHAN: case Symbols.TokenGREATERTHAN:
if (!fPrefs.prefHasGenerics) if (!fPrefs.prefHasTemplates)
return false; return false;
int storedPosition= fPosition; int storedPosition= fPosition;
int storedToken= fToken; int storedToken= fToken;
nextToken(); nextToken();
switch (fToken) { switch (fToken) {
case Symbols.TokenIDENT: case Symbols.TokenIDENT:
if (!isGenericStarter(getTokenContent()))
break;
// fall thru
if (skipScope(Symbols.TokenLESSTHAN, Symbols.TokenGREATERTHAN)) if (skipScope(Symbols.TokenLESSTHAN, Symbols.TokenGREATERTHAN))
return true; return true;
break; break;
@ -1532,36 +1564,6 @@ public final class CIndenter {
return new DocumentCharacterIterator(fDocument, fPosition, fPreviousPos); return new DocumentCharacterIterator(fDocument, fPosition, fPreviousPos);
} }
/**
* Returns <code>true</code> if <code>identifier</code> is probably a
* type variable or type name, <code>false</code> if it is rather not.
* This is a heuristic.
*
* @param identifier the identifier to check
* @return <code>true</code> if <code>identifier</code> is probably a
* type variable or type name, <code>false</code> if not
*/
private boolean isGenericStarter(CharSequence identifier) {
/* This heuristic allows any identifiers if they start with an upper
* case. This will fail when a comparison is made with constants:
*
* if (MAX > foo)
*
* will try to find the matching '<' which will never come
*
* Also, it will fail on lower case types and type variables
*/
int length= identifier.length();
if (length > 0 && Character.isUpperCase(identifier.charAt(0))) {
for (int i= 0; i < length; i++) {
if (identifier.charAt(i) == '_')
return false;
}
return true;
}
return false;
}
/** /**
* Handles the introduction of a new scope. The current token must be one out * Handles the introduction of a new scope. The current token must be one out
* of <code>Symbols.TokenLPAREN</code>, <code>Symbols.TokenLBRACE</code>, * of <code>Symbols.TokenLPAREN</code>, <code>Symbols.TokenLBRACE</code>,
@ -1738,7 +1740,6 @@ public final class CIndenter {
case Symbols.TokenRPAREN: case Symbols.TokenRPAREN:
case Symbols.TokenRBRACKET: case Symbols.TokenRBRACKET:
case Symbols.TokenRBRACE: case Symbols.TokenRBRACE:
case Symbols.TokenGREATERTHAN:
skipScope(); skipScope();
break; break;
@ -1863,6 +1864,14 @@ public final class CIndenter {
} }
} }
/**
* Reads the next token in backward direction from the heuristic scanner
* and returns that token without changing the current position.
*/
private int peekToken() {
return fScanner.previousToken(fPosition - 1, CHeuristicScanner.UNBOUND);
}
/** /**
* Returns <code>true</code> if the current tokens look like a method * Returns <code>true</code> if the current tokens look like a method
* declaration header (i.e. only the return type and method name). The * declaration header (i.e. only the return type and method name). The
@ -1905,8 +1914,6 @@ public final class CIndenter {
return true; return true;
} }
break; break;
case Symbols.TokenGREATERTHAN:
return skipScope();
case Symbols.TokenCOLON: case Symbols.TokenCOLON:
nextToken(); nextToken();
switch (fToken) { switch (fToken) {