From: Daniel Jasper Date: Wed, 6 May 2015 14:03:02 +0000 (+0000) Subject: clang-format: Accept slightly more record declarations. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1fc06ca35a4e5d126ce29e4116d2465054e2651f;p=clang clang-format: Accept slightly more record declarations. This fixes llvm.org/PR23397. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@236599 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 41c7fd1b22..9461911648 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -1531,38 +1531,40 @@ void UnwrappedLineParser::parseJavaEnumBody() { void UnwrappedLineParser::parseRecord() { const FormatToken &InitialToken = *FormatTok; nextToken(); - if (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::kw___attribute, - tok::kw___declspec, tok::kw_alignas)) { + + + // The actual identifier can be a nested name specifier, and in macros + // it is often token-pasted. + while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::hashhash, + tok::kw___attribute, tok::kw___declspec, + tok::kw_alignas) || + ((Style.Language == FormatStyle::LK_Java || + Style.Language == FormatStyle::LK_JavaScript) && + FormatTok->isOneOf(tok::period, tok::comma))) { + bool IsNonMacroIdentifier = + FormatTok->is(tok::identifier) && + FormatTok->TokenText != FormatTok->TokenText.upper(); nextToken(); // We can have macros or attributes in between 'class' and the class name. - if (FormatTok->Tok.is(tok::l_paren)) { + if (!IsNonMacroIdentifier && FormatTok->Tok.is(tok::l_paren)) parseParens(); - } - // The actual identifier can be a nested name specifier, and in macros - // it is often token-pasted. - while (FormatTok->is(tok::identifier) || FormatTok->is(tok::coloncolon) || - FormatTok->is(tok::hashhash) || - ((Style.Language == FormatStyle::LK_Java || - Style.Language == FormatStyle::LK_JavaScript) && - FormatTok->isOneOf(tok::period, tok::comma))) - nextToken(); + } - // Note that parsing away template declarations here leads to incorrectly - // accepting function declarations as record declarations. - // In general, we cannot solve this problem. Consider: - // class A B() {} - // which can be a function definition or a class definition when B() is a - // macro. If we find enough real-world cases where this is a problem, we - // can parse for the 'template' keyword in the beginning of the statement, - // and thus rule out the record production in case there is no template - // (this would still leave us with an ambiguity between template function - // and class declarations). - if (FormatTok->Tok.is(tok::colon) || FormatTok->Tok.is(tok::less)) { - while (!eof() && FormatTok->Tok.isNot(tok::l_brace)) { - if (FormatTok->Tok.is(tok::semi)) - return; - nextToken(); - } + // Note that parsing away template declarations here leads to incorrectly + // accepting function declarations as record declarations. + // In general, we cannot solve this problem. Consider: + // class A B() {} + // which can be a function definition or a class definition when B() is a + // macro. If we find enough real-world cases where this is a problem, we + // can parse for the 'template' keyword in the beginning of the statement, + // and thus rule out the record production in case there is no template + // (this would still leave us with an ambiguity between template function + // and class declarations). + if (FormatTok->Tok.is(tok::colon) || FormatTok->Tok.is(tok::less)) { + while (!eof() && FormatTok->Tok.isNot(tok::l_brace)) { + if (FormatTok->Tok.is(tok::semi)) + return; + nextToken(); } } if (FormatTok->Tok.is(tok::l_brace)) { diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 7e75de4409..9173061c97 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -6396,6 +6396,8 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) { verifyFormat("class __declspec(X) Z {\n} n;"); verifyFormat("class A##B##C {\n} n;"); verifyFormat("class alignas(16) Z {\n} n;"); + verifyFormat("class MACRO(X) alignas(16) Z {\n} n;"); + verifyFormat("class MACROA MACRO(X) Z {\n} n;"); // Redefinition from nested context: verifyFormat("class A::B::C {\n} n;");