mirror of
https://github.com/intel/llvm.git
synced 2026-01-22 23:49:22 +08:00
[clang-format] Add AllowBreakBeforeQtProperty option (#159909)
The test cases are adapted from #131605.
This commit is contained in:
@@ -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>`
|
||||
|
||||
@@ -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
|
||||
--------
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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",
|
||||
@@ -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 !=
|
||||
|
||||
@@ -136,6 +136,7 @@ namespace format {
|
||||
TYPE(PointerOrReference) \
|
||||
TYPE(ProtoExtensionLSquare) \
|
||||
TYPE(PureVirtualSpecifier) \
|
||||
TYPE(QtProperty) \
|
||||
TYPE(RangeBasedForLoopColon) \
|
||||
TYPE(RecordLBrace) \
|
||||
TYPE(RecordRBrace) \
|
||||
@@ -703,6 +704,7 @@ public:
|
||||
isAttribute();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isQtProperty() const;
|
||||
[[nodiscard]] bool isTypeName(const LangOptions &LangOpts) const;
|
||||
[[nodiscard]] bool isTypeOrIdentifier(const LangOptions &LangOpts) const;
|
||||
|
||||
|
||||
@@ -384,6 +384,10 @@ private:
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user