diff --git a/clang/lib/Format/FormatTokenLexer.h b/clang/lib/Format/FormatTokenLexer.h --- a/clang/lib/Format/FormatTokenLexer.h +++ b/clang/lib/Format/FormatTokenLexer.h @@ -114,7 +114,12 @@ unsigned FirstInLineIndex; SmallVector Tokens; - llvm::SmallMapVector Macros; + struct MacroTokenInfo { + TokenType Type; + bool Finalized; + }; + + llvm::SmallMapVector Macros; bool FormattingDisabled; diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -39,37 +39,38 @@ for (const std::string &ForEachMacro : Style.ForEachMacros) { auto Identifier = &IdentTable.get(ForEachMacro); - Macros.insert({Identifier, TT_ForEachMacro}); + Macros.insert({Identifier, {TT_ForEachMacro, /*Finalized=*/false}}); } for (const std::string &IfMacro : Style.IfMacros) { auto Identifier = &IdentTable.get(IfMacro); - Macros.insert({Identifier, TT_IfMacro}); + Macros.insert({Identifier, {TT_IfMacro, /*Finalized=*/false}}); } for (const std::string &AttributeMacro : Style.AttributeMacros) { auto Identifier = &IdentTable.get(AttributeMacro); - Macros.insert({Identifier, TT_AttributeMacro}); + Macros.insert({Identifier, {TT_AttributeMacro, /*Finalized=*/false}}); } for (const std::string &StatementMacro : Style.StatementMacros) { auto Identifier = &IdentTable.get(StatementMacro); - Macros.insert({Identifier, TT_StatementMacro}); + Macros.insert({Identifier, {TT_StatementMacro, /*Finalized=*/false}}); } for (const std::string &TypenameMacro : Style.TypenameMacros) { auto Identifier = &IdentTable.get(TypenameMacro); - Macros.insert({Identifier, TT_TypenameMacro}); + Macros.insert({Identifier, {TT_TypenameMacro, /*Finalized=*/false}}); } for (const std::string &NamespaceMacro : Style.NamespaceMacros) { auto Identifier = &IdentTable.get(NamespaceMacro); - Macros.insert({Identifier, TT_NamespaceMacro}); + Macros.insert({Identifier, {TT_NamespaceMacro, /*Finalized=*/false}}); } for (const std::string &WhitespaceSensitiveMacro : Style.WhitespaceSensitiveMacros) { auto Identifier = &IdentTable.get(WhitespaceSensitiveMacro); - Macros.insert({Identifier, TT_UntouchableMacroFunc}); + Macros.insert({Identifier, {TT_UntouchableMacroFunc, /*Finalized=*/true}}); } for (const std::string &StatementAttributeLikeMacro : Style.StatementAttributeLikeMacros) { auto Identifier = &IdentTable.get(StatementAttributeLikeMacro); - Macros.insert({Identifier, TT_StatementAttributeLikeMacro}); + Macros.insert( + {Identifier, {TT_StatementAttributeLikeMacro, /*Finalized=*/false}}); } } @@ -1027,8 +1028,12 @@ Tokens.back()->Tok.getIdentifierInfo()->getPPKeywordID() == tok::pp_define) && it != Macros.end()) { - FormatTok->setType(it->second); - if (it->second == TT_IfMacro) { + if (it->second.Finalized) { + FormatTok->setFinalizedType(it->second.Type); + } else { + FormatTok->setType(it->second.Type); + } + if (it->second.Type == TT_IfMacro) { // The lexer token currently has type tok::kw_unknown. However, for this // substitution to be treated correctly in the TokenAnnotator, faking // the tok value seems to be needed. Not sure if there's a more elegant diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -1787,7 +1787,8 @@ : CommentsBeforeNextToken.front()->NewlinesBefore > 0; if (FollowedByNewline && (Text.size() >= 5 || FunctionLike) && - tokenCanStartNewLine(*FormatTok) && Text == Text.upper()) { + tokenCanStartNewLine(*FormatTok) && Text == Text.upper() && + !PreviousToken->isTypeFinalized()) { PreviousToken->setFinalizedType(TT_FunctionLikeOrFreestandingMacro); addUnwrappedLine(); return; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -23540,6 +23540,11 @@ // Don't use the helpers here, since 'mess up' will change the whitespace // and these are all whitespace sensitive by definition + + // Newlines are important here. + EXPECT_EQ("FOO(1+2 );\n", format("FOO(1+2 );\n", Style)); + EXPECT_EQ("FOO(1+2 )\n", format("FOO(1+2 )\n", Style)); + EXPECT_EQ("FOO(String-ized&Messy+But(: :Still)=Intentional);", format("FOO(String-ized&Messy+But(: :Still)=Intentional);", Style)); EXPECT_EQ(