diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 64e936f627d43..8cd2edaf4fbcd 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -137,9 +137,8 @@ class AnnotatingParser { private: ScopeType getScopeType(const FormatToken &Token) const { switch (Token.getType()) { - case TT_FunctionLBrace: case TT_LambdaLBrace: - return ST_Function; + return ST_ChildBlock; case TT_ClassLBrace: case TT_StructLBrace: case TT_UnionLBrace: @@ -400,7 +399,8 @@ class AnnotatingParser { OpeningParen.Previous->MatchingParen->isOneOf( TT_ObjCBlockLParen, TT_FunctionTypeLParen)) { Contexts.back().IsExpression = false; - } else if (!Line.MustBeDeclaration && !Line.InPPDirective) { + } else if (!Line.MustBeDeclaration && + (!Line.InPPDirective || (Line.InMacroBody && !Scopes.empty()))) { bool IsForOrCatch = OpeningParen.Previous && OpeningParen.Previous->isOneOf(tok::kw_for, tok::kw_catch); @@ -3650,11 +3650,21 @@ static bool isCtorOrDtorName(const FormatToken *Tok) { } void TokenAnnotator::annotate(AnnotatedLine &Line) { - AnnotatingParser Parser(Style, Line, Keywords, Scopes); + if (!Line.InMacroBody) + MacroBodyScopes.clear(); + + auto &ScopeStack = Line.InMacroBody ? MacroBodyScopes : Scopes; + AnnotatingParser Parser(Style, Line, Keywords, ScopeStack); Line.Type = Parser.parseLine(); - for (auto &Child : Line.Children) - annotate(*Child); + if (!Line.Children.empty()) { + ScopeStack.push_back(ST_ChildBlock); + for (auto &Child : Line.Children) + annotate(*Child); + // ScopeStack can become empty if Child has an unmatched `}`. + if (!ScopeStack.empty()) + ScopeStack.pop_back(); + } // With very deep nesting, ExpressionParser uses lots of stack and the // formatting algorithm is very slow. We're not going to do a good job here @@ -3672,7 +3682,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) { if (IsCpp) { FormatToken *OpeningParen = nullptr; auto *Tok = getFunctionName(Line, OpeningParen); - if (Tok && ((!Scopes.empty() && Scopes.back() == ST_Class) || + if (Tok && ((!ScopeStack.empty() && ScopeStack.back() == ST_Class) || Line.endsWith(TT_FunctionLBrace) || isCtorOrDtorName(Tok))) { Tok->setFinalizedType(TT_CtorDtorDeclName); assert(OpeningParen); diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h index f4f2bba0eb217..5a02030e5ba7f 100644 --- a/clang/lib/Format/TokenAnnotator.h +++ b/clang/lib/Format/TokenAnnotator.h @@ -36,11 +36,11 @@ enum LineType { }; enum ScopeType { + // Contained in child block. + ST_ChildBlock, // Contained in class declaration/definition. ST_Class, - // Contained within function definition. - ST_Function, - // Contained within other scope block (loop, if/else, etc). + // Contained within other scope block (function, loop, if/else, etc). ST_Other, }; @@ -269,7 +269,7 @@ class TokenAnnotator { const AdditionalKeywords &Keywords; - SmallVector Scopes; + SmallVector Scopes, MacroBodyScopes; }; } // end namespace format diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 497b911f4efbb..93a64276fa021 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -327,6 +327,21 @@ TEST_F(TokenAnnotatorTest, UnderstandsUsesOfStarAndAmp) { ASSERT_EQ(Tokens.size(), 26u) << Tokens; EXPECT_TOKEN(Tokens[3], tok::ampamp, TT_BinaryOperator); EXPECT_TOKEN(Tokens[16], tok::ampamp, TT_BinaryOperator); + + Tokens = annotate("#define FOO \\\n" + " void foo() { f(a * b); }"); + ASSERT_EQ(Tokens.size(), 17u) << Tokens; + EXPECT_TOKEN(Tokens[11], tok::star, TT_BinaryOperator); + + Tokens = annotate("#define FOO auto Foo = [] { f(a * b); };"); + ASSERT_EQ(Tokens.size(), 19u) << Tokens; + EXPECT_TOKEN(Tokens[12], tok::star, TT_BinaryOperator); + + Tokens = annotate("namespace {\n" + "#define FOO(x) void foo(a##x *b);\n" + "}"); + ASSERT_EQ(Tokens.size(), 20u) << Tokens; + EXPECT_TOKEN(Tokens[14], tok::star, TT_PointerOrReference); } TEST_F(TokenAnnotatorTest, UnderstandsUsesOfPlusAndMinus) {