-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang-format] Handle variable declarations in BreakAfterAttributes #71935
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
Also cleaned up some old test cases. Fixes llvm#71563.
@llvm/pr-subscribers-clang-format @llvm/pr-subscribers-clang Author: Owen Pan (owenca) ChangesAlso fixed a bug in Fixed #71563. This is a rework of #71755. Full diff: https://github.com/llvm/llvm-project/pull/71935.diff 4 Files Affected:
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 21342e1b89ea866..d496fc85f7ae71a 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -2049,8 +2049,8 @@ the configuration (without a prefix: ``Auto``).
.. _BreakAfterAttributes:
**BreakAfterAttributes** (``AttributeBreakingStyle``) :versionbadge:`clang-format 16` :ref:`¶ <BreakAfterAttributes>`
- Break after a group of C++11 attributes before a function
- declaration/definition name.
+ Break after a group of C++11 attributes before a variable/function
+ (including constructor/destructor) declaration/definition name.
Possible values:
@@ -2059,6 +2059,10 @@ the configuration (without a prefix: ``Auto``).
.. code-block:: c++
+ [[maybe_unused]]
+ const int i;
+ [[gnu::const]] [[maybe_unused]]
+ int j;
[[nodiscard]]
inline int f();
[[gnu::const]] [[nodiscard]]
@@ -2069,6 +2073,9 @@ the configuration (without a prefix: ``Auto``).
.. code-block:: c++
+ [[maybe_unused]] const int i;
+ [[gnu::const]] [[maybe_unused]]
+ int j;
[[nodiscard]] inline int f();
[[gnu::const]] [[nodiscard]]
int g();
@@ -2078,6 +2085,8 @@ the configuration (without a prefix: ``Auto``).
.. code-block:: c++
+ [[maybe_unused]] const int i;
+ [[gnu::const]] [[maybe_unused]] int j;
[[nodiscard]] inline int f();
[[gnu::const]] [[nodiscard]] int g();
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 3e9d1915badd87f..9442344000e142b 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -1428,6 +1428,10 @@ struct FormatStyle {
enum AttributeBreakingStyle : int8_t {
/// Always break after attributes.
/// \code
+ /// [[maybe_unused]]
+ /// const int i;
+ /// [[gnu::const]] [[maybe_unused]]
+ /// int j;
/// [[nodiscard]]
/// inline int f();
/// [[gnu::const]] [[nodiscard]]
@@ -1436,6 +1440,9 @@ struct FormatStyle {
ABS_Always,
/// Leave the line breaking after attributes as is.
/// \code
+ /// [[maybe_unused]] const int i;
+ /// [[gnu::const]] [[maybe_unused]]
+ /// int j;
/// [[nodiscard]] inline int f();
/// [[gnu::const]] [[nodiscard]]
/// int g();
@@ -1443,14 +1450,16 @@ struct FormatStyle {
ABS_Leave,
/// Never break after attributes.
/// \code
+ /// [[maybe_unused]] const int i;
+ /// [[gnu::const]] [[maybe_unused]] int j;
/// [[nodiscard]] inline int f();
/// [[gnu::const]] [[nodiscard]] int g();
/// \endcode
ABS_Never,
};
- /// Break after a group of C++11 attributes before a function
- /// declaration/definition name.
+ /// Break after a group of C++11 attributes before a variable/function
+ /// (including constructor/destructor) declaration/definition name.
/// \version 16
AttributeBreakingStyle BreakAfterAttributes;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index d648e441f23fe9e..725f02a37581d24 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -1997,6 +1997,10 @@ class AnnotatingParser {
(!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) {
Contexts.back().FirstStartOfName = &Current;
Current.setType(TT_StartOfName);
+ if (auto *PrevNonComment = Current.getPreviousNonComment();
+ PrevNonComment && PrevNonComment->is(TT_StartOfName)) {
+ PrevNonComment->setType(TT_Unknown);
+ }
} else if (Current.is(tok::semi)) {
// Reset FirstStartOfName after finding a semicolon so that a for loop
// with multiple increment statements is not confused with a for loop
@@ -2184,6 +2188,11 @@ class AnnotatingParser {
if (Tok.isNot(tok::identifier) || !Tok.Previous)
return false;
+ if (const auto *NextNonComment = Tok.getNextNonComment();
+ !NextNonComment || NextNonComment->isPointerOrReference()) {
+ return false;
+ }
+
if (Tok.Previous->isOneOf(TT_LeadingJavaAnnotation, Keywords.kw_instanceof,
Keywords.kw_as)) {
return false;
@@ -3438,10 +3447,15 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
if (AlignArrayOfStructures)
calculateArrayInitializerColumnList(Line);
+ const bool IsCpp = Style.isCpp();
+ bool SeenName = false;
bool LineIsFunctionDeclaration = false;
FormatToken *ClosingParen = nullptr;
- for (FormatToken *Tok = Current, *AfterLastAttribute = nullptr; Tok;
- Tok = Tok->Next) {
+ FormatToken *AfterLastAttribute = nullptr;
+
+ for (auto *Tok = Current; Tok; Tok = Tok->Next) {
+ if (Tok->is(TT_StartOfName))
+ SeenName = true;
if (Tok->Previous->EndsCppAttributeGroup)
AfterLastAttribute = Tok;
if (const bool IsCtorOrDtor = Tok->is(TT_CtorDtorDeclName);
@@ -3451,16 +3465,19 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const {
LineIsFunctionDeclaration = true;
Tok->setFinalizedType(TT_FunctionDeclarationName);
}
- if (AfterLastAttribute &&
- mustBreakAfterAttributes(*AfterLastAttribute, Style)) {
- AfterLastAttribute->MustBreakBefore = true;
- Line.ReturnTypeWrapped = true;
- }
+ SeenName = true;
break;
}
}
- if (Style.isCpp()) {
+ if (IsCpp && SeenName && AfterLastAttribute &&
+ mustBreakAfterAttributes(*AfterLastAttribute, Style)) {
+ AfterLastAttribute->MustBreakBefore = true;
+ if (LineIsFunctionDeclaration)
+ Line.ReturnTypeWrapped = true;
+ }
+
+ if (IsCpp) {
if (!LineIsFunctionDeclaration) {
// Annotate */&/&& in `operator` function calls as binary operators.
for (const auto *Tok = Line.First; Tok; Tok = Tok->Next) {
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 80903e7630c8073..bb01f57dce31a7a 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -8479,18 +8479,25 @@ TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) {
" aaaaaaaaaaaaaaaaaaaaaaaaa));");
verifyFormat("bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
" __attribute__((unused));");
- verifyGoogleFormat(
+
+ Style = getGoogleStyle();
+ Style.AttributeMacros.push_back("GUARDED_BY");
+ verifyFormat(
"bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " GUARDED_BY(aaaaaaaaaaaa);");
- verifyGoogleFormat(
+ " GUARDED_BY(aaaaaaaaaaaa);",
+ Style);
+ verifyFormat(
"bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
- " GUARDED_BY(aaaaaaaaaaaa);");
- verifyGoogleFormat(
+ " GUARDED_BY(aaaaaaaaaaaa);",
+ Style);
+ verifyFormat(
"bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa GUARDED_BY(aaaaaaaaaaaa) =\n"
- " aaaaaaaa::aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
- verifyGoogleFormat(
+ " aaaaaaaa::aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
+ Style);
+ verifyFormat(
"bool aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa GUARDED_BY(aaaaaaaaaaaa) =\n"
- " aaaaaaaaaaaaaaaaaaaaaaaaa;");
+ " aaaaaaaaaaaaaaaaaaaaaaaaa;",
+ Style);
}
TEST_F(FormatTest, FunctionAnnotations) {
@@ -26192,9 +26199,10 @@ TEST_F(FormatTest, RemoveSemicolon) {
}
TEST_F(FormatTest, BreakAfterAttributes) {
- FormatStyle Style = getLLVMStyle();
-
- constexpr StringRef Code("[[nodiscard]] inline int f(int &i);\n"
+ constexpr StringRef Code("[[maybe_unused]] const int i;\n"
+ "[[foo([[]])]] [[maybe_unused]]\n"
+ "int j;\n"
+ "[[nodiscard]] inline int f(int &i);\n"
"[[foo([[]])]] [[nodiscard]]\n"
"int g(int &i);\n"
"[[nodiscard]]\n"
@@ -26207,11 +26215,14 @@ TEST_F(FormatTest, BreakAfterAttributes) {
" return 1;\n"
"}");
+ FormatStyle Style = getLLVMStyle();
EXPECT_EQ(Style.BreakAfterAttributes, FormatStyle::ABS_Leave);
verifyNoChange(Code, Style);
Style.BreakAfterAttributes = FormatStyle::ABS_Never;
- verifyFormat("[[nodiscard]] inline int f(int &i);\n"
+ verifyFormat("[[maybe_unused]] const int i;\n"
+ "[[foo([[]])]] [[maybe_unused]] int j;\n"
+ "[[nodiscard]] inline int f(int &i);\n"
"[[foo([[]])]] [[nodiscard]] int g(int &i);\n"
"[[nodiscard]] inline int f(int &i) {\n"
" i = 1;\n"
@@ -26224,7 +26235,11 @@ TEST_F(FormatTest, BreakAfterAttributes) {
Code, Style);
Style.BreakAfterAttributes = FormatStyle::ABS_Always;
- verifyFormat("[[nodiscard]]\n"
+ verifyFormat("[[maybe_unused]]\n"
+ "const int i;\n"
+ "[[foo([[]])]] [[maybe_unused]]\n"
+ "int j;\n"
+ "[[nodiscard]]\n"
"inline int f(int &i);\n"
"[[foo([[]])]] [[nodiscard]]\n"
"int g(int &i);\n"
|
…lvm#71935) Also fixed a bug in `isStartOfName()` and cleaned up some old test cases. Fixed llvm#71563. This is a rework of llvm#71755.
We started seeing some inconsistent behavior in Input:
Clang-format invocation:
Output:
|
The default value of |
Also fixed a bug in
isStartOfName()
and cleaned up some old test cases.Fixed #71563.
This is a rework of #71755.