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

Bug 383277 - Invalid auto indentation before and after colon in class

declaration with inheritance
This commit is contained in:
Sergey Prigogin 2012-06-22 15:11:35 -07:00
parent 5eb8410fbd
commit bac3846b32
4 changed files with 201 additions and 104 deletions

View file

@ -40,7 +40,6 @@ import org.eclipse.cdt.ui.PreferenceConstants;
import org.eclipse.cdt.ui.text.ICPartitions; import org.eclipse.cdt.ui.text.ICPartitions;
import org.eclipse.cdt.ui.text.doctools.DefaultMultilineCommentAutoEditStrategy; import org.eclipse.cdt.ui.text.doctools.DefaultMultilineCommentAutoEditStrategy;
import org.eclipse.cdt.internal.ui.text.CAutoIndentStrategy; import org.eclipse.cdt.internal.ui.text.CAutoIndentStrategy;
import org.eclipse.cdt.internal.ui.text.CTextTools; import org.eclipse.cdt.internal.ui.text.CTextTools;
@ -270,28 +269,28 @@ public class CAutoIndentTest extends AbstractAutoEditTest {
String[] kw_inh= new String[] {"class", "union", "struct"}; String[] kw_inh= new String[] {"class", "union", "struct"};
String[] kw_anon= new String[] {"union", "struct", "enum"}; String[] kw_anon= new String[] {"union", "struct", "enum"};
for(int i=0; i<kw.length; i++) { for (int i= 0; i < kw.length; i++) {
tester.reset(); tester.reset();
tester.type("\n\n\n "+kw[i]+" A {\n"); //$NON-NLS-1$ tester.type("\n\n\n "+kw[i]+" A {\n"); //$NON-NLS-1$
assertEquals("\n\n\n "+kw[i]+" A {\n\t \n };", tester.fDoc.get()); //$NON-NLS-1$ assertEquals("\n\n\n "+kw[i]+" A {\n\t \n };", tester.fDoc.get()); //$NON-NLS-1$
} }
for(int i=0; i<kw.length; i++) { for (int i= 0; i < kw.length; i++) {
tester.reset(); tester.reset();
tester.type("\n\n\n"+kw[i]+" A {\n"); //$NON-NLS-1$ tester.type("\n\n\n"+kw[i]+" A {\n"); //$NON-NLS-1$
assertEquals("\n\n\n"+kw[i]+" A {\n\t\n};", tester.fDoc.get()); //$NON-NLS-1$ assertEquals("\n\n\n"+kw[i]+" A {\n\t\n};", tester.fDoc.get()); //$NON-NLS-1$
} }
for(int i=0; i<kw.length; i++) { for (int i= 0; i < kw.length; i++) {
tester.reset(); tester.reset();
tester.type("\n\n\n "+kw[i]+" A {\n"); //$NON-NLS-1$ tester.type("\n\n\n "+kw[i]+" A {\n"); //$NON-NLS-1$
assertEquals("\n\n\n "+kw[i]+" A {\n\t \n };", tester.fDoc.get()); //$NON-NLS-1$ assertEquals("\n\n\n "+kw[i]+" A {\n\t \n };", tester.fDoc.get()); //$NON-NLS-1$
} }
for(int i=0; i<kw.length; i++) { for (int i= 0; i < kw.length; i++) {
tester.reset(); tester.reset();
tester.type("\n// foo\n\n\n//bar\n\n"); //$NON-NLS-1$ tester.type("\n// foo\n\n\n//bar\n\n"); //$NON-NLS-1$
@ -300,17 +299,17 @@ public class CAutoIndentTest extends AbstractAutoEditTest {
assertEquals("\n// foo\n"+kw[i]+" A {\n\t\n};\n\n//bar\n\n", tester.fDoc.get()); //$NON-NLS-1$ assertEquals("\n// foo\n"+kw[i]+" A {\n\t\n};\n\n//bar\n\n", tester.fDoc.get()); //$NON-NLS-1$
} }
// this tests for a sensible behaviour for enums, although the // this tests for a sensible behavior for enums, although the
// code generated is invalid, its the user entered part that is // code generated is invalid, its the user entered part that is
// the problem // the problem
for(int i=0; i<kw_inh.length; i++) { for (int i= 0; i < kw_inh.length; i++) {
tester.reset(); tester.reset();
tester.type("\n\n\n"+kw_inh[i]+" A\n:\npublic B\n,\npublic C\n{\n"); //$NON-NLS-1$ tester.type("\n\n\n"+kw_inh[i]+" A\n:\npublic B\n,\npublic C\n{\n"); //$NON-NLS-1$
assertEquals("\n\n\n"+kw_inh[i]+" A\n:\n\tpublic B\n\t,\n\tpublic C\n\t{\n\t\t\n\t};", tester.fDoc.get()); //$NON-NLS-1$ assertEquals("\n\n\n"+kw_inh[i]+" A\n:\n\t\tpublic B\n\t\t,\n\t\tpublic C\n{\n\t\n};", tester.fDoc.get()); //$NON-NLS-1$
} }
for(int i=0; i<kw.length; i++) { for (int i= 0; i < kw.length; i++) {
tester.reset(); tester.reset();
tester.type("\n// foo\n\n\n//bar\n\n"); //$NON-NLS-1$ tester.type("\n// foo\n\n\n//bar\n\n"); //$NON-NLS-1$
@ -319,13 +318,13 @@ public class CAutoIndentTest extends AbstractAutoEditTest {
assertEquals("\n// foo\n"+kw[i]+" /* for(int i=0; i<100; i++) {} */\nA \n{\n\t\n};\n\n//bar\n\n", tester.fDoc.get()); //$NON-NLS-1$ assertEquals("\n// foo\n"+kw[i]+" /* for(int i=0; i<100; i++) {} */\nA \n{\n\t\n};\n\n//bar\n\n", tester.fDoc.get()); //$NON-NLS-1$
} }
for(int i=0; i<kw_anon.length; i++) { for (int i= 0; i < kw_anon.length; i++) {
tester.reset(); tester.reset();
tester.type("\n\n\n"+kw_anon[i]+" {\n"); //$NON-NLS-1$ tester.type("\n\n\n"+kw_anon[i]+" {\n"); //$NON-NLS-1$
assertEquals("\n\n\n"+kw_anon[i]+" {\n\t\n};", tester.fDoc.get()); //$NON-NLS-1$ assertEquals("\n\n\n"+kw_anon[i]+" {\n\t\n};", tester.fDoc.get()); //$NON-NLS-1$
} }
} }
/** /**
* Tests that brackets are inserted (without semi-colons) in appropriate * Tests that brackets are inserted (without semi-colons) in appropriate

View file

@ -460,6 +460,32 @@ public class CIndenterTest extends BaseUITestCase {
assertIndenterResult(); assertIndenterResult();
} }
//class ClassWithLongName :
//public AnotherClassWithLongName,
//protected YetAnotherClassWithLongName
//{
//};
//class ClassWithLongName
//: public AnotherClassWithLongName,
//protected YetAnotherClassWithLongName
//{
//};
//class ClassWithLongName :
// public AnotherClassWithLongName,
// protected YetAnotherClassWithLongName
//{
//};
//class ClassWithLongName
// : public AnotherClassWithLongName,
// protected YetAnotherClassWithLongName
//{
//};
public void testBaseClause_Bug383277() throws Exception {
fOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, CCorePlugin.SPACE);
assertIndenterResult();
}
//namespace ns { //namespace ns {
//class A; //class A;
//} //}

View file

@ -41,6 +41,7 @@ import org.eclipse.cdt.ui.text.ICPartitions;
import org.eclipse.cdt.internal.corext.util.CodeFormatterUtil; import org.eclipse.cdt.internal.corext.util.CodeFormatterUtil;
import org.eclipse.cdt.internal.ui.editor.IndentUtil; import org.eclipse.cdt.internal.ui.editor.IndentUtil;
import org.eclipse.cdt.internal.ui.text.CIndenter.MatchMode;
/** /**
* Auto indent strategy sensitive to brackets. * Auto indent strategy sensitive to brackets.
@ -183,7 +184,7 @@ public class CAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
// shift only when line does not contain any text up to the closing bracket // shift only when line does not contain any text up to the closing bracket
if (whiteend == c.offset) { if (whiteend == c.offset) {
// evaluate the line with the opening bracket that matches out closing bracket // evaluate the line with the opening bracket that matches out closing bracket
int reference = indenter.findReferencePosition(c.offset, false, true, false, false, false); int reference = indenter.findReferencePosition(c.offset, false, MatchMode.MATCH_BRACE);
int indLine = d.getLineOfOffset(reference); int indLine = d.getLineOfOffset(reference);
if (indLine != -1 && indLine != line) { if (indLine != -1 && indLine != line) {
// take the indent of the found line // take the indent of the found line
@ -219,7 +220,7 @@ public class CAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
int lineOffset = d.getLineOffset(line); int lineOffset = d.getLineOffset(line);
// make sure we don't have any leading comments etc. // make sure we don't have any leading comments etc.
if (d.get(lineOffset, c.offset - lineOffset).trim().length() != 0) if (!d.get(lineOffset, c.offset - lineOffset).trim().isEmpty())
return; return;
// Line of last C code // Line of last C code
@ -851,7 +852,7 @@ public class CAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
case Symbols.TokenDEFAULT: case Symbols.TokenDEFAULT:
{ {
CIndenter indenter= new CIndenter(document, dScanner, fProject); CIndenter indenter= new CIndenter(document, dScanner, fProject);
peer= indenter.findReferencePosition(dPos, false, false, false, true, false); peer= indenter.findReferencePosition(dPos, false, MatchMode.MATCH_CASE);
if (peer == CHeuristicScanner.NOT_FOUND) if (peer == CHeuristicScanner.NOT_FOUND)
return firstPeer; return firstPeer;
firstPeer= peer; firstPeer= peer;
@ -863,7 +864,7 @@ public class CAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
case Symbols.TokenPRIVATE: case Symbols.TokenPRIVATE:
{ {
CIndenter indenter= new CIndenter(document, dScanner, fProject); CIndenter indenter= new CIndenter(document, dScanner, fProject);
peer= indenter.findReferencePosition(dPos, false, false, false, false, true); peer= indenter.findReferencePosition(dPos, false, MatchMode.MATCH_ACCESS_SPECIFIER);
if (peer == CHeuristicScanner.NOT_FOUND) if (peer == CHeuristicScanner.NOT_FOUND)
return firstPeer; return firstPeer;
firstPeer= peer; firstPeer= peer;
@ -969,7 +970,7 @@ public class CAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
// Only shift if the last C line is further up and is a braceless block candidate // Only shift if the last C line is further up and is a braceless block candidate
if (lastLine < line) { if (lastLine < line) {
CIndenter indenter = new CIndenter(doc, scanner, fProject); CIndenter indenter = new CIndenter(doc, scanner, fProject);
int ref = indenter.findReferencePosition(p, true, false, false, false, false); int ref = indenter.findReferencePosition(p, true, MatchMode.REGULAR);
if (ref == CHeuristicScanner.NOT_FOUND) if (ref == CHeuristicScanner.NOT_FOUND)
return; return;
int refLine = doc.getLineOfOffset(ref); int refLine = doc.getLineOfOffset(ref);
@ -1006,7 +1007,7 @@ public class CAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
// Only shift if the last C line is further up and is a braceless block candidate // Only shift if the last C line is further up and is a braceless block candidate
if (lastLine < line) { if (lastLine < line) {
CIndenter indenter = new CIndenter(doc, scanner, fProject); CIndenter indenter = new CIndenter(doc, scanner, fProject);
int ref = indenter.findReferencePosition(p, false, false, false, true, false); int ref = indenter.findReferencePosition(p, false, MatchMode.MATCH_CASE);
if (ref == CHeuristicScanner.NOT_FOUND) if (ref == CHeuristicScanner.NOT_FOUND)
return; return;
int refLine = doc.getLineOfOffset(ref); int refLine = doc.getLineOfOffset(ref);
@ -1069,9 +1070,9 @@ public class CAutoIndentStrategy extends DefaultIndentLineAutoEditStrategy {
CIndenter indenter = new CIndenter(doc, scanner, fProject); CIndenter indenter = new CIndenter(doc, scanner, fProject);
int ref; int ref;
if (prevToken == Symbols.TokenDEFAULT) if (prevToken == Symbols.TokenDEFAULT)
ref = indenter.findReferencePosition(p, false, false, false, true, false); ref = indenter.findReferencePosition(p, false, MatchMode.MATCH_CASE);
else else
ref = indenter.findReferencePosition(p, false, false, false, false, true); ref = indenter.findReferencePosition(p, false, MatchMode.MATCH_ACCESS_SPECIFIER);
if (ref == CHeuristicScanner.NOT_FOUND) if (ref == CHeuristicScanner.NOT_FOUND)
return; return;
int refLine = doc.getLineOfOffset(ref); int refLine = doc.getLineOfOffset(ref);

View file

@ -12,6 +12,8 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.cdt.internal.ui.text; package org.eclipse.cdt.internal.ui.text;
import static org.eclipse.cdt.internal.ui.text.CHeuristicScanner.NOT_FOUND;
import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Platform;
@ -386,7 +388,7 @@ public final class CIndenter {
private int fExtraSpaces; private int fExtraSpaces;
/** /**
* The absolute (character-counted) indentation offset for special cases * The absolute (character-counted) indentation offset for special cases
* (method defs, array initializers) * (method definitions, array initializers)
*/ */
private int fAlign; private int fAlign;
/** The stateful scan position for the indentation methods. */ /** The stateful scan position for the indentation methods. */
@ -458,14 +460,11 @@ public final class CIndenter {
* if it cannot be determined * if it cannot be determined
*/ */
private StringBuilder getReferenceIndentation(int offset, boolean assumeOpeningBrace) { private StringBuilder getReferenceIndentation(int offset, boolean assumeOpeningBrace) {
int unit; int unit= findReferencePosition(offset,
if (assumeOpeningBrace) assumeOpeningBrace ? Symbols.TokenLBRACE : peekToken(offset));
unit= findReferencePosition(offset, Symbols.TokenLBRACE);
else
unit= findReferencePosition(offset, peekToken(offset));
// if we were unable to find anything, return null // if we were unable to find anything, return null
if (unit == CHeuristicScanner.NOT_FOUND) if (unit == NOT_FOUND)
return null; return null;
return getLeadingWhitespace(unit); return getLeadingWhitespace(unit);
@ -496,7 +495,7 @@ public final class CIndenter {
StringBuilder reference= getReferenceIndentation(offset, assumeOpeningBrace); StringBuilder reference= getReferenceIndentation(offset, assumeOpeningBrace);
// handle special alignment // handle special alignment
if (fAlign != CHeuristicScanner.NOT_FOUND) { if (fAlign != NOT_FOUND) {
try { try {
// a special case has been detected. // a special case has been detected.
IRegion line= fDocument.getLineInformationOfOffset(fAlign); IRegion line= fDocument.getLineInformationOfOffset(fAlign);
@ -717,13 +716,13 @@ public final class CIndenter {
/** /**
* 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 {@link CHeuristicScanner#NOT_FOUND NOT_FOUND}. This method calls
* {@link #findReferencePosition(int, int) findReferencePosition(offset, nextChar)} where * {@link #findReferencePosition(int, int) findReferencePosition(offset, nextChar)} where
* <code>nextChar</code> is the next character after <code>offset</code>. * <code>nextChar</code> is the next character after <code>offset</code>.
* *
* @param offset the offset for which the reference is computed * @param offset the offset for which the reference is computed
* @return the reference statement relative to which <code>offset</code> * @return the reference statement relative to which <code>offset</code>
* should be indented, or {@link CHeuristicScanner#NOT_FOUND} * should be indented, or {@link CHeuristicScanner#NOT_FOUND NOT_FOUND}
*/ */
public int findReferencePosition(int offset) { public int findReferencePosition(int offset) {
return findReferencePosition(offset, peekToken(offset)); return findReferencePosition(offset, peekToken(offset));
@ -740,8 +739,29 @@ public final class CIndenter {
if (offset < fDocument.getLength()) { if (offset < fDocument.getLength()) {
try { try {
IRegion line= fDocument.getLineInformationOfOffset(offset); IRegion line= fDocument.getLineInformationOfOffset(offset);
int lineOffset= line.getOffset(); int lineEnd= line.getOffset() + line.getLength();
int next= fScanner.nextToken(offset, lineOffset + line.getLength()); int next= fScanner.nextToken(offset, lineEnd);
return next;
} catch (BadLocationException e) {
}
}
return Symbols.TokenEOF;
}
/**
* Peeks the second next token in the document that comes after <code>offset</code>
* on the same line as <code>offset</code>.
*
* @param offset the offset into document
* @return the token symbol of the second next element, or TokenEOF if there is none
*/
private int peekSecondToken(int offset) {
if (offset < fDocument.getLength()) {
try {
IRegion line= fDocument.getLineInformationOfOffset(offset);
int lineEnd= line.getOffset() + line.getLength();
fScanner.nextToken(offset, lineEnd);
int next = fScanner.nextToken(fScanner.getPosition(), lineEnd);
return next; return next;
} catch (BadLocationException e) { } catch (BadLocationException e) {
} }
@ -751,7 +771,7 @@ public final class CIndenter {
/** /**
* Returns the reference position regarding to indentation for <code>position</code>, * Returns the reference position regarding to indentation for <code>position</code>,
* or <code>NOT_FOUND</code>. * or {@link CHeuristicScanner#NOT_FOUND NOT_FOUND}.
* *
* <p>If <code>peekNextChar</code> is <code>true</code>, the next token after * <p>If <code>peekNextChar</code> is <code>true</code>, the next token after
* <code>offset</code> is read and taken into account when computing the * <code>offset</code> is read and taken into account when computing the
@ -773,16 +793,13 @@ public final class CIndenter {
* @param offset the offset for which the reference is computed * @param offset the offset for which the reference is computed
* @param nextToken the next token to assume in the document * @param nextToken the next token to assume in the document
* @return the reference statement relative to which <code>offset</code> * @return the reference statement relative to which <code>offset</code>
* should be indented, or {@link CHeuristicScanner#NOT_FOUND} * should be indented, or {@link CHeuristicScanner#NOT_FOUND NOT_FOUND}
*/ */
public int findReferencePosition(int offset, int nextToken) { public int findReferencePosition(int offset, int nextToken) {
boolean danglingElse= false; boolean danglingElse= false;
boolean cancelIndent= false; // If set to true, fIndent is ignored. boolean cancelIndent= false; // If set to true, fIndent is ignored.
int extraIndent= 0; // Can be either positive or negative. int extraIndent= 0; // Can be either positive or negative.
boolean matchBrace= false; MatchMode matchMode = MatchMode.REGULAR;
boolean matchParen= false;
boolean matchCase= false;
boolean matchAccessSpecifier= false;
// Account for un-indentation characters already typed in, but after position. // Account for un-indentation characters already typed in, but after position.
// If they are on a line by themselves, the indentation gets adjusted accordingly. // If they are on a line by themselves, the indentation gets adjusted accordingly.
@ -793,7 +810,8 @@ public final class CIndenter {
IRegion line= fDocument.getLineInformationOfOffset(offset); IRegion line= fDocument.getLineInformationOfOffset(offset);
int lineOffset= line.getOffset(); int lineOffset= line.getOffset();
int prevPos= Math.max(offset - 1, 0); int prevPos= Math.max(offset - 1, 0);
boolean isFirstTokenOnLine= fDocument.get(lineOffset, prevPos + 1 - lineOffset).trim().length() == 0; boolean isFirstTokenOnLine=
fDocument.get(lineOffset, prevPos + 1 - lineOffset).trim().length() == 0;
int prevToken= fScanner.previousToken(prevPos, CHeuristicScanner.UNBOUND); int prevToken= fScanner.previousToken(prevPos, CHeuristicScanner.UNBOUND);
boolean bracelessBlockStart= fScanner.isBracelessBlockStart(prevPos, CHeuristicScanner.UNBOUND); boolean bracelessBlockStart= fScanner.isBracelessBlockStart(prevPos, CHeuristicScanner.UNBOUND);
@ -805,14 +823,14 @@ public final class CIndenter {
case Symbols.TokenCASE: case Symbols.TokenCASE:
case Symbols.TokenDEFAULT: case Symbols.TokenDEFAULT:
if (isFirstTokenOnLine) if (isFirstTokenOnLine)
matchCase= true; matchMode = MatchMode.MATCH_CASE;
break; break;
case Symbols.TokenPUBLIC: case Symbols.TokenPUBLIC:
case Symbols.TokenPROTECTED: case Symbols.TokenPROTECTED:
case Symbols.TokenPRIVATE: case Symbols.TokenPRIVATE:
if (isFirstTokenOnLine) if (isFirstTokenOnLine && peekSecondToken(offset) != Symbols.TokenIDENT)
matchAccessSpecifier= true; matchMode = MatchMode.MATCH_ACCESS_SPECIFIER;
break; break;
case Symbols.TokenLBRACE: // for opening-brace-on-new-line style case Symbols.TokenLBRACE: // for opening-brace-on-new-line style
@ -825,34 +843,41 @@ public final class CIndenter {
cancelIndent= true; cancelIndent= true;
} else if ((prevToken == Symbols.TokenRPAREN || prevToken == Symbols.TokenCONST) && fPrefs.prefIndentBracesForMethods) { } else if ((prevToken == Symbols.TokenRPAREN || prevToken == Symbols.TokenCONST) && fPrefs.prefIndentBracesForMethods) {
extraIndent= 1; extraIndent= 1;
} else if (prevToken == Symbols.TokenIDENT && fPrefs.prefIndentBracesForTypes) { } else if (prevToken == Symbols.TokenIDENT) {
extraIndent= 1; if (fPrefs.prefIndentBracesForTypes) {
extraIndent= 1;
}
int pos = fPosition;
fPosition = offset;
if (matchTypeDeclaration() != NOT_FOUND) {
matchMode = MatchMode.MATCH_TYPE_DECLARATION;
}
fPosition = pos;
} }
break; break;
case Symbols.TokenRBRACE: // closing braces get unindented case Symbols.TokenRBRACE: // closing braces get unindented
if (isFirstTokenOnLine || prevToken != Symbols.TokenLBRACE) if (isFirstTokenOnLine || prevToken != Symbols.TokenLBRACE)
matchBrace= true; matchMode = MatchMode.MATCH_BRACE;
break; break;
case Symbols.TokenRPAREN: case Symbols.TokenRPAREN:
if (isFirstTokenOnLine) if (isFirstTokenOnLine)
matchParen= true; matchMode = MatchMode.MATCH_PAREN;
break; break;
} }
} catch (BadLocationException e) { } catch (BadLocationException e) {
} }
} else { } else {
// don't assume an else could come if we are at the end of file // Don't assume an else could come if we are at the end of file.
danglingElse= false; danglingElse= false;
} }
int ref= findReferencePosition(offset, danglingElse, matchBrace, matchParen, matchCase, int ref= findReferencePosition(offset, danglingElse, matchMode);
matchAccessSpecifier);
if (cancelIndent) { if (cancelIndent) {
fIndent = 0; fIndent = 0;
} else if (extraIndent > 0) { } else if (extraIndent > 0) {
fAlign= CHeuristicScanner.NOT_FOUND; fAlign= NOT_FOUND;
fIndent += extraIndent; fIndent += extraIndent;
} else { } else {
fIndent += extraIndent; fIndent += extraIndent;
@ -860,91 +885,130 @@ public final class CIndenter {
return ref; return ref;
} }
/**
* Enumeration used by {@link #findReferencePosition(int, boolean, MatchMode)} method.
*/
public enum MatchMode {
/**
* The reference position should be returned based on the regular code analysis.
*/
REGULAR,
/**
* The position of the matching brace should be returned instead of doing code analysis.
*/
MATCH_BRACE,
/**
* The position of the matching parenthesis should be returned instead of doing code
* analysis.
*/
MATCH_PAREN,
/**
* The position of a switch statement reference should be returned (either an earlier case
* statement or the switch block brace).
*/
MATCH_CASE,
/**
* The position of a class body reference should be returned (either an earlier
* public/protected/private or the class body brace).
*/
MATCH_ACCESS_SPECIFIER,
/**
* The position of a class declaration should be returned.
*/
MATCH_TYPE_DECLARATION
}
/** /**
* Returns the reference position regarding to indentation for <code>position</code>, * Returns the reference position regarding to indentation for <code>position</code>,
* or <code>NOT_FOUND</code>.<code>fIndent</code> will contain the * or {@link CHeuristicScanner#NOT_FOUND NOT_FOUND}. <code>fIndent</code> will contain
* relative indentation (in indentation units, not characters) after the * the relative indentation (in indentation units, not characters) after the call. If there is
* call. If there is a special alignment (e.g. for a method declaration * a special alignment (e.g. for a method declaration where parameters should be aligned),
* where parameters should be aligned), <code>fAlign</code> will contain * <code>fAlign</code> will contain the absolute position of the alignment reference
* the absolute position of the alignment reference in <code>fDocument</code>, * in <code>fDocument</code>, otherwise <code>fAlign</code> is set to
* otherwise <code>fAlign</code> is set to <code>CHeuristicScanner.NOT_FOUND</code>. * {@link CHeuristicScanner#NOT_FOUND}.
* *
* @param offset the offset for which the reference is computed * @param offset the offset for which the reference is computed
* @param danglingElse whether a dangling else should be assumed at <code>position</code> * @param danglingElse whether a dangling else should be assumed at <code>position</code>
* @param matchBrace whether the position of the matching brace should be * @param matchMode determines what kind of reference position should be returned.
* returned instead of doing code analysis * See {@link MatchMode}.
* @param matchParen whether the position of the matching parenthesis
* should be returned instead of doing code analysis
* @param matchCase whether the position of a switch statement reference
* should be returned (either an earlier case statement or the
* switch block brace)
* @param matchAccessSpecifier whether the position of a class body reference
* should be returned (either an earlier public/protected/private
* or the class body brace)
* @return the reference statement relative to which <code>position</code> * @return the reference statement relative to which <code>position</code>
* should be indented, or {@link CHeuristicScanner#NOT_FOUND} * should be indented, or {@link CHeuristicScanner#NOT_FOUND}
*/ */
public int findReferencePosition(int offset, boolean danglingElse, boolean matchBrace, boolean matchParen, public int findReferencePosition(int offset, boolean danglingElse, MatchMode matchMode) {
boolean matchCase, boolean matchAccessSpecifier) {
fIndent= 0; // The indentation modification fIndent= 0; // The indentation modification
fExtraSpaces= 0; fExtraSpaces= 0;
fAlign= CHeuristicScanner.NOT_FOUND; fAlign= NOT_FOUND;
fPosition= offset; fPosition= offset;
// forward cases // Forward cases.
// An unindentation happens sometimes if the next token is special, namely on braces, parens and case // An unindentation happens sometimes if the next token is special, namely on braces,
// labels align braces, but handle the case where we align with the method declaration start instead // parens and case labels align braces, but handle the case where we align with the method
// of the opening brace. // declaration start instead of the opening brace.
if (matchBrace) { switch (matchMode) {
case MATCH_BRACE:
if (skipScope(Symbols.TokenLBRACE, Symbols.TokenRBRACE)) { if (skipScope(Symbols.TokenLBRACE, Symbols.TokenRBRACE)) {
try { try {
// Align with the opening brace that is on a line by its own // Align with the opening brace that is on a line by its own
int lineOffset= fDocument.getLineOffset(fLine); int lineOffset= fDocument.getLineOffset(fLine);
if (lineOffset <= fPosition && fDocument.get(lineOffset, fPosition - lineOffset).trim().length() == 0) if (lineOffset <= fPosition &&
fDocument.get(lineOffset, fPosition - lineOffset).trim().isEmpty()) {
return fPosition; return fPosition;
}
} catch (BadLocationException e) { } catch (BadLocationException e) {
// Concurrent modification - walk default path // Concurrent modification - walk default path
} }
// If the opening brace is not on the start of the line, skip to the start // If the opening brace is not on the start of the line, skip to the start.
int pos= skipToStatementStart(true, true); int pos= skipToStatementStart(true, true);
fIndent= 0; // indent is aligned with reference position fIndent= 0; // indent is aligned with reference position
return pos; return pos;
} else { } else {
// If we can't find the matching brace, the heuristic is to unindent // If we can't find the matching brace, the heuristic is to unindent
// by one against the normal position // by one against the normal position
int pos= findReferencePosition(offset, danglingElse, false, matchParen, matchCase, int pos= findReferencePosition(offset, danglingElse, MatchMode.REGULAR);
matchAccessSpecifier);
fIndent--; fIndent--;
return pos; return pos;
} }
}
// Align parentheses case MATCH_PAREN:
if (matchParen) { // Align parentheses.
if (skipScope(Symbols.TokenLPAREN, Symbols.TokenRPAREN)) { if (skipScope(Symbols.TokenLPAREN, Symbols.TokenRPAREN)) {
return fPosition; return fPosition;
} else { } else {
// if we can't find the matching paren, the heuristic is to unindent // If we can't find the matching paren, the heuristic is to unindent by one
// by one against the normal position // against the normal position.
int pos= findReferencePosition(offset, danglingElse, matchBrace, false, matchCase, int pos= findReferencePosition(offset, danglingElse, MatchMode.REGULAR);
matchAccessSpecifier);
fIndent--; fIndent--;
return pos; return pos;
} }
}
// The only reliable way to get case labels aligned (due to many different styles of using braces in case MATCH_CASE:
// a block) is to go for another case statement, or the scope opening brace. // The only reliable way to get case labels aligned (due to many different styles of
if (matchCase) { // using braces in a block) is to go for another case statement, or the scope opening
// brace.
return matchCaseAlignment(); return matchCaseAlignment();
case MATCH_ACCESS_SPECIFIER:
// The only reliable way to get access specifiers aligned (due to many different styles
// of using braces in a block) is to go for another access specifier, or the scope
// opening brace.
return matchAccessSpecifierAlignment();
case MATCH_TYPE_DECLARATION:
return matchTypeDeclaration();
case REGULAR:
break;
} }
// the only reliable way to get access specifiers aligned (due to many different styles of using if (peekToken(offset) == Symbols.TokenCOLON) {
// braces in a block) is to go for another access specifier, or the scope opening brace. int pos= fPosition;
if (matchAccessSpecifier) { if (looksLikeTypeInheritanceDecl()) {
return matchAccessSpecifierAlignment(); fIndent = fPrefs.prefContinuationIndent;
return fPosition;
}
fPosition = pos;
} }
nextToken(); nextToken();
// Skip access specifiers // Skip access specifiers
while (fToken == Symbols.TokenCOLON && isAccessSpecifier()) { while (fToken == Symbols.TokenCOLON && isAccessSpecifier()) {
@ -955,21 +1019,21 @@ public final class CIndenter {
switch (fToken) { switch (fToken) {
case Symbols.TokenGREATERTHAN: case Symbols.TokenGREATERTHAN:
case Symbols.TokenRBRACE: case Symbols.TokenRBRACE:
// skip the block and fall through // Skip the block and fall through.
// if we can't complete the scope, reset the scan position // If we can't complete the scope, reset the scan position
int pos= fPosition; int pos= fPosition;
if (!skipScope()) if (!skipScope())
fPosition= pos; fPosition= pos;
return skipToStatementStart(danglingElse, false); return skipToStatementStart(danglingElse, false);
case Symbols.TokenSEMICOLON: case Symbols.TokenSEMICOLON:
// this is the 90% case: after a statement block // This is the 90% case: after a statement block
// the end of the previous statement / block previous.end // the end of the previous statement / block previous.end
// search to the end of the statement / block before the previous; // search to the end of the statement / block before the previous;
// the token just after that is previous.start // the token just after that is previous.start
return skipToStatementStart(danglingElse, false); return skipToStatementStart(danglingElse, false);
// scope introduction: special treat who special is // Scope introduction: special treat who special is
case Symbols.TokenLPAREN: case Symbols.TokenLPAREN:
case Symbols.TokenLBRACE: case Symbols.TokenLBRACE:
case Symbols.TokenLBRACKET: case Symbols.TokenLBRACKET:
@ -977,7 +1041,7 @@ public final class CIndenter {
case Symbols.TokenEOF: case Symbols.TokenEOF:
// trap when hitting start of document // trap when hitting start of document
return CHeuristicScanner.NOT_FOUND; return NOT_FOUND;
case Symbols.TokenEQUAL: case Symbols.TokenEQUAL:
// indent assignments // indent assignments
@ -992,7 +1056,7 @@ public final class CIndenter {
} }
fPosition= pos; fPosition= pos;
if (looksLikeTypeInheritanceDecl()) { if (looksLikeTypeInheritanceDecl()) {
fIndent= fPrefs.prefBlockIndent; fIndent= fPrefs.prefContinuationIndent;
return pos; return pos;
} }
fPosition= pos; fPosition= pos;
@ -1114,10 +1178,10 @@ public final class CIndenter {
if (fToken == Symbols.TokenSEMICOLON || fToken == Symbols.TokenEOF) { if (fToken == Symbols.TokenSEMICOLON || fToken == Symbols.TokenEOF) {
return pos; return pos;
} else { } else {
return CHeuristicScanner.NOT_FOUND; return NOT_FOUND;
} }
} else { } else {
return CHeuristicScanner.NOT_FOUND; return NOT_FOUND;
} }
} }
} }
@ -1341,6 +1405,13 @@ public final class CIndenter {
return fPreviousPos; return fPreviousPos;
case Symbols.TokenCOLON: case Symbols.TokenCOLON:
switch (prevToken) {
case Symbols.TokenPRIVATE:
case Symbols.TokenPROTECTED:
case Symbols.TokenPUBLIC:
case Symbols.TokenVIRTUAL:
continue; // Don't stop at colon in a class declaration
}
int pos= fPreviousPos; int pos= fPreviousPos;
if (!isConditional()) if (!isConditional())
return pos; return pos;
@ -1549,7 +1620,7 @@ public final class CIndenter {
int typeDeclPos= matchTypeDeclaration(); int typeDeclPos= matchTypeDeclaration();
fIndent= fPrefs.prefAccessSpecifierIndent; fIndent= fPrefs.prefAccessSpecifierIndent;
fExtraSpaces = fPrefs.prefAccessSpecifierExtraSpaces; fExtraSpaces = fPrefs.prefAccessSpecifierExtraSpaces;
if (typeDeclPos != CHeuristicScanner.NOT_FOUND) { if (typeDeclPos != NOT_FOUND) {
return typeDeclPos; return typeDeclPos;
} }
return pos; return pos;
@ -1799,7 +1870,7 @@ public final class CIndenter {
fIndent = fPrefs.prefTypeIndent; fIndent = fPrefs.prefTypeIndent;
} else { } else {
int typeDeclPos = matchTypeDeclaration(); int typeDeclPos = matchTypeDeclaration();
if (typeDeclPos == CHeuristicScanner.NOT_FOUND) { if (typeDeclPos == NOT_FOUND) {
fIndent= fPrefs.prefBlockIndent; fIndent= fPrefs.prefBlockIndent;
} else { } else {
fIndent= fPrefs.prefAccessSpecifierIndent + fPrefs.prefTypeIndent; fIndent= fPrefs.prefAccessSpecifierIndent + fPrefs.prefTypeIndent;
@ -1845,7 +1916,7 @@ public final class CIndenter {
private int setFirstElementAlignment(int scopeIntroducerOffset, int bound) { private int setFirstElementAlignment(int scopeIntroducerOffset, int bound) {
int firstPossible= scopeIntroducerOffset + 1; // align with the first position after the scope intro int firstPossible= scopeIntroducerOffset + 1; // align with the first position after the scope intro
fAlign= fScanner.findNonWhitespaceForwardInAnyPartition(firstPossible, bound); fAlign= fScanner.findNonWhitespaceForwardInAnyPartition(firstPossible, bound);
if (fAlign == CHeuristicScanner.NOT_FOUND) { if (fAlign == NOT_FOUND) {
fAlign= firstPossible; fAlign= firstPossible;
} else { } else {
try { try {