[clang] [clang-format] Handle AttributeMacro before access modifiers (PR #95634)
Owen Pan via cfe-commits
cfe-commits at lists.llvm.org
Sat Jun 15 10:35:55 PDT 2024
https://github.com/owenca updated https://github.com/llvm/llvm-project/pull/95634
>From 1c4ab4a5fd869de44795abd48bbaa43176e7275e Mon Sep 17 00:00:00 2001
From: Owen Pan <owenpiano at gmail.com>
Date: Fri, 14 Jun 2024 23:36:58 -0700
Subject: [PATCH 1/2] [clang-format] Handle AttributeMacro before access
modifiers
Closes #95094.
---
clang/lib/Format/TokenAnnotator.cpp | 7 ++++-
clang/lib/Format/TokenAnnotator.h | 1 +
clang/lib/Format/UnwrappedLineFormatter.cpp | 35 ++++++++++-----------
clang/unittests/Format/FormatTest.cpp | 15 +++++++++
4 files changed, 39 insertions(+), 19 deletions(-)
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 1fe3b61a5a81f..ff00e772a75f4 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -1970,6 +1970,7 @@ class AnnotatingParser {
}
}
+ bool SeenAccessModifier = false;
bool KeywordVirtualFound = false;
bool ImportStatement = false;
@@ -1978,7 +1979,9 @@ class AnnotatingParser {
ImportStatement = true;
while (CurrentToken) {
- if (CurrentToken->is(tok::kw_virtual))
+ if (CurrentToken->isAccessSpecifier())
+ SeenAccessModifier = true;
+ else if (CurrentToken->is(tok::kw_virtual))
KeywordVirtualFound = true;
if (Style.isJavaScript()) {
// export {...} from '...';
@@ -1998,6 +2001,8 @@ class AnnotatingParser {
if (!consumeToken())
return LT_Invalid;
}
+ if (SeenAccessModifier)
+ return LT_AccessModifier;
if (KeywordVirtualFound)
return LT_VirtualFunctionDecl;
if (ImportStatement)
diff --git a/clang/lib/Format/TokenAnnotator.h b/clang/lib/Format/TokenAnnotator.h
index d19d3d061e40c..136880eca718b 100644
--- a/clang/lib/Format/TokenAnnotator.h
+++ b/clang/lib/Format/TokenAnnotator.h
@@ -22,6 +22,7 @@ namespace format {
enum LineType {
LT_Invalid,
+ LT_AccessModifier, // Contains public/protected/private followed by colon.
LT_ImportStatement,
LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
LT_ObjCMethodDecl,
diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp
index 4d53361aaf333..729f3d78f4a35 100644
--- a/clang/lib/Format/UnwrappedLineFormatter.cpp
+++ b/clang/lib/Format/UnwrappedLineFormatter.cpp
@@ -57,7 +57,7 @@ class LevelIndentTracker {
/// Update the indent state given that \p Line is going to be formatted
/// next.
void nextLine(const AnnotatedLine &Line) {
- Offset = getIndentOffset(*Line.First);
+ Offset = getIndentOffset(Line);
// Update the indent level cache size so that we can rely on it
// having the right size in adjustToUnmodifiedline.
if (Line.Level >= IndentForLevel.size())
@@ -111,42 +111,41 @@ class LevelIndentTracker {
///
/// For example, 'public:' labels in classes are offset by 1 or 2
/// characters to the left from their level.
- int getIndentOffset(const FormatToken &RootToken) {
+ int getIndentOffset(const AnnotatedLine &Line) {
if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() ||
Style.isCSharp()) {
return 0;
}
- auto IsAccessModifier = [this, &RootToken]() {
- if (RootToken.isAccessSpecifier(Style.isCpp())) {
+ auto IsAccessModifier = [&](const FormatToken &RootToken) {
+ if (Line.Type == LT_AccessModifier || RootToken.isObjCAccessSpecifier())
return true;
- } else if (RootToken.isObjCAccessSpecifier()) {
- return true;
- }
+
+ const auto *Next = RootToken.Next;
+
// Handle Qt signals.
- else if (RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) &&
- RootToken.Next && RootToken.Next->is(tok::colon)) {
- return true;
- } else if (RootToken.Next &&
- RootToken.Next->isOneOf(Keywords.kw_slots,
- Keywords.kw_qslots) &&
- RootToken.Next->Next && RootToken.Next->Next->is(tok::colon)) {
+ if (RootToken.isOneOf(Keywords.kw_signals, Keywords.kw_qsignals) &&
+ Next && Next->is(tok::colon)) {
return true;
}
- // Handle malformed access specifier e.g. 'private' without trailing ':'.
- else if (!RootToken.Next && RootToken.isAccessSpecifier(false)) {
+
+ if (Next && Next->isOneOf(Keywords.kw_slots, Keywords.kw_qslots) &&
+ Next->Next && Next->Next->is(tok::colon)) {
return true;
}
- return false;
+
+ // Handle malformed access specifier e.g. 'private' without trailing ':'.
+ return !Next && RootToken.isAccessSpecifier(false);
};
- if (IsAccessModifier()) {
+ if (IsAccessModifier(*Line.First)) {
// The AccessModifierOffset may be overridden by IndentAccessModifiers,
// in which case we take a negative value of the IndentWidth to simulate
// the upper indent level.
return Style.IndentAccessModifiers ? -Style.IndentWidth
: Style.AccessModifierOffset;
}
+
return 0;
}
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index fb57333858529..2ca85c7b70e65 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -12912,6 +12912,15 @@ TEST_F(FormatTest, FormatsAccessModifiers) {
" int j;\n"
"};",
Style);
+ Style.AttributeMacros.push_back("FOO");
+ Style.AttributeMacros.push_back("BAR");
+ verifyFormat("struct foo {\n"
+ "FOO private:\n"
+ " int i;\n"
+ "BAR private:\n"
+ " int j;\n"
+ "};",
+ Style);
FormatStyle NoEmptyLines = getLLVMStyle();
NoEmptyLines.MaxEmptyLinesToKeep = 0;
@@ -26130,6 +26139,12 @@ TEST_F(FormatTest, IndentAccessModifiers) {
" int i;\n"
"};",
Style);
+ Style.AttributeMacros.push_back("FOO");
+ verifyFormat("class C {\n"
+ " FOO public:\n"
+ " int i;\n"
+ "};",
+ Style);
}
TEST_F(FormatTest, LimitlessStringsAndComments) {
>From fc7e0472f7970f3d4396c66ed3cade5e4579cc83 Mon Sep 17 00:00:00 2001
From: Owen Pan <owenpiano at gmail.com>
Date: Sat, 15 Jun 2024 10:34:29 -0700
Subject: [PATCH 2/2] Add support for function-like `AttributeMacro`.
---
clang/lib/Format/UnwrappedLineParser.cpp | 2 ++
clang/unittests/Format/FormatTest.cpp | 2 +-
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 899e68eadf70e..1fad02de202a3 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -368,6 +368,8 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace,
do {
if (FormatTok->isAttribute()) {
nextToken();
+ if (FormatTok->is(tok::l_paren))
+ parseParens();
continue;
}
tok::TokenKind Kind = FormatTok->Tok.getKind();
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 2ca85c7b70e65..fc63afce70042 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -12917,7 +12917,7 @@ TEST_F(FormatTest, FormatsAccessModifiers) {
verifyFormat("struct foo {\n"
"FOO private:\n"
" int i;\n"
- "BAR private:\n"
+ "BAR(x) protected:\n"
" int j;\n"
"};",
Style);
More information about the cfe-commits
mailing list