-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[clang-format] Handle pointer/reference in macro definitions #107074
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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 llvm#99271.
@llvm/pr-subscribers-clang-format Author: Owen Pan (owenca) ChangesA 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. Full diff: https://github.com/llvm/llvm-project/pull/107074.diff 3 Files Affected:
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 64e936f627d438..8cd2edaf4fbcdc 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 f4f2bba0eb217f..5a02030e5ba7f9 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<ScopeType> Scopes;
+ SmallVector<ScopeType> Scopes, MacroBodyScopes;
};
} // end namespace format
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index 497b911f4efbba..93a64276fa021d 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) {
|
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.