forked from OSchip/llvm-project
[clang-format] Improve clang-formats handling of concepts
This is a starting point to improve the handling of concepts in clang-format. There is currently no real formatting of concepts and this can lead to some odd formatting, e.g. Reviewed By: mitchell-stellar, miscco, curdeius Differential Revision: https://reviews.llvm.org/D79773
This commit is contained in:
parent
c36801ecd5
commit
840e651dc6
|
@ -1382,6 +1382,18 @@ the configuration (without a prefix: ``Auto``).
|
|||
|
||||
|
||||
|
||||
**BreakBeforeConceptDeclarations** (``bool``)
|
||||
If ``true``, concept will be placed on a new line.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
template<typename T>
|
||||
concept ...
|
||||
|
||||
false:
|
||||
template<typename T> concept ...
|
||||
|
||||
**BreakBeforeTernaryOperators** (``bool``)
|
||||
If ``true``, ternary operators will be placed after line breaks.
|
||||
|
||||
|
@ -1901,6 +1913,25 @@ the configuration (without a prefix: ``Auto``).
|
|||
|
||||
|
||||
|
||||
**IndentRequires** (``bool``)
|
||||
Indent the requires clause in a template
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
true:
|
||||
template <typename It>
|
||||
requires Iterator<It>
|
||||
void sort(It begin, It end) {
|
||||
//....
|
||||
}
|
||||
|
||||
false:
|
||||
template <typename It>
|
||||
requires Iterator<It>
|
||||
void sort(It begin, It end) {
|
||||
//....
|
||||
}
|
||||
|
||||
**IndentWidth** (``unsigned``)
|
||||
The number of columns to use for indentation.
|
||||
|
||||
|
|
|
@ -271,6 +271,14 @@ clang-format
|
|||
};
|
||||
|
||||
|
||||
- Experimental Support in clang-format for concepts has been improved, to
|
||||
aid this the follow options have been added
|
||||
|
||||
- Option ``IndentRequires`` has been added to indent the ``requires`` keyword
|
||||
in templates.
|
||||
- Option ``BreakBeforeConceptDeclarations`` has been added to aid the formatting of concepts.
|
||||
|
||||
|
||||
libclang
|
||||
--------
|
||||
|
||||
|
|
|
@ -1160,6 +1160,17 @@ struct FormatStyle {
|
|||
/// \endcode
|
||||
BraceWrappingFlags BraceWrapping;
|
||||
|
||||
/// If ``true``, concept will be placed on a new line.
|
||||
/// \code
|
||||
/// true:
|
||||
/// template<typename T>
|
||||
/// concept ...
|
||||
///
|
||||
/// false:
|
||||
/// template<typename T> concept ...
|
||||
/// \endcode
|
||||
bool BreakBeforeConceptDeclarations;
|
||||
|
||||
/// If ``true``, ternary operators will be placed after line breaks.
|
||||
/// \code
|
||||
/// true:
|
||||
|
@ -1590,6 +1601,24 @@ struct FormatStyle {
|
|||
/// IndentExternBlockStyle is the type of indenting of extern blocks.
|
||||
IndentExternBlockStyle IndentExternBlock;
|
||||
|
||||
/// Indent the requires clause in a template
|
||||
/// \code
|
||||
/// true:
|
||||
/// template <typename It>
|
||||
/// requires Iterator<It>
|
||||
/// void sort(It begin, It end) {
|
||||
/// //....
|
||||
/// }
|
||||
///
|
||||
/// false:
|
||||
/// template <typename It>
|
||||
/// requires Iterator<It>
|
||||
/// void sort(It begin, It end) {
|
||||
/// //....
|
||||
/// }
|
||||
/// \endcode
|
||||
bool IndentRequires;
|
||||
|
||||
/// The number of columns to use for indentation.
|
||||
/// \code
|
||||
/// IndentWidth: 3
|
||||
|
@ -2435,6 +2464,7 @@ struct FormatStyle {
|
|||
BinPackParameters == R.BinPackParameters &&
|
||||
BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators &&
|
||||
BreakBeforeBraces == R.BreakBeforeBraces &&
|
||||
BreakBeforeConceptDeclarations == R.BreakBeforeConceptDeclarations &&
|
||||
BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators &&
|
||||
BreakConstructorInitializers == R.BreakConstructorInitializers &&
|
||||
CompactNamespaces == R.CompactNamespaces &&
|
||||
|
@ -2466,7 +2496,8 @@ struct FormatStyle {
|
|||
IndentGotoLabels == R.IndentGotoLabels &&
|
||||
IndentPPDirectives == R.IndentPPDirectives &&
|
||||
IndentExternBlock == R.IndentExternBlock &&
|
||||
IndentWidth == R.IndentWidth && Language == R.Language &&
|
||||
IndentRequires == R.IndentRequires && IndentWidth == R.IndentWidth &&
|
||||
Language == R.Language &&
|
||||
IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
|
||||
JavaImportGroups == R.JavaImportGroups &&
|
||||
JavaScriptQuotes == R.JavaScriptQuotes &&
|
||||
|
|
|
@ -501,6 +501,8 @@ template <> struct MappingTraits<FormatStyle> {
|
|||
IO.mapOptional("BraceWrapping", Style.BraceWrapping);
|
||||
IO.mapOptional("BreakBeforeBinaryOperators",
|
||||
Style.BreakBeforeBinaryOperators);
|
||||
IO.mapOptional("BreakBeforeConceptDeclarations",
|
||||
Style.BreakBeforeConceptDeclarations);
|
||||
IO.mapOptional("BreakBeforeBraces", Style.BreakBeforeBraces);
|
||||
|
||||
bool BreakBeforeInheritanceComma = false;
|
||||
|
@ -557,6 +559,7 @@ template <> struct MappingTraits<FormatStyle> {
|
|||
IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels);
|
||||
IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives);
|
||||
IO.mapOptional("IndentExternBlock", Style.IndentExternBlock);
|
||||
IO.mapOptional("IndentRequires", Style.IndentRequires);
|
||||
IO.mapOptional("IndentWidth", Style.IndentWidth);
|
||||
IO.mapOptional("IndentWrappedFunctionNames",
|
||||
Style.IndentWrappedFunctionNames);
|
||||
|
@ -872,6 +875,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
|
|||
LLVMStyle.BinPackArguments = true;
|
||||
LLVMStyle.BinPackParameters = true;
|
||||
LLVMStyle.BreakBeforeBinaryOperators = FormatStyle::BOS_None;
|
||||
LLVMStyle.BreakBeforeConceptDeclarations = true;
|
||||
LLVMStyle.BreakBeforeTernaryOperators = true;
|
||||
LLVMStyle.BreakBeforeBraces = FormatStyle::BS_Attach;
|
||||
LLVMStyle.BraceWrapping = {/*AfterCaseLabel=*/false,
|
||||
|
@ -921,6 +925,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
|
|||
LLVMStyle.IndentCaseBlocks = false;
|
||||
LLVMStyle.IndentGotoLabels = true;
|
||||
LLVMStyle.IndentPPDirectives = FormatStyle::PPDIS_None;
|
||||
LLVMStyle.IndentRequires = false;
|
||||
LLVMStyle.IndentWrappedFunctionNames = false;
|
||||
LLVMStyle.IndentWidth = 2;
|
||||
LLVMStyle.InsertTrailingCommas = FormatStyle::TCS_None;
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace format {
|
|||
TYPE(ConflictAlternative) \
|
||||
TYPE(ConflictEnd) \
|
||||
TYPE(ConflictStart) \
|
||||
TYPE(ConstraintJunctions) \
|
||||
TYPE(CtorInitializerColon) \
|
||||
TYPE(CtorInitializerComma) \
|
||||
TYPE(DesignatedInitializerLSquare) \
|
||||
|
@ -590,6 +591,7 @@ public:
|
|||
case tok::kw__Atomic:
|
||||
case tok::kw___attribute:
|
||||
case tok::kw___underlying_type:
|
||||
case tok::kw_requires:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
|
|
@ -1367,7 +1367,7 @@ private:
|
|||
TT_ImplicitStringLiteral, TT_InlineASMBrace, TT_JsFatArrow,
|
||||
TT_LambdaArrow, TT_NamespaceMacro, TT_OverloadedOperator,
|
||||
TT_RegexLiteral, TT_TemplateString, TT_ObjCStringLiteral,
|
||||
TT_UntouchableMacroFunc))
|
||||
TT_UntouchableMacroFunc, TT_ConstraintJunctions))
|
||||
CurrentToken->setType(TT_Unknown);
|
||||
CurrentToken->Role.reset();
|
||||
CurrentToken->MatchingParen = nullptr;
|
||||
|
@ -1621,7 +1621,11 @@ private:
|
|||
!Current.Previous->is(tok::kw_operator)) {
|
||||
// not auto operator->() -> xxx;
|
||||
Current.setType(TT_TrailingReturnArrow);
|
||||
|
||||
} else if (Current.is(tok::arrow) && Current.Previous &&
|
||||
Current.Previous->is(tok::r_brace)) {
|
||||
// Concept implicit conversion contraint needs to be treated like
|
||||
// a trailing return type ... } -> <type>.
|
||||
Current.setType(TT_TrailingReturnArrow);
|
||||
} else if (isDeductionGuide(Current)) {
|
||||
// Deduction guides trailing arrow " A(...) -> A<T>;".
|
||||
Current.setType(TT_TrailingReturnArrow);
|
||||
|
@ -1722,8 +1726,8 @@ private:
|
|||
// colon after this, this is the only place which annotates the identifier
|
||||
// as a selector.)
|
||||
Current.setType(TT_SelectorName);
|
||||
} else if (Current.isOneOf(tok::identifier, tok::kw_const,
|
||||
tok::kw_noexcept) &&
|
||||
} else if (Current.isOneOf(tok::identifier, tok::kw_const, tok::kw_noexcept,
|
||||
tok::kw_requires) &&
|
||||
Current.Previous &&
|
||||
!Current.Previous->isOneOf(tok::equal, tok::at) &&
|
||||
Line.MightBeFunctionDecl && Contexts.size() == 1) {
|
||||
|
@ -1839,8 +1843,8 @@ private:
|
|||
// Functions which end with decorations like volatile, noexcept are unlikely
|
||||
// to be casts.
|
||||
if (Tok.Next->isOneOf(tok::kw_noexcept, tok::kw_volatile, tok::kw_const,
|
||||
tok::kw_throw, tok::arrow, Keywords.kw_override,
|
||||
Keywords.kw_final) ||
|
||||
tok::kw_requires, tok::kw_throw, tok::arrow,
|
||||
Keywords.kw_override, Keywords.kw_final) ||
|
||||
isCpp11AttributeSpecifier(*Tok.Next))
|
||||
return false;
|
||||
|
||||
|
@ -2817,6 +2821,14 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
|
|||
isKeywordWithCondition(*Right.MatchingParen->Previous))
|
||||
return true;
|
||||
}
|
||||
|
||||
// requires ( or requires(
|
||||
if (Right.is(tok::l_paren) && Left.is(tok::kw_requires))
|
||||
return spaceRequiredBeforeParens(Right);
|
||||
// requires clause Concept1<T> && Concept2<T>
|
||||
if (Left.is(TT_ConstraintJunctions) && Right.is(tok::identifier))
|
||||
return true;
|
||||
|
||||
if (Left.is(tok::l_paren) || Right.is(tok::r_paren))
|
||||
return (Right.is(TT_CastRParen) ||
|
||||
(Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen)))
|
||||
|
@ -3594,11 +3606,17 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line,
|
|||
Right.Previous->is(tok::string_literal) &&
|
||||
Right.Next->is(tok::string_literal))
|
||||
return true;
|
||||
// Can break after template<> declaration
|
||||
if (Right.Previous->ClosesTemplateDeclaration &&
|
||||
Right.Previous->MatchingParen &&
|
||||
Right.Previous->MatchingParen->NestingLevel == 0 &&
|
||||
Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes)
|
||||
return true;
|
||||
Right.Previous->MatchingParen->NestingLevel == 0) {
|
||||
// Put concepts on the next line e.g.
|
||||
// template<typename T>
|
||||
// concept ...
|
||||
if (Right.is(tok::kw_concept))
|
||||
return Style.BreakBeforeConceptDeclarations;
|
||||
return (Style.AlwaysBreakTemplateDeclarations == FormatStyle::BTDS_Yes);
|
||||
}
|
||||
if (Right.is(TT_CtorInitializerComma) &&
|
||||
Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma &&
|
||||
!Style.ConstructorInitializerAllOnOneLineOrOnePerLine)
|
||||
|
|
|
@ -626,8 +626,16 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel,
|
|||
if (MacroBlock && FormatTok->is(tok::l_paren))
|
||||
parseParens();
|
||||
|
||||
if (FormatTok->is(tok::arrow)) {
|
||||
// Following the } we can find a trailing return type arrow
|
||||
// as part of an implicit conversion constraint.
|
||||
nextToken();
|
||||
parseStructuralElement();
|
||||
}
|
||||
|
||||
if (MunchSemi && FormatTok->Tok.is(tok::semi))
|
||||
nextToken();
|
||||
|
||||
Line->Level = InitialLevel;
|
||||
|
||||
if (PPStartHash == PPEndHash) {
|
||||
|
@ -1262,6 +1270,12 @@ void UnwrappedLineParser::parseStructuralElement() {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case tok::kw_concept:
|
||||
parseConcept();
|
||||
break;
|
||||
case tok::kw_requires:
|
||||
parseRequires();
|
||||
break;
|
||||
case tok::kw_enum:
|
||||
// Ignore if this is part of "template <enum ...".
|
||||
if (Previous && Previous->is(tok::less)) {
|
||||
|
@ -2279,6 +2293,117 @@ void UnwrappedLineParser::parseAccessSpecifier() {
|
|||
addUnwrappedLine();
|
||||
}
|
||||
|
||||
void UnwrappedLineParser::parseConcept() {
|
||||
assert(FormatTok->Tok.is(tok::kw_concept) && "'concept' expected");
|
||||
nextToken();
|
||||
if (!FormatTok->Tok.is(tok::identifier))
|
||||
return;
|
||||
nextToken();
|
||||
if (!FormatTok->Tok.is(tok::equal))
|
||||
return;
|
||||
nextToken();
|
||||
if (FormatTok->Tok.is(tok::kw_requires)) {
|
||||
nextToken();
|
||||
parseRequiresExpression(Line->Level);
|
||||
} else {
|
||||
parseConstraintExpression(Line->Level);
|
||||
}
|
||||
}
|
||||
|
||||
void UnwrappedLineParser::parseRequiresExpression(unsigned int OriginalLevel) {
|
||||
// requires (R range)
|
||||
if (FormatTok->Tok.is(tok::l_paren)) {
|
||||
parseParens();
|
||||
if (Style.IndentRequires && OriginalLevel != Line->Level) {
|
||||
addUnwrappedLine();
|
||||
--Line->Level;
|
||||
}
|
||||
}
|
||||
|
||||
if (FormatTok->Tok.is(tok::l_brace)) {
|
||||
if (Style.BraceWrapping.AfterFunction)
|
||||
addUnwrappedLine();
|
||||
FormatTok->setType(TT_FunctionLBrace);
|
||||
parseBlock(/*MustBeDeclaration=*/false);
|
||||
addUnwrappedLine();
|
||||
} else {
|
||||
parseConstraintExpression(OriginalLevel);
|
||||
}
|
||||
}
|
||||
|
||||
void UnwrappedLineParser::parseConstraintExpression(
|
||||
unsigned int OriginalLevel) {
|
||||
// requires Id<T> && Id<T> || Id<T>
|
||||
while (
|
||||
FormatTok->isOneOf(tok::identifier, tok::kw_requires, tok::coloncolon)) {
|
||||
nextToken();
|
||||
while (FormatTok->isOneOf(tok::identifier, tok::coloncolon, tok::less,
|
||||
tok::greater, tok::comma, tok::ellipsis)) {
|
||||
if (FormatTok->Tok.is(tok::less)) {
|
||||
parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false,
|
||||
/*ClosingBraceKind=*/tok::greater);
|
||||
continue;
|
||||
}
|
||||
nextToken();
|
||||
}
|
||||
if (FormatTok->Tok.is(tok::kw_requires)) {
|
||||
parseRequiresExpression(OriginalLevel);
|
||||
}
|
||||
if (FormatTok->Tok.is(tok::less)) {
|
||||
parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false,
|
||||
/*ClosingBraceKind=*/tok::greater);
|
||||
}
|
||||
|
||||
if (FormatTok->Tok.is(tok::l_paren)) {
|
||||
parseParens();
|
||||
}
|
||||
if (FormatTok->Tok.is(tok::l_brace)) {
|
||||
if (Style.BraceWrapping.AfterFunction)
|
||||
addUnwrappedLine();
|
||||
FormatTok->setType(TT_FunctionLBrace);
|
||||
parseBlock(/*MustBeDeclaration=*/false);
|
||||
}
|
||||
if (FormatTok->Tok.is(tok::semi)) {
|
||||
// Eat any trailing semi.
|
||||
nextToken();
|
||||
addUnwrappedLine();
|
||||
}
|
||||
if (FormatTok->Tok.is(tok::colon)) {
|
||||
return;
|
||||
}
|
||||
if (!FormatTok->Tok.isOneOf(tok::ampamp, tok::pipepipe)) {
|
||||
if (FormatTok->Previous &&
|
||||
!FormatTok->Previous->isOneOf(tok::identifier, tok::kw_requires,
|
||||
tok::coloncolon)) {
|
||||
addUnwrappedLine();
|
||||
}
|
||||
if (Style.IndentRequires && OriginalLevel != Line->Level) {
|
||||
--Line->Level;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
FormatTok->setType(TT_ConstraintJunctions);
|
||||
}
|
||||
|
||||
nextToken();
|
||||
}
|
||||
}
|
||||
|
||||
void UnwrappedLineParser::parseRequires() {
|
||||
assert(FormatTok->Tok.is(tok::kw_requires) && "'requires' expected");
|
||||
|
||||
unsigned OriginalLevel = Line->Level;
|
||||
if (FormatTok->Previous && FormatTok->Previous->is(tok::greater)) {
|
||||
addUnwrappedLine();
|
||||
if (Style.IndentRequires) {
|
||||
Line->Level++;
|
||||
}
|
||||
}
|
||||
nextToken();
|
||||
|
||||
parseRequiresExpression(OriginalLevel);
|
||||
}
|
||||
|
||||
bool UnwrappedLineParser::parseEnum() {
|
||||
// Won't be 'enum' for NS_ENUMs.
|
||||
if (FormatTok->Tok.is(tok::kw_enum))
|
||||
|
|
|
@ -113,6 +113,10 @@ private:
|
|||
void parseNew();
|
||||
void parseAccessSpecifier();
|
||||
bool parseEnum();
|
||||
void parseConcept();
|
||||
void parseRequires();
|
||||
void parseRequiresExpression(unsigned int OriginalLevel);
|
||||
void parseConstraintExpression(unsigned int OriginalLevel);
|
||||
void parseJavaEnumBody();
|
||||
// Parses a record (aka class) as a top level element. If ParseAsExpr is true,
|
||||
// parses the record as a child block, i.e. if the class declaration is an
|
||||
|
|
|
@ -14104,6 +14104,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
|
|||
CHECK_PARSE_BOOL(BinPackArguments);
|
||||
CHECK_PARSE_BOOL(BinPackParameters);
|
||||
CHECK_PARSE_BOOL(BreakAfterJavaFieldAnnotations);
|
||||
CHECK_PARSE_BOOL(BreakBeforeConceptDeclarations);
|
||||
CHECK_PARSE_BOOL(BreakBeforeTernaryOperators);
|
||||
CHECK_PARSE_BOOL(BreakStringLiterals);
|
||||
CHECK_PARSE_BOOL(CompactNamespaces);
|
||||
|
@ -14115,6 +14116,7 @@ TEST_F(FormatTest, ParsesConfigurationBools) {
|
|||
CHECK_PARSE_BOOL(IndentCaseLabels);
|
||||
CHECK_PARSE_BOOL(IndentCaseBlocks);
|
||||
CHECK_PARSE_BOOL(IndentGotoLabels);
|
||||
CHECK_PARSE_BOOL(IndentRequires);
|
||||
CHECK_PARSE_BOOL(IndentWrappedFunctionNames);
|
||||
CHECK_PARSE_BOOL(KeepEmptyLinesAtTheStartOfBlocks);
|
||||
CHECK_PARSE_BOOL(ObjCSpaceAfterProperty);
|
||||
|
@ -17288,6 +17290,277 @@ TEST_F(FormatTest, WebKitDefaultStyle) {
|
|||
"}",
|
||||
Style);
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, ConceptsAndRequires) {
|
||||
FormatStyle Style = getLLVMStyle();
|
||||
Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
|
||||
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept Hashable = requires(T a) {\n"
|
||||
" { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;\n"
|
||||
"};",
|
||||
Style);
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept EqualityComparable = requires(T a, T b) {\n"
|
||||
" { a == b } -> bool;\n"
|
||||
"};",
|
||||
Style);
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept EqualityComparable = requires(T a, T b) {\n"
|
||||
" { a == b } -> bool;\n"
|
||||
" { a != b } -> bool;\n"
|
||||
"};",
|
||||
Style);
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept EqualityComparable = requires(T a, T b) {\n"
|
||||
" { a == b } -> bool;\n"
|
||||
" { a != b } -> bool;\n"
|
||||
"};",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename It>\n"
|
||||
"requires Iterator<It>\n"
|
||||
"void sort(It begin, It end) {\n"
|
||||
" //....\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept Large = sizeof(T) > 10;",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename T, typename U>\n"
|
||||
"concept FooableWith = requires(T t, U u) {\n"
|
||||
" typename T::foo_type;\n"
|
||||
" { t.foo(u) } -> typename T::foo_type;\n"
|
||||
" t++;\n"
|
||||
"};\n"
|
||||
"void doFoo(FooableWith<int> auto t) {\n"
|
||||
" t.foo(3);\n"
|
||||
"}",
|
||||
Style);
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept Context = sizeof(T) == 1;",
|
||||
Style);
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept Context = is_specialization_of_v<context, T>;",
|
||||
Style);
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept Node = std::is_object_v<T>;",
|
||||
Style);
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept Tree = true;",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename T> int g(T i) requires Concept1<I> {\n"
|
||||
" //...\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat(
|
||||
"template <typename T> int g(T i) requires Concept1<I> && Concept2<I> {\n"
|
||||
" //...\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat(
|
||||
"template <typename T> int g(T i) requires Concept1<I> || Concept2<I> {\n"
|
||||
" //...\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename T>\n"
|
||||
"veryveryvery_long_return_type g(T i) requires Concept1<I> || "
|
||||
"Concept2<I> {\n"
|
||||
" //...\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename T>\n"
|
||||
"veryveryvery_long_return_type g(T i) requires Concept1<I> && "
|
||||
"Concept2<I> {\n"
|
||||
" //...\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat(
|
||||
"template <typename T>\n"
|
||||
"veryveryvery_long_return_type g(T i) requires Concept1 && Concept2 {\n"
|
||||
" //...\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat(
|
||||
"template <typename T>\n"
|
||||
"veryveryvery_long_return_type g(T i) requires Concept1 || Concept2 {\n"
|
||||
" //...\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename It>\n"
|
||||
"requires Foo<It>() && Bar<It> {\n"
|
||||
" //....\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename It>\n"
|
||||
"requires Foo<Bar<It>>() && Bar<Foo<It, It>> {\n"
|
||||
" //....\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename It>\n"
|
||||
"requires Foo<Bar<It, It>>() && Bar<Foo<It, It>> {\n"
|
||||
" //....\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
verifyFormat(
|
||||
"template <typename It>\n"
|
||||
"requires Foo<Bar<It>, Baz<It>>() && Bar<Foo<It>, Baz<It, It>> {\n"
|
||||
" //....\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
Style.IndentRequires = true;
|
||||
verifyFormat("template <typename It>\n"
|
||||
" requires Iterator<It>\n"
|
||||
"void sort(It begin, It end) {\n"
|
||||
" //....\n"
|
||||
"}",
|
||||
Style);
|
||||
verifyFormat("template <std::size index_>\n"
|
||||
" requires(index_ < sizeof...(Children_))\n"
|
||||
"Tree auto &child() {\n"
|
||||
" // ...\n"
|
||||
"}",
|
||||
Style);
|
||||
|
||||
Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept Hashable = requires (T a) {\n"
|
||||
" { std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;\n"
|
||||
"};",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <class T = void>\n"
|
||||
" requires EqualityComparable<T> || Same<T, void>\n"
|
||||
"struct equal_to;",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <class T>\n"
|
||||
" requires requires {\n"
|
||||
" T{};\n"
|
||||
" T (int);\n"
|
||||
" }\n",
|
||||
Style);
|
||||
|
||||
Style.ColumnLimit = 78;
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept Context = Traits<typename T::traits_type> and\n"
|
||||
" Interface<typename T::interface_type> and\n"
|
||||
" Request<typename T::request_type> and\n"
|
||||
" Response<typename T::response_type> and\n"
|
||||
" ContextExtension<typename T::extension_type> and\n"
|
||||
" ::std::is_copy_constructable<T> and "
|
||||
"::std::is_move_constructable<T> and\n"
|
||||
" requires (T c) {\n"
|
||||
" { c.response; } -> Response;\n"
|
||||
"} and requires (T c) {\n"
|
||||
" { c.request; } -> Request;\n"
|
||||
"}\n",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept Context = Traits<typename T::traits_type> or\n"
|
||||
" Interface<typename T::interface_type> or\n"
|
||||
" Request<typename T::request_type> or\n"
|
||||
" Response<typename T::response_type> or\n"
|
||||
" ContextExtension<typename T::extension_type> or\n"
|
||||
" ::std::is_copy_constructable<T> or "
|
||||
"::std::is_move_constructable<T> or\n"
|
||||
" requires (T c) {\n"
|
||||
" { c.response; } -> Response;\n"
|
||||
"} or requires (T c) {\n"
|
||||
" { c.request; } -> Request;\n"
|
||||
"}\n",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename T>\n"
|
||||
"concept Context = Traits<typename T::traits_type> &&\n"
|
||||
" Interface<typename T::interface_type> &&\n"
|
||||
" Request<typename T::request_type> &&\n"
|
||||
" Response<typename T::response_type> &&\n"
|
||||
" ContextExtension<typename T::extension_type> &&\n"
|
||||
" ::std::is_copy_constructable<T> && "
|
||||
"::std::is_move_constructable<T> &&\n"
|
||||
" requires (T c) {\n"
|
||||
" { c.response; } -> Response;\n"
|
||||
"} && requires (T c) {\n"
|
||||
" { c.request; } -> Request;\n"
|
||||
"}\n",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <typename T>\nconcept someConcept = Constraint1<T> && "
|
||||
"Constraint2<T>;");
|
||||
|
||||
Style.BreakBeforeBraces = FormatStyle::BS_Custom;
|
||||
Style.BraceWrapping.AfterFunction = true;
|
||||
Style.BraceWrapping.AfterClass = true;
|
||||
Style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes;
|
||||
Style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon;
|
||||
verifyFormat("void Foo () requires (std::copyable<T>)\n"
|
||||
"{\n"
|
||||
" return\n"
|
||||
"}\n",
|
||||
Style);
|
||||
|
||||
verifyFormat("void Foo () requires std::copyable<T>\n"
|
||||
"{\n"
|
||||
" return\n"
|
||||
"}\n",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <std::semiregular F, std::semiregular... Args>\n"
|
||||
" requires (std::invocable<F, std::invoke_result_t<Args>...>)\n"
|
||||
"struct constant;",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <std::semiregular F, std::semiregular... Args>\n"
|
||||
" requires std::invocable<F, std::invoke_result_t<Args>...>\n"
|
||||
"struct constant;",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <class T>\n"
|
||||
"class plane_with_very_very_very_long_name\n"
|
||||
"{\n"
|
||||
" constexpr plane_with_very_very_very_long_name () requires "
|
||||
"std::copyable<T>\n"
|
||||
" : plane_with_very_very_very_long_name (1)\n"
|
||||
" {\n"
|
||||
" }\n"
|
||||
"}\n",
|
||||
Style);
|
||||
|
||||
verifyFormat("template <class T>\n"
|
||||
"class plane_with_long_name\n"
|
||||
"{\n"
|
||||
" constexpr plane_with_long_name () requires std::copyable<T>\n"
|
||||
" : plane_with_long_name (1)\n"
|
||||
" {\n"
|
||||
" }\n"
|
||||
"}\n",
|
||||
Style);
|
||||
|
||||
Style.BreakBeforeConceptDeclarations = false;
|
||||
verifyFormat("template <typename T> concept Tree = true;", Style);
|
||||
|
||||
Style.IndentRequires = false;
|
||||
verifyFormat("template <std::semiregular F, std::semiregular... Args>\n"
|
||||
"requires (std::invocable<F, std::invoke_result_t<Args>...>) "
|
||||
"struct constant;",
|
||||
Style);
|
||||
}
|
||||
} // namespace
|
||||
} // namespace format
|
||||
} // namespace clang
|
||||
|
|
Loading…
Reference in New Issue