Skip to content

Commit 583256d

Browse files
authored
[clang-format] Add AllowBreakBeforeQtProperty option (#159909)
The test cases are adapted from #131605.
1 parent 322b990 commit 583256d

File tree

10 files changed

+100
-2
lines changed

10 files changed

+100
-2
lines changed

clang/docs/ClangFormatStyleOptions.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1795,6 +1795,13 @@ the configuration (without a prefix: ``Auto``).
17951795

17961796

17971797

1798+
.. _AllowBreakBeforeQtProperty:
1799+
1800+
**AllowBreakBeforeQtProperty** (``Boolean``) :versionbadge:`clang-format 22` :ref:`<AllowBreakBeforeQtProperty>`
1801+
Allow breaking before ``Q_Property`` keywords ``READ``, ``WRITE``, etc. as
1802+
if they were preceded by a comma (``,``). This allows them to be formatted
1803+
according to ``BinPackParameters``.
1804+
17981805
.. _AllowShortBlocksOnASingleLine:
17991806

18001807
**AllowShortBlocksOnASingleLine** (``ShortBlockStyle``) :versionbadge:`clang-format 3.5` :ref:`<AllowShortBlocksOnASingleLine>`

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,7 @@ clang-format
530530
- Add ``NumericLiteralCase`` option for enforcing character case in numeric
531531
literals.
532532
- Add ``Leave`` suboption to ``IndentPPDirectives``.
533+
- Add ``AllowBreakBeforeQtProperty`` option.
533534

534535
libclang
535536
--------

clang/include/clang/Format/Format.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,12 @@ struct FormatStyle {
732732
/// \version 18
733733
BreakBeforeNoexceptSpecifierStyle AllowBreakBeforeNoexceptSpecifier;
734734

735+
/// Allow breaking before ``Q_Property`` keywords ``READ``, ``WRITE``, etc. as
736+
/// if they were preceded by a comma (``,``). This allows them to be formatted
737+
/// according to ``BinPackParameters``.
738+
/// \version 22
739+
bool AllowBreakBeforeQtProperty;
740+
735741
/// Different styles for merging short blocks containing at most one
736742
/// statement.
737743
enum ShortBlockStyle : int8_t {
@@ -5458,6 +5464,7 @@ struct FormatStyle {
54585464
R.AllowAllParametersOfDeclarationOnNextLine &&
54595465
AllowBreakBeforeNoexceptSpecifier ==
54605466
R.AllowBreakBeforeNoexceptSpecifier &&
5467+
AllowBreakBeforeQtProperty == R.AllowBreakBeforeQtProperty &&
54615468
AllowShortBlocksOnASingleLine == R.AllowShortBlocksOnASingleLine &&
54625469
AllowShortCaseExpressionOnASingleLine ==
54635470
R.AllowShortCaseExpressionOnASingleLine &&

clang/lib/Format/Format.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,6 +1028,8 @@ template <> struct MappingTraits<FormatStyle> {
10281028
Style.AllowAllParametersOfDeclarationOnNextLine);
10291029
IO.mapOptional("AllowBreakBeforeNoexceptSpecifier",
10301030
Style.AllowBreakBeforeNoexceptSpecifier);
1031+
IO.mapOptional("AllowBreakBeforeQtProperty",
1032+
Style.AllowBreakBeforeQtProperty);
10311033
IO.mapOptional("AllowShortBlocksOnASingleLine",
10321034
Style.AllowShortBlocksOnASingleLine);
10331035
IO.mapOptional("AllowShortCaseExpressionOnASingleLine",
@@ -1567,6 +1569,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
15671569
LLVMStyle.AllowAllArgumentsOnNextLine = true;
15681570
LLVMStyle.AllowAllParametersOfDeclarationOnNextLine = true;
15691571
LLVMStyle.AllowBreakBeforeNoexceptSpecifier = FormatStyle::BBNSS_Never;
1572+
LLVMStyle.AllowBreakBeforeQtProperty = false;
15701573
LLVMStyle.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
15711574
LLVMStyle.AllowShortCaseExpressionOnASingleLine = true;
15721575
LLVMStyle.AllowShortCaseLabelsOnASingleLine = false;

clang/lib/Format/FormatToken.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,20 @@ const char *getTokenTypeName(TokenType Type) {
3333
return nullptr;
3434
}
3535

36+
static constexpr std::array<StringRef, 14> QtPropertyKeywords = {
37+
"BINDABLE", "CONSTANT", "DESIGNABLE", "FINAL", "MEMBER",
38+
"NOTIFY", "READ", "REQUIRED", "RESET", "REVISION",
39+
"SCRIPTABLE", "STORED", "USER", "WRITE",
40+
};
41+
42+
bool FormatToken::isQtProperty() const {
43+
assert(llvm::is_sorted(QtPropertyKeywords));
44+
return std::binary_search(QtPropertyKeywords.begin(),
45+
QtPropertyKeywords.end(), TokenText);
46+
}
47+
3648
// Sorted common C++ non-keyword types.
37-
static SmallVector<StringRef> CppNonKeywordTypes = {
49+
static constexpr std::array<StringRef, 14> CppNonKeywordTypes = {
3850
"clock_t", "int16_t", "int32_t", "int64_t", "int8_t",
3951
"intptr_t", "ptrdiff_t", "size_t", "time_t", "uint16_t",
4052
"uint32_t", "uint64_t", "uint8_t", "uintptr_t",
@@ -330,6 +342,8 @@ bool startsNextParameter(const FormatToken &Current, const FormatStyle &Style) {
330342
}
331343
if (Style.Language == FormatStyle::LK_Proto && Current.is(TT_SelectorName))
332344
return true;
345+
if (Current.is(TT_QtProperty))
346+
return true;
333347
return Previous.is(tok::comma) && !Current.isTrailingComment() &&
334348
((Previous.isNot(TT_CtorInitializerComma) ||
335349
Style.BreakConstructorInitializers !=

clang/lib/Format/FormatToken.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ namespace format {
136136
TYPE(PointerOrReference) \
137137
TYPE(ProtoExtensionLSquare) \
138138
TYPE(PureVirtualSpecifier) \
139+
TYPE(QtProperty) \
139140
TYPE(RangeBasedForLoopColon) \
140141
TYPE(RecordLBrace) \
141142
TYPE(RecordRBrace) \
@@ -703,6 +704,7 @@ struct FormatToken {
703704
isAttribute();
704705
}
705706

707+
[[nodiscard]] bool isQtProperty() const;
706708
[[nodiscard]] bool isTypeName(const LangOptions &LangOpts) const;
707709
[[nodiscard]] bool isTypeOrIdentifier(const LangOptions &LangOpts) const;
708710

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,10 @@ class AnnotatingParser {
384384
OpeningParen.Previous->is(tok::kw__Generic)) {
385385
Contexts.back().ContextType = Context::C11GenericSelection;
386386
Contexts.back().IsExpression = true;
387+
} else if (OpeningParen.Previous &&
388+
OpeningParen.Previous->TokenText == "Q_PROPERTY") {
389+
Contexts.back().ContextType = Context::QtProperty;
390+
Contexts.back().IsExpression = false;
387391
} else if (Line.InPPDirective &&
388392
(!OpeningParen.Previous ||
389393
OpeningParen.Previous->isNot(tok::identifier))) {
@@ -1803,6 +1807,11 @@ class AnnotatingParser {
18031807
return false;
18041808
}
18051809
}
1810+
if (Style.AllowBreakBeforeQtProperty &&
1811+
Contexts.back().ContextType == Context::QtProperty &&
1812+
Tok->isQtProperty()) {
1813+
Tok->setFinalizedType(TT_QtProperty);
1814+
}
18061815
break;
18071816
case tok::arrow:
18081817
if (Tok->isNot(TT_LambdaArrow) && Prev && Prev->is(tok::kw_noexcept))
@@ -2169,6 +2178,7 @@ class AnnotatingParser {
21692178
TemplateArgument,
21702179
// C11 _Generic selection.
21712180
C11GenericSelection,
2181+
QtProperty,
21722182
// Like in the outer parentheses in `ffnand ff1(.q());`.
21732183
VerilogInstancePortList,
21742184
} ContextType = Unknown;
@@ -6254,7 +6264,7 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line,
62546264
Right.Next->isOneOf(TT_FunctionDeclarationName, tok::kw_const)));
62556265
}
62566266
if (Right.isOneOf(TT_StartOfName, TT_FunctionDeclarationName,
6257-
TT_ClassHeadName, tok::kw_operator)) {
6267+
TT_ClassHeadName, TT_QtProperty, tok::kw_operator)) {
62586268
return true;
62596269
}
62606270
if (Left.is(TT_PointerOrReference))

clang/unittests/Format/ConfigParseTest.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ TEST(ConfigParseTest, ParsesConfigurationBools) {
161161
Style.Language = FormatStyle::LK_Cpp;
162162
CHECK_PARSE_BOOL(AllowAllArgumentsOnNextLine);
163163
CHECK_PARSE_BOOL(AllowAllParametersOfDeclarationOnNextLine);
164+
CHECK_PARSE_BOOL(AllowBreakBeforeQtProperty);
164165
CHECK_PARSE_BOOL(AllowShortCaseExpressionOnASingleLine);
165166
CHECK_PARSE_BOOL(AllowShortCaseLabelsOnASingleLine);
166167
CHECK_PARSE_BOOL(AllowShortCompoundRequirementOnASingleLine);

clang/unittests/Format/FormatTest.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28772,6 +28772,36 @@ TEST_F(FormatTest, BreakBeforeClassName) {
2877228772
" ArenaSafeUniquePtr {};");
2877328773
}
2877428774

28775+
TEST_F(FormatTest, KeywordedFunctionLikeMacros) {
28776+
constexpr StringRef Code("Q_PROPERTY(int name\n"
28777+
" READ name\n"
28778+
" WRITE setName\n"
28779+
" NOTIFY nameChanged)");
28780+
constexpr StringRef Code2("class A {\n"
28781+
" Q_PROPERTY(int name\n"
28782+
" READ name\n"
28783+
" WRITE setName\n"
28784+
" NOTIFY nameChanged)\n"
28785+
"};");
28786+
28787+
auto Style = getLLVMStyle();
28788+
Style.AllowBreakBeforeQtProperty = true;
28789+
28790+
Style.BinPackParameters = FormatStyle::BPPS_AlwaysOnePerLine;
28791+
verifyFormat(Code, Style);
28792+
verifyFormat(Code2, Style);
28793+
28794+
Style.BinPackParameters = FormatStyle::BPPS_OnePerLine;
28795+
Style.ColumnLimit = 40;
28796+
verifyFormat(Code, Style);
28797+
verifyFormat(Code2, Style);
28798+
verifyFormat("/* sdf */ Q_PROPERTY(int name\n"
28799+
" READ name\n"
28800+
" WRITE setName\n"
28801+
" NOTIFY nameChanged)",
28802+
Style);
28803+
}
28804+
2877528805
} // namespace
2877628806
} // namespace test
2877728807
} // namespace format

clang/unittests/Format/TokenAnnotatorTest.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4159,6 +4159,29 @@ TEST_F(TokenAnnotatorTest, LineCommentTrailingBackslash) {
41594159
EXPECT_TOKEN(Tokens[1], tok::comment, TT_LineComment);
41604160
}
41614161

4162+
TEST_F(TokenAnnotatorTest, KeywordedFunctionLikeMacro) {
4163+
auto Style = getLLVMStyle();
4164+
Style.AllowBreakBeforeQtProperty = true;
4165+
4166+
auto Tokens = annotate(
4167+
"Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)",
4168+
Style);
4169+
ASSERT_EQ(Tokens.size(), 12u) << Tokens;
4170+
EXPECT_TOKEN(Tokens[4], tok::identifier, TT_QtProperty);
4171+
EXPECT_TOKEN(Tokens[6], tok::identifier, TT_QtProperty);
4172+
EXPECT_TOKEN(Tokens[8], tok::identifier, TT_QtProperty);
4173+
4174+
Tokens = annotate(
4175+
"struct S {\n"
4176+
" Q_OBJECT Q_PROPERTY(int value READ value WRITE setValue NOTIFY foo)\n"
4177+
"};",
4178+
Style);
4179+
ASSERT_EQ(Tokens.size(), 18u) << Tokens;
4180+
EXPECT_TOKEN(Tokens[8], tok::identifier, TT_QtProperty);
4181+
EXPECT_TOKEN(Tokens[10], tok::identifier, TT_QtProperty);
4182+
EXPECT_TOKEN(Tokens[12], tok::identifier, TT_QtProperty);
4183+
}
4184+
41624185
} // namespace
41634186
} // namespace format
41644187
} // namespace clang

0 commit comments

Comments
 (0)