Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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>`
Expand Down
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
--------
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -5458,6 +5464,7 @@ struct FormatStyle {
R.AllowAllParametersOfDeclarationOnNextLine &&
AllowBreakBeforeNoexceptSpecifier ==
R.AllowBreakBeforeNoexceptSpecifier &&
AllowBreakBeforeQtProperty == R.AllowBreakBeforeQtProperty &&
AllowShortBlocksOnASingleLine == R.AllowShortBlocksOnASingleLine &&
AllowShortCaseExpressionOnASingleLine ==
R.AllowShortCaseExpressionOnASingleLine &&
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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;
Expand Down
16 changes: 15 additions & 1 deletion clang/lib/Format/FormatToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,20 @@ const char *getTokenTypeName(TokenType Type) {
return nullptr;
}

static constexpr std::array<StringRef, 14> 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 = {
static constexpr std::array<StringRef, 14> CppNonKeywordTypes = {
"clock_t", "int16_t", "int32_t", "int64_t", "int8_t",
"intptr_t", "ptrdiff_t", "size_t", "time_t", "uint16_t",
"uint32_t", "uint64_t", "uint8_t", "uintptr_t",
Expand Down Expand Up @@ -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 !=
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Format/FormatToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ namespace format {
TYPE(PointerOrReference) \
TYPE(ProtoExtensionLSquare) \
TYPE(PureVirtualSpecifier) \
TYPE(QtProperty) \
TYPE(RangeBasedForLoopColon) \
TYPE(RecordLBrace) \
TYPE(RecordRBrace) \
Expand Down Expand Up @@ -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;

Expand Down
12 changes: 11 additions & 1 deletion clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))) {
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -2169,6 +2178,7 @@ class AnnotatingParser {
TemplateArgument,
// C11 _Generic selection.
C11GenericSelection,
QtProperty,
// Like in the outer parentheses in `ffnand ff1(.q());`.
VerilogInstancePortList,
} ContextType = Unknown;
Expand Down Expand Up @@ -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))
Expand Down
1 change: 1 addition & 0 deletions clang/unittests/Format/ConfigParseTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
30 changes: 30 additions & 0 deletions clang/unittests/Format/FormatTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions clang/unittests/Format/TokenAnnotatorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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