diff options
-rw-r--r-- | lib/Format/UnwrappedLineParser.cpp | 45 | ||||
-rw-r--r-- | lib/Format/UnwrappedLineParser.h | 2 | ||||
-rw-r--r-- | unittests/Format/FormatTest.cpp | 31 |
3 files changed, 54 insertions, 24 deletions
diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index b3671b3040..fe522ac9d8 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -320,8 +320,10 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::kw_struct: // fallthrough case tok::kw_union: // fallthrough case tok::kw_class: - parseStructClassOrBracedList(); - return; + parseRecord(); + // A record declaration or definition is always the start of a structural + // element. + break; case tok::semi: nextToken(); addUnwrappedLine(); @@ -569,30 +571,29 @@ void UnwrappedLineParser::parseEnum() { } while (!eof()); } -void UnwrappedLineParser::parseStructClassOrBracedList() { +void UnwrappedLineParser::parseRecord() { nextToken(); - do { - switch (FormatTok.Tok.getKind()) { - case tok::l_brace: - // FIXME: Think about how to resolve the error handling here. - parseBlock(); - parseStructuralElement(); - return; - case tok::semi: - nextToken(); - addUnwrappedLine(); - return; - case tok::equal: + if (FormatTok.Tok.is(tok::identifier) || + FormatTok.Tok.is(tok::kw___attribute) || + FormatTok.Tok.is(tok::kw___declspec)) { + nextToken(); + // We can have macros or attributes in between 'class' and the class name. + if (FormatTok.Tok.is(tok::l_paren)) { + parseParens(); + } + if (FormatTok.Tok.is(tok::identifier)) nextToken(); - if (FormatTok.Tok.is(tok::l_brace)) { - parseBracedList(); + + if (FormatTok.Tok.is(tok::colon)) { + while (FormatTok.Tok.isNot(tok::l_brace)) { + if (FormatTok.Tok.is(tok::semi)) + return; + nextToken(); } - break; - default: - nextToken(); - break; } - } while (!eof()); + } + if (FormatTok.Tok.is(tok::l_brace)) + parseBlock(); } void UnwrappedLineParser::parseObjCProtocolList() { diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index 487e7019f7..08faff15af 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -146,7 +146,7 @@ private: void parseNamespace(); void parseAccessSpecifier(); void parseEnum(); - void parseStructClassOrBracedList(); + void parseRecord(); void parseObjCProtocolList(); void parseObjCUntilAtEnd(); void parseObjCInterfaceOrImplementation(); diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index f8a81b5982..e9fa666f90 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -1290,8 +1290,37 @@ TEST_F(FormatTest, PullTrivialFunctionDefinitionsIntoSingleLine) { "}"); } -TEST_F(FormatTest, BracedInitListWithElaboratedTypeSpecifier) { +TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) { + // Elaborate type variable declarations. verifyFormat("struct foo a = { bar };\nint n;"); + verifyFormat("class foo a = { bar };\nint n;"); + verifyFormat("union foo a = { bar };\nint n;"); + + // Elaborate types inside function definitions. + verifyFormat("struct foo f() {}\nint n;"); + verifyFormat("class foo f() {}\nint n;"); + verifyFormat("union foo f() {}\nint n;"); + + // Templates. + verifyFormat("template <class X> void f() {}\nint n;"); + verifyFormat("template <struct X> void f() {}\nint n;"); + verifyFormat("template <union X> void f() {}\nint n;"); + + // Actual definitions... + verifyFormat("struct {} n;"); + verifyFormat("template <template <class T, class Y>, class Z > class X {} n;"); + verifyFormat("union Z {\n int n;\n} x;"); + verifyFormat("class MACRO Z {} n;"); + verifyFormat("class MACRO(X) Z {} n;"); + verifyFormat("class __attribute__(X) Z {} n;"); + verifyFormat("class __declspec(X) Z {} n;"); + + // Elaborate types where incorrectly parsing the structural element would + // break the indent. + verifyFormat("if (true)\n" + " class X x;\n" + "else\n" + " f();\n"); } // FIXME: This breaks the order of the unwrapped lines: |