diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h --- a/clang/lib/Format/TokenAnnotator.h +++ b/clang/lib/Format/TokenAnnotator.h @@ -40,7 +40,7 @@ : First(Line.Tokens.front().Tok), Level(Line.Level), MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex), MatchingClosingBlockLineIndex(Line.MatchingClosingBlockLineIndex), - InPPDirective(Line.InPPDirective), + InPPDirective(Line.InPPDirective), InMacroBody(Line.InMacroBody), MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false), IsMultiVariableDeclStmt(false), Affected(false), LeadingEmptyLinesAffected(false), ChildrenAffected(false), @@ -130,6 +130,7 @@ size_t MatchingOpeningBlockLineIndex; size_t MatchingClosingBlockLineIndex; bool InPPDirective; + bool InMacroBody; bool MustBeDeclaration; bool MightBeFunctionDecl; bool IsMultiVariableDeclStmt; diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -1427,7 +1427,7 @@ if (!CurrentToken) return LT_Invalid; NonTemplateLess.clear(); - if (CurrentToken->is(tok::hash)) { + if (!Line.InMacroBody && CurrentToken->is(tok::hash)) { // We were not yet allowed to use C++17 optional when this was being // written. So we used LT_Invalid to mark that the line is not a // preprocessor directive. @@ -4241,7 +4241,7 @@ return false; } if (Right.is(tok::less) && Left.isNot(tok::l_paren) && - Line.startsWith(tok::hash)) { + Line.Type == LT_ImportStatement) { return true; } if (Right.is(TT_TrailingUnaryOperator)) diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -46,6 +46,8 @@ /// Whether this \c UnwrappedLine is part of a preprocessor directive. bool InPPDirective; + /// Whether it is part of a macro body. + bool InMacroBody; bool MustBeDeclaration; @@ -353,8 +355,8 @@ }; inline UnwrappedLine::UnwrappedLine() - : Level(0), InPPDirective(false), MustBeDeclaration(false), - MatchingOpeningBlockLineIndex(kInvalidIndex) {} + : Level(0), InPPDirective(false), InMacroBody(false), + MustBeDeclaration(false), MatchingOpeningBlockLineIndex(kInvalidIndex) {} } // end namespace format } // end namespace clang 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 @@ -116,12 +116,14 @@ TokenSource = this; Line.Level = 0; Line.InPPDirective = true; + // InMacroBody gets set after the `#define x` part. } ~ScopedMacroState() override { TokenSource = PreviousTokenSource; ResetToken = Token; Line.InPPDirective = false; + Line.InMacroBody = false; Line.Level = PreviousLineLevel; } @@ -196,6 +198,7 @@ Parser.Line = std::make_unique(); Parser.Line->Level = PreBlockLine->Level; Parser.Line->InPPDirective = PreBlockLine->InPPDirective; + Parser.Line->InMacroBody = PreBlockLine->InMacroBody; } ~ScopedLineState() { @@ -1253,6 +1256,7 @@ Line->Level += PPBranchLevel + 1; addUnwrappedLine(); ++Line->Level; + Line->InMacroBody = true; // Errors during a preprocessor directive can only affect the layout of the // preprocessor directive, and thus we ignore them. An alternative approach 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 @@ -9864,6 +9864,10 @@ verifyFormat("Constructor(A... a) : a_(X{std::forward(a)}...) {}"); verifyFormat("< < < < < < < < < < < < < < < < < < < < < < < < < < < < < <"); verifyFormat("some_templated_type"); + + verifyFormat("#define FOO(typeName, realClass) \\\n" + " { #typeName, foo(new foo(#typeName)) }", + getLLVMStyleWithColumns(60)); } TEST_F(FormatTest, UnderstandsShiftOperators) { diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -284,6 +284,17 @@ EXPECT_TOKEN(Tokens[13], tok::ampamp, TT_BinaryOperator); } +TEST_F(TokenAnnotatorTest, UnderstandsTemplatesInMacros) { + auto Tokens = + annotate("#define FOO(typeName) \\\n" + " { #typeName, foo(new foo(#typeName)) }"); + ASSERT_EQ(Tokens.size(), 27u) << Tokens; + EXPECT_TOKEN(Tokens[11], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[13], tok::greater, TT_TemplateCloser); + EXPECT_TOKEN(Tokens[17], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[19], tok::greater, TT_TemplateCloser); +} + TEST_F(TokenAnnotatorTest, UnderstandsWhitespaceSensitiveMacros) { FormatStyle Style = getLLVMStyle(); Style.WhitespaceSensitiveMacros.push_back("FOO");