Skip to content

Commit 812c96e

Browse files
authored
[clang-format] Handle pointer/reference in macro definitions (#107074)
A macro definition needs its own scope stack in the annotator, so we add the MacroBodyScopes stack and use ScopeStack to refer to it when in the macro definition body. Also, we need to have a scope type for a child block because its parent line is parsed (and thus the scope type for the braces is popped off the scope stack) before the lines in the child block are. Fixes #99271.
1 parent 8d08166 commit 812c96e

File tree

3 files changed

+36
-11
lines changed

3 files changed

+36
-11
lines changed

clang/lib/Format/TokenAnnotator.cpp

+17-7
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,8 @@ class AnnotatingParser {
137137
private:
138138
ScopeType getScopeType(const FormatToken &Token) const {
139139
switch (Token.getType()) {
140-
case TT_FunctionLBrace:
141140
case TT_LambdaLBrace:
142-
return ST_Function;
141+
return ST_ChildBlock;
143142
case TT_ClassLBrace:
144143
case TT_StructLBrace:
145144
case TT_UnionLBrace:
@@ -400,7 +399,8 @@ class AnnotatingParser {
400399
OpeningParen.Previous->MatchingParen->isOneOf(
401400
TT_ObjCBlockLParen, TT_FunctionTypeLParen)) {
402401
Contexts.back().IsExpression = false;
403-
} else if (!Line.MustBeDeclaration && !Line.InPPDirective) {
402+
} else if (!Line.MustBeDeclaration &&
403+
(!Line.InPPDirective || (Line.InMacroBody && !Scopes.empty()))) {
404404
bool IsForOrCatch =
405405
OpeningParen.Previous &&
406406
OpeningParen.Previous->isOneOf(tok::kw_for, tok::kw_catch);
@@ -3649,11 +3649,21 @@ static bool isCtorOrDtorName(const FormatToken *Tok) {
36493649
}
36503650

36513651
void TokenAnnotator::annotate(AnnotatedLine &Line) {
3652-
AnnotatingParser Parser(Style, Line, Keywords, Scopes);
3652+
if (!Line.InMacroBody)
3653+
MacroBodyScopes.clear();
3654+
3655+
auto &ScopeStack = Line.InMacroBody ? MacroBodyScopes : Scopes;
3656+
AnnotatingParser Parser(Style, Line, Keywords, ScopeStack);
36533657
Line.Type = Parser.parseLine();
36543658

3655-
for (auto &Child : Line.Children)
3656-
annotate(*Child);
3659+
if (!Line.Children.empty()) {
3660+
ScopeStack.push_back(ST_ChildBlock);
3661+
for (auto &Child : Line.Children)
3662+
annotate(*Child);
3663+
// ScopeStack can become empty if Child has an unmatched `}`.
3664+
if (!ScopeStack.empty())
3665+
ScopeStack.pop_back();
3666+
}
36573667

36583668
// With very deep nesting, ExpressionParser uses lots of stack and the
36593669
// formatting algorithm is very slow. We're not going to do a good job here
@@ -3671,7 +3681,7 @@ void TokenAnnotator::annotate(AnnotatedLine &Line) {
36713681
if (IsCpp) {
36723682
FormatToken *OpeningParen = nullptr;
36733683
auto *Tok = getFunctionName(Line, OpeningParen);
3674-
if (Tok && ((!Scopes.empty() && Scopes.back() == ST_Class) ||
3684+
if (Tok && ((!ScopeStack.empty() && ScopeStack.back() == ST_Class) ||
36753685
Line.endsWith(TT_FunctionLBrace) || isCtorOrDtorName(Tok))) {
36763686
Tok->setFinalizedType(TT_CtorDtorDeclName);
36773687
assert(OpeningParen);

clang/lib/Format/TokenAnnotator.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ enum LineType {
3636
};
3737

3838
enum ScopeType {
39+
// Contained in child block.
40+
ST_ChildBlock,
3941
// Contained in class declaration/definition.
4042
ST_Class,
41-
// Contained within function definition.
42-
ST_Function,
43-
// Contained within other scope block (loop, if/else, etc).
43+
// Contained within other scope block (function, loop, if/else, etc).
4444
ST_Other,
4545
};
4646

@@ -269,7 +269,7 @@ class TokenAnnotator {
269269

270270
const AdditionalKeywords &Keywords;
271271

272-
SmallVector<ScopeType> Scopes;
272+
SmallVector<ScopeType> Scopes, MacroBodyScopes;
273273
};
274274

275275
} // end namespace format

clang/unittests/Format/TokenAnnotatorTest.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,21 @@ TEST_F(TokenAnnotatorTest, UnderstandsUsesOfStarAndAmp) {
327327
ASSERT_EQ(Tokens.size(), 26u) << Tokens;
328328
EXPECT_TOKEN(Tokens[3], tok::ampamp, TT_BinaryOperator);
329329
EXPECT_TOKEN(Tokens[16], tok::ampamp, TT_BinaryOperator);
330+
331+
Tokens = annotate("#define FOO \\\n"
332+
" void foo() { f(a * b); }");
333+
ASSERT_EQ(Tokens.size(), 17u) << Tokens;
334+
EXPECT_TOKEN(Tokens[11], tok::star, TT_BinaryOperator);
335+
336+
Tokens = annotate("#define FOO auto Foo = [] { f(a * b); };");
337+
ASSERT_EQ(Tokens.size(), 19u) << Tokens;
338+
EXPECT_TOKEN(Tokens[12], tok::star, TT_BinaryOperator);
339+
340+
Tokens = annotate("namespace {\n"
341+
"#define FOO(x) void foo(a##x *b);\n"
342+
"}");
343+
ASSERT_EQ(Tokens.size(), 20u) << Tokens;
344+
EXPECT_TOKEN(Tokens[14], tok::star, TT_PointerOrReference);
330345
}
331346

332347
TEST_F(TokenAnnotatorTest, UnderstandsUsesOfPlusAndMinus) {

0 commit comments

Comments
 (0)