diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/DefaultCodeFormatterOptions.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/DefaultCodeFormatterOptions.java index 3f57b84a6f6..aaae54b5462 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/DefaultCodeFormatterOptions.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/DefaultCodeFormatterOptions.java @@ -1785,7 +1785,6 @@ public class DefaultCodeFormatterOptions { this.brace_position_for_array_initializer = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED; this.brace_position_for_block = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED; this.brace_position_for_block_in_case = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED; -// this.brace_position_for_enum_declaration = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED; this.brace_position_for_method_declaration = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED; this.brace_position_for_type_declaration = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED; this.brace_position_for_namespace_declaration = DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED; @@ -1794,8 +1793,7 @@ public class DefaultCodeFormatterOptions { this.indent_statements_compare_to_block = false; this.indent_statements_compare_to_body = false; this.indent_body_declarations_compare_to_namespace_header = false; -// this.indent_body_declarations_compare_to_enum_declaration_header = true; - this.indent_body_declarations_compare_to_access_specifier = false; + this.indent_body_declarations_compare_to_access_specifier = true; this.indent_breaks_compare_to_cases = true; this.indent_empty_lines = false; this.indent_switchstatements_compare_to_cases = true; diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CIndenterTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CIndenterTest.java index 410726c0713..796c04d6af7 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CIndenterTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/text/CIndenterTest.java @@ -19,6 +19,8 @@ import org.eclipse.jface.text.Document; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.source.LineRange; +import org.eclipse.cdt.core.CCorePlugin; +import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants; import org.eclipse.cdt.ui.tests.BaseUITestCase; import org.eclipse.cdt.internal.formatter.DefaultCodeFormatterOptions; @@ -35,7 +37,7 @@ import org.eclipse.cdt.internal.ui.text.CIndenter; */ public class CIndenterTest extends BaseUITestCase { - private Map fOptions; + private HashMap fOptions; private Map fDefaultOptions; public static TestSuite suite() { @@ -45,14 +47,16 @@ public class CIndenterTest extends BaseUITestCase { protected void setUp() throws Exception { super.setUp(); fDefaultOptions= DefaultCodeFormatterOptions.getDefaultSettings().getMap(); - fOptions= new HashMap(fDefaultOptions); + fOptions= new HashMap(); } protected void tearDown() throws Exception { + CCorePlugin.setOptions(new HashMap(fDefaultOptions)); super.tearDown(); } protected void assertIndenterResult() throws Exception { + CCorePlugin.setOptions(fOptions); StringBuffer[] contents= getContentsForTest(2); String before= contents[0].toString(); IDocument document= new Document(before); @@ -276,4 +280,183 @@ public class CIndenterTest extends BaseUITestCase { public void testIndentationOfNestedInitializerLists_Bug194585() throws Exception { assertIndenterResult(); } + + //// a comment + //class MyClass + //{ + //}; + // union DisUnion + // { + //}; + + //// a comment + //class MyClass + // { + // }; + //union DisUnion + // { + // }; + public void testIndentedClassIndentation_Bug210417() throws Exception { + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION, + DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED); + assertIndenterResult(); + } + + //// a comment + //class MyClass : public Base + //{ + //}; + + //// a comment + //class MyClass : public Base + // { + // }; + public void testIndentedClassIndentation_Bug210417_2() throws Exception { + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION, + DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED); + assertIndenterResult(); + } + + //// a comment + //class MyClass : public Base, public OtherBase + //{ + //}; + + //// a comment + //class MyClass : public Base, public OtherBase + // { + // }; + public void testIndentedClassIndentation_Bug210417_3() throws Exception { + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION, + DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED); + assertIndenterResult(); + } + + //// a comment + //class MyClass : public Base, public OtherBase + //{ + //}; + + //// a comment + //class MyClass : public Base, public OtherBase + // { + // }; + public void testIndentedClassIndentation_Bug210417_4() throws Exception { + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION, + DefaultCodeFormatterConstants.NEXT_LINE_SHIFTED); + assertIndenterResult(); + } + + //class A + //{ + //public: + //A(); + //}; + + //class A + // { + //public: + // A(); + // }; + public void testWhiteSmithsAccessSpecifierIndentation1_Bug204575() throws Exception { + fOptions.putAll(DefaultCodeFormatterOptions.getWhitesmithsSettings().getMap()); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_ACCESS_SPECIFIER_COMPARE_TO_TYPE_HEADER, DefaultCodeFormatterConstants.FALSE); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_ACCESS_SPECIFIER, DefaultCodeFormatterConstants.TRUE); + assertIndenterResult(); + } + + //class A + //{ + //public: + //A(); + //}; + + //class A + // { + // public: + // A(); + // }; + public void testWhiteSmithsAccessSpecifierIndentation2_Bug204575() throws Exception { + fOptions.putAll(DefaultCodeFormatterOptions.getWhitesmithsSettings().getMap()); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_ACCESS_SPECIFIER_COMPARE_TO_TYPE_HEADER, DefaultCodeFormatterConstants.TRUE); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_ACCESS_SPECIFIER, DefaultCodeFormatterConstants.FALSE); + assertIndenterResult(); + } + + //class A + //{ + //public: + //A(); + //}; + + //class A + // { + // public: + // A(); + // }; + public void testWhiteSmithsAccessSpecifierIndentation3_Bug204575() throws Exception { + fOptions.putAll(DefaultCodeFormatterOptions.getWhitesmithsSettings().getMap()); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_ACCESS_SPECIFIER_COMPARE_TO_TYPE_HEADER, DefaultCodeFormatterConstants.TRUE); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_BODY_DECLARATIONS_COMPARE_TO_ACCESS_SPECIFIER, DefaultCodeFormatterConstants.TRUE); + assertIndenterResult(); + } + + //void f() + //{ + //switch(x) + //{ + //case 1: + //doOne(); + //default: + //doOther(); + //} + //} + + //void f() + // { + // switch(x) + // { + // case 1: + // doOne(); + // default: + // doOther(); + // } + // } + public void testWhiteSmithsSwitchIndentation1() throws Exception { + fOptions.putAll(DefaultCodeFormatterOptions.getWhitesmithsSettings().getMap()); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_CASES, DefaultCodeFormatterConstants.TRUE); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH, DefaultCodeFormatterConstants.FALSE); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, DefaultCodeFormatterConstants.MIXED); + assertIndenterResult(); + } + + //void f() + //{ + //switch(x) + //{ + //case 1: + //doOne(); + //default: + //doOther(); + //} + //} + + //void f() + // { + // switch(x) + // { + // case 1: + // doOne(); + // default: + // doOther(); + // } + // } + public void testWhiteSmithsSwitchIndentation2() throws Exception { + fOptions.putAll(DefaultCodeFormatterOptions.getWhitesmithsSettings().getMap()); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_CASES, DefaultCodeFormatterConstants.FALSE); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH, DefaultCodeFormatterConstants.TRUE); + fOptions.put(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR, CCorePlugin.TAB); + assertIndenterResult(); + } + } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java index 650fd0e790d..16b3393ef39 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/text/CIndenter.java @@ -185,17 +185,14 @@ public final class CIndenter { private int prefCaseIndent() { if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_SWITCH))) - return prefBlockIndent(); + return 1; else return 0; } private int prefCaseBlockIndent() { - if (true) - return prefBlockIndent(); - if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_SWITCHSTATEMENTS_COMPARE_TO_CASES))) - return prefBlockIndent(); + return 1; else return 0; } @@ -305,7 +302,7 @@ public final class CIndenter { private int prefAccessSpecifierIndent() { if (DefaultCodeFormatterConstants.TRUE.equals(getCoreFormatterOption(DefaultCodeFormatterConstants.FORMATTER_INDENT_ACCESS_SPECIFIER_COMPARE_TO_TYPE_HEADER))) - return prefBlockIndent(); + return 1; else return 0; } @@ -430,7 +427,7 @@ public final class CIndenter { if (assumeOpeningBrace) unit= findReferencePosition(offset, Symbols.TokenLBRACE); else - unit= findReferencePosition(offset, peekChar(offset)); + unit= findReferencePosition(offset, peekToken(offset)); // if we were unable to find anything, return null if (unit == CHeuristicScanner.NOT_FOUND) @@ -686,17 +683,17 @@ public final class CIndenter { * should be indented, or {@link CHeuristicScanner#NOT_FOUND} */ public int findReferencePosition(int offset) { - return findReferencePosition(offset, peekChar(offset)); + return findReferencePosition(offset, peekToken(offset)); } /** - * Peeks the next char in the document that comes after offset + * Peeks the next token in the document that comes after offset * on the same line as offset. * * @param offset the offset into document * @return the token symbol of the next element, or TokenEOF if there is none */ - private int peekChar(int offset) { + private int peekToken(int offset) { if (offset < fDocument.getLength()) { try { IRegion line= fDocument.getLineInformationOfOffset(offset); @@ -777,13 +774,15 @@ public final class CIndenter { break; case Symbols.TokenLBRACE: // for opening-brace-on-new-line style - if (bracelessBlockStart && !fPrefs.prefIndentBracesForBlocks) - unindent= true; + if (bracelessBlockStart) + unindent= !fPrefs.prefIndentBracesForBlocks; else if (prevToken == Symbols.TokenCOLON && !fPrefs.prefIndentBracesForBlocks) unindent= true; else if ((prevToken == Symbols.TokenEQUAL || prevToken == Symbols.TokenRBRACKET) && !fPrefs.prefIndentBracesForArrays) unindent= true; - else if (!bracelessBlockStart && fPrefs.prefIndentBracesForMethods) + else if (prevToken == Symbols.TokenRPAREN && fPrefs.prefIndentBracesForMethods) + indent= true; + else if (prevToken == Symbols.TokenIDENT && fPrefs.prefIndentBracesForTypes) indent= true; break; @@ -807,8 +806,10 @@ public final class CIndenter { int ref= findReferencePosition(offset, danglingElse, matchBrace, matchParen, matchCase, matchAccessSpecifier); if (unindent) fIndent--; - if (indent) + if (indent) { + fAlign= CHeuristicScanner.NOT_FOUND; fIndent++; + } return ref; } @@ -926,14 +927,24 @@ public final class CIndenter { case Symbols.TokenCOLON: pos= fPosition; + if (isAccessSpecifier()) { + fIndent= fPrefs.prefTypeIndent; + return pos; + } + fPosition= pos; if (looksLikeCaseStatement()) { fIndent= fPrefs.prefCaseBlockIndent; return pos; - } else { - // TODO handle ternary deep indentation - fPosition= pos; - return skipToStatementStart(danglingElse, false); } + fPosition= pos; + if (looksLikeTypeInheritanceDecl()) { + fIndent= fPrefs.prefBlockIndent; + return pos; + } + // TODO handle ternary deep indentation + fPosition= pos; + return skipToStatementStart(danglingElse, false); + case Symbols.TokenQUESTIONMARK: if (fPrefs.prefTernaryDeepAlign) { setFirstElementAlignment(fPosition, offset + 1); @@ -952,6 +963,7 @@ public final class CIndenter { case Symbols.TokenTRY: return skipToStatementStart(danglingElse, false); + case Symbols.TokenRPAREN: int line= fLine; if (skipScope(Symbols.TokenLPAREN, Symbols.TokenRPAREN)) { @@ -961,6 +973,9 @@ public final class CIndenter { fIndent= fPrefs.prefSimpleIndent; return fPosition; } + if (fToken == Symbols.TokenSWITCH) { + return fPosition; + } fPosition= scope; if (looksLikeMethodDecl()) { return skipToStatementStart(danglingElse, false); @@ -991,9 +1006,46 @@ public final class CIndenter { } } + /** + * Test whether an identifier encountered during scanning is part of + * a type declaration, by scanning backward and ignoring any identifiers, commas, + * and colons until we hit class, struct, union, + * or enum. If any braces, semicolons, or parentheses are encountered, + * this is not a type declaration. + * @return the reference offset of the start of the statement + */ + private int matchTypeDeclaration() { + while (true) { + nextToken(); + if (fToken == Symbols.TokenIDENT + || fToken == Symbols.TokenCOMMA + || fToken == Symbols.TokenCOLON + || fToken == Symbols.TokenPUBLIC + || fToken == Symbols.TokenPROTECTED + || fToken == Symbols.TokenPRIVATE) { + continue; + } + else if (fToken == Symbols.TokenCLASS + || fToken == Symbols.TokenSTRUCT + || fToken == Symbols.TokenUNION + || fToken == Symbols.TokenENUM) { + // inside a type declaration? Only so if not preceded by '(' or ',' as in + // a parameter list. To be safe, only accept ';' or EOF + int pos= fPosition; + nextToken(); + if (fToken == Symbols.TokenSEMICOLON || fToken == Symbols.TokenEOF) { + return pos; + } else { + return CHeuristicScanner.NOT_FOUND; + } + } + else + return CHeuristicScanner.NOT_FOUND; + } + } + /** * Test whether the colon at the current position marks a case statement - * (or a similar construct increasing the indent). * * @return true if this looks like a case statement */ @@ -1010,9 +1062,6 @@ public final class CIndenter { } switch (fToken) { case Symbols.TokenCASE: - case Symbols.TokenCLASS: - case Symbols.TokenSTRUCT: - case Symbols.TokenUNION: return true; } break; @@ -1022,8 +1071,49 @@ public final class CIndenter { case Symbols.TokenCASE: return true; } - case Symbols.TokenRPAREN: // constructor initializer case Symbols.TokenDEFAULT: + return true; + } + return false; + } + + /** + * Test whether the colon at the current position marks a type inheritance decl. + * + * @return true if this looks like a a type inheritance decl + */ + private boolean looksLikeTypeInheritanceDecl() { + nextToken(); + switch (fToken) { + case Symbols.TokenIDENT: + nextToken(); + while (skipQualifiers()) { + nextToken(); + } + switch (fToken) { + case Symbols.TokenCLASS: + case Symbols.TokenSTRUCT: + case Symbols.TokenUNION: + return true; + } + break; + case Symbols.TokenRPAREN: // constructor initializer + case Symbols.TokenPUBLIC: + case Symbols.TokenPROTECTED: + case Symbols.TokenPRIVATE: + return true; + } + return false; + } + + /** + * Test whether the colon at the current position marks an access specifier. + * + * @return true if current position marks an access specifier + */ + private boolean isAccessSpecifier() { + nextToken(); + switch (fToken) { case Symbols.TokenPUBLIC: case Symbols.TokenPROTECTED: case Symbols.TokenPRIVATE: @@ -1046,6 +1136,7 @@ public final class CIndenter { int mayBeMethodBody= NOTHING; boolean isTypeBody= false; while (true) { + int prevToken= fToken; nextToken(); if (isInBlock) { @@ -1097,13 +1188,18 @@ public final class CIndenter { // RBRACE is a little tricky: it can be the end of an array definition, but // usually it is the end of a previous block pos= fPreviousPos; // store state - if (skipScope() && looksLikeArrayInitializerIntro()) { - continue; // it's an array - } else { - if (isInBlock) - fIndent= getBlockIndent(mayBeMethodBody == READ_IDENT, isTypeBody); - return pos; // it's not - do as with all the above + if (skipScope()) { + if (looksLikeArrayInitializerIntro()) { + continue; // it's an array + } + if (prevToken == Symbols.TokenSEMICOLON) { + // end of type def + continue; + } } + if (isInBlock) + fIndent= getBlockIndent(mayBeMethodBody == READ_IDENT, isTypeBody); + return pos; // it's not - do as with all the above // scopes: skip them case Symbols.TokenRPAREN: @@ -1230,8 +1326,8 @@ public final class CIndenter { case Symbols.TokenEOF: return fPosition; - case Symbols.TokenLBRACE: - // opening brace of switch statement + case Symbols.TokenSWITCH: + // start of switch statement fIndent= fPrefs.prefCaseIndent; return fPosition; @@ -1278,9 +1374,13 @@ public final class CIndenter { case Symbols.TokenLBRACE: // opening brace of class body + int pos= fPosition; + int typeDeclPos= matchTypeDeclaration(); fIndent= fPrefs.prefAccessSpecifierIndent; - return fPosition; - + if (typeDeclPos != CHeuristicScanner.NOT_FOUND) { + return typeDeclPos; + } + return pos; case Symbols.TokenPUBLIC: case Symbols.TokenPROTECTED: case Symbols.TokenPRIVATE: