-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[clang-format] Add AllowBreakBeforeQtProperty option #159909
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
Merged
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Test cases are adpated from llvm#131605.
Member
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-format Author: owenca (owenca) ChangesTest cases are adpated from #131605. Full diff: https://github.com/llvm/llvm-project/pull/159909.diff 10 Files Affected:
diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst
index 9413b9a348b76..b746df5dab264 100644
--- a/clang/docs/ClangFormatStyleOptions.rst
+++ b/clang/docs/ClangFormatStyleOptions.rst
@@ -1795,6 +1795,13 @@ the configuration (without a prefix: ``Auto``).
+.. _AllowBreakBeforeQtProperty:
+
+**AllowBreakBeforeQtProperty** (``Boolean``) :versionbadge:`clang-format 22` :ref:`¶ <AllowBreakBeforeQtProperty>`
+ Allow breaking before ``Q_Property`` keywords ``READ``, ``WRITE``, etc. as
+ if they were preceded by a comma (``,``). This allows them to be formatted
+ according to ``BinPackParameters``.
+
.. _AllowShortBlocksOnASingleLine:
**AllowShortBlocksOnASingleLine** (``ShortBlockStyle``) :versionbadge:`clang-format 3.5` :ref:`¶ <AllowShortBlocksOnASingleLine>`
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 46d56bb3f07f5..6daf2ab23bbf2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -530,6 +530,7 @@ clang-format
- Add ``NumericLiteralCase`` option for enforcing character case in numeric
literals.
- Add ``Leave`` suboption to ``IndentPPDirectives``.
+- Add ``AllowBreakBeforeQtProperty`` option.
libclang
--------
diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h
index 342fefcfc408c..3df5b92654094 100644
--- a/clang/include/clang/Format/Format.h
+++ b/clang/include/clang/Format/Format.h
@@ -732,6 +732,12 @@ struct FormatStyle {
/// \version 18
BreakBeforeNoexceptSpecifierStyle AllowBreakBeforeNoexceptSpecifier;
+ /// Allow breaking before ``Q_Property`` keywords ``READ``, ``WRITE``, etc. as
+ /// if they were preceded by a comma (``,``). This allows them to be formatted
+ /// according to ``BinPackParameters``.
+ /// \version 22
+ bool AllowBreakBeforeQtProperty;
+
/// Different styles for merging short blocks containing at most one
/// statement.
enum ShortBlockStyle : int8_t {
@@ -5458,6 +5464,7 @@ struct FormatStyle {
R.AllowAllParametersOfDeclarationOnNextLine &&
AllowBreakBeforeNoexceptSpecifier ==
R.AllowBreakBeforeNoexceptSpecifier &&
+ AllowBreakBeforeQtProperty == R.AllowBreakBeforeQtProperty &&
AllowShortBlocksOnASingleLine == R.AllowShortBlocksOnASingleLine &&
AllowShortCaseExpressionOnASingleLine ==
R.AllowShortCaseExpressionOnASingleLine &&
diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp
index 24a36d97a6fa9..b38f2810c0a74 100644
--- a/clang/lib/Format/Format.cpp
+++ b/clang/lib/Format/Format.cpp
@@ -1028,6 +1028,8 @@ template <> struct MappingTraits<FormatStyle> {
Style.AllowAllParametersOfDeclarationOnNextLine);
IO.mapOptional("AllowBreakBeforeNoexceptSpecifier",
Style.AllowBreakBeforeNoexceptSpecifier);
+ IO.mapOptional("AllowBreakBeforeQtProperty",
+ Style.AllowBreakBeforeQtProperty);
IO.mapOptional("AllowShortBlocksOnASingleLine",
Style.AllowShortBlocksOnASingleLine);
IO.mapOptional("AllowShortCaseExpressionOnASingleLine",
@@ -1567,6 +1569,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AllowAllArgumentsOnNextLine = true;
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never;
+ LLVMStyle.AllowBreakBeforeQtProperty = false;
LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
LLVMStyle.AllowShortCaseExpressionOnASingleLine = true;
LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;
diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp
index 9c98b7819e61a..8da50bc885c34 100644
--- a/clang/lib/Format/FormatToken.cpp
+++ b/clang/lib/Format/FormatToken.cpp
@@ -33,6 +33,18 @@ const char *getTokenTypeName(TokenType Type) {
return nullptr;
}
+static SmallVector<StringRef> QtPropertyKeywords = {
+ "BINDABLE", "CONSTANT", "DESIGNABLE", "FINAL", "MEMBER",
+ "NOTIFY", "READ", "REQUIRED", "RESET", "REVISION",
+ "SCRIPTABLE", "STORED", "USER", "WRITE",
+};
+
+bool FormatToken::isQtProperty() const {
+ assert(llvm::is_sorted(QtPropertyKeywords));
+ return std::binary_search(QtPropertyKeywords.begin(),
+ QtPropertyKeywords.end(), TokenText);
+}
+
// Sorted common C++ non-keyword types.
static SmallVector<StringRef> CppNonKeywordTypes = {
"clock_t", "int16_t", "int32_t", "int64_t", "int8_t",
@@ -330,6 +342,8 @@ bool startsNextParameter(const FormatToken &Current, const FormatStyle &Style) {
}
if (Style.Language == FormatStyle::LK_Proto && Current.is(TT_SelectorName))
return true;
+ if (Current.is(TT_QtProperty))
+ return true;
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
((Previous.isNot(TT_CtorInitializerComma) ||
Style.BreakConstructorInitializers !=
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 9252a795a0b5e..e04b0e7af10c0 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -136,6 +136,7 @@ namespace format {
TYPE(PointerOrReference) \
TYPE(ProtoExtensionLSquare) \
TYPE(PureVirtualSpecifier) \
+ TYPE(QtProperty) \
TYPE(RangeBasedForLoopColon) \
TYPE(RecordLBrace) \
TYPE(RecordRBrace) \
@@ -703,6 +704,7 @@ struct FormatToken {
isAttribute();
}
+ [[nodiscard]] bool isQtProperty() const;
[[nodiscard]] bool isTypeName(const LangOptions &LangOpts) const;
[[nodiscard]] bool isTypeOrIdentifier(const LangOptions &LangOpts) const;
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index d97f56751ea69..4bfb803ebedf7 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -384,6 +384,10 @@ class AnnotatingParser {
OpeningParen.Previous->is(tok::kw__Generic)) {
Contexts.back().ContextType = Context::C11GenericSelection;
Contexts.back().IsExpression = true;
+ } else if (OpeningParen.Previous &&
+ OpeningParen.Previous->TokenText == "Q_PROPERTY") {
+ Contexts.back().ContextType = Context::QtProperty;
+ Contexts.back().IsExpression = false;
} else if (Line.InPPDirective &&
(!OpeningParen.Previous ||
OpeningParen.Previous->isNot(tok::identifier))) {
@@ -1803,6 +1807,11 @@ class AnnotatingParser {
return false;
}
}
+ if (Style.AllowBreakBeforeQtProperty &&
+ Contexts.back().ContextType == Context::QtProperty &&
+ Tok->isQtProperty()) {
+ Tok->setFinalizedType(TT_QtProperty);
+ }
break;
case tok::arrow:
if (Tok->isNot(TT_LambdaArrow) && Prev && Prev->is(tok::kw_noexcept))
@@ -2169,6 +2178,7 @@ class AnnotatingParser {
TemplateArgument,
// C11 _Generic selection.
C11GenericSelection,
+ QtProperty,
// Like in the outer parentheses in `ffnand ff1(.q());`.
VerilogInstancePortList,
} ContextType = Unknown;
@@ -6254,7 +6264,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
Right.Next->isOneOf(TT_FunctionDeclarationName, tok::kw_const)));
}
if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName,
- TT_ClassHeadName, tok::kw_operator)) {
+ TT_ClassHeadName, TT_QtProperty, tok::kw_operator)) {
return true;
}
if (Left.is(TT_PointerOrReference))
diff --git a/clang/unittests/Format/ConfigParseTest.cpp b/clang/unittests/Format/ConfigParseTest.cpp
index 7c993c0f8fd33..bb4d38bb741ec 100644
--- a/clang/unittests/Format/ConfigParseTest.cpp
+++ b/clang/unittests/Format/ConfigParseTest.cpp
@@ -161,6 +161,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
Style.Language = FormatStyle::LK_Cpp;
CHECK_PARSE_BOOL(AllowAllArgumentsOnNextLine);
CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
+ CHECK_PARSE_BOOL(AllowBreakBeforeQtProperty);
CHECK_PARSE_BOOL(AllowShortCaseExpressionOnASingleLine);
CHECK_PARSE_BOOL(AllowShortCaseLabelsOnASingleLine);
CHECK_PARSE_BOOL(AllowShortCompoundRequirementOnASingleLine);
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index d9db06667d802..7d550143be5df 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -28772,6 +28772,36 @@ TEST_F(FormatTest, BreakBeforeClassName) {
" ArenaSafeUniquePtr {};");
}
+TEST_F(FormatTest, KeywordedFunctionLikeMacros) {
+ constexpr StringRef Code("Q_PROPERTY(int name\n"
+ " READ name\n"
+ " WRITE setName\n"
+ " NOTIFY nameChanged)");
+ constexpr StringRef Code2("class A {\n"
+ " Q_PROPERTY(int name\n"
+ " READ name\n"
+ " WRITE setName\n"
+ " NOTIFY nameChanged)\n"
+ "};");
+
+ auto Style = getLLVMStyle();
+ Style.AllowBreakBeforeQtProperty = true;
+
+ Style.BinPackParameters = FormatStyle::BPPS_AlwaysOnePerLine;
+ verifyFormat(Code, Style);
+ verifyFormat(Code2, Style);
+
+ Style.BinPackParameters = FormatStyle::BPPS_OnePerLine;
+ Style.ColumnLimit = 40;
+ verifyFormat(Code, Style);
+ verifyFormat(Code2, Style);
+ verifyFormat("/* sdf */ Q_PROPERTY(int name\n"
+ " READ name\n"
+ " WRITE setName\n"
+ " NOTIFY nameChanged)",
+ Style);
+}
+
} // namespace
} // namespace test
} // namespace format
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index f6435f13f0791..4c43a963632a6 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -4159,6 +4159,29 @@ TEST_F(TokenAnnotatorTest, LineCommentTrailingBackslash) {
EXPECT_TOKEN(Tokens[1], tok::comment, TT_LineComment);
}
+TEST_F(TokenAnnotatorTest, KeywordedFunctionLikeMacro) {
+ auto Style = getLLVMStyle();
+ Style.AllowBreakBeforeQtProperty = true;
+
+ auto Tokens = annotate(
+ "Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)",
+ Style);
+ ASSERT_EQ(Tokens.size(), 12u) << Tokens;
+ EXPECT_TOKEN(Tokens[4], tok::identifier, TT_QtProperty);
+ EXPECT_TOKEN(Tokens[6], tok::identifier, TT_QtProperty);
+ EXPECT_TOKEN(Tokens[8], tok::identifier, TT_QtProperty);
+
+ Tokens = annotate(
+ "struct S {\n"
+ " Q_OBJECT Q_PROPERTY(int value READ value WRITE setValue NOTIFY foo)\n"
+ "};",
+ Style);
+ ASSERT_EQ(Tokens.size(), 18u) << Tokens;
+ EXPECT_TOKEN(Tokens[8], tok::identifier, TT_QtProperty);
+ EXPECT_TOKEN(Tokens[10], tok::identifier, TT_QtProperty);
+ EXPECT_TOKEN(Tokens[12], tok::identifier, TT_QtProperty);
+}
+
} // namespace
} // namespace format
} // namespace clang
|
HazardyKnusperkeks
approved these changes
Sep 22, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The test cases are adapted from #131605.