mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-19 19:45:40 -04:00
[clang-format] [PR35518] C++17 deduction guides are wrongly formatted
Summary: see https://bugs.llvm.org/show_bug.cgi?id=35518 clang-format removes spaces around deduction guides but not trailing return types, make the consistent ``` template <typename T> S(T)->S<T>; auto f(int, int) -> double; ``` becomes ``` template <typename T> S(T) -> S<T>; auto f(int, int) -> double; ``` Reviewers: klimek, mitchell-stellar, owenpan, sammccall, lichray, curdeius, KyrBoh Reviewed By: curdeius Subscribers: merge_guards_bot, hans, lichray, cfe-commits Tags: #clang-format, #clang-tools-extra, #clang Differential Revision: https://reviews.llvm.org/D69577
This commit is contained in:
parent
1a6903bdfe
commit
76ec6b1ef6
@ -1350,6 +1350,70 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
static FormatToken *untilMatchingParen(FormatToken *Current) {
|
||||
// Used when `MatchingParen` is not yet established.
|
||||
int ParenLevel = 0;
|
||||
while (Current) {
|
||||
if (Current->is(tok::l_paren))
|
||||
ParenLevel++;
|
||||
if (Current->is(tok::r_paren))
|
||||
ParenLevel--;
|
||||
if (ParenLevel < 1)
|
||||
break;
|
||||
Current = Current->Next;
|
||||
}
|
||||
return Current;
|
||||
}
|
||||
|
||||
static bool isDeductionGuide(FormatToken &Current) {
|
||||
// Look for a deduction guide template<T> A(...) -> A<...>;
|
||||
if (Current.Previous && Current.Previous->is(tok::r_paren) &&
|
||||
Current.startsSequence(tok::arrow, tok::identifier, tok::less)) {
|
||||
// Find the TemplateCloser.
|
||||
FormatToken *TemplateCloser = Current.Next->Next;
|
||||
int NestingLevel = 0;
|
||||
while (TemplateCloser) {
|
||||
// Skip over an expressions in parens A<(3 < 2)>;
|
||||
if (TemplateCloser->is(tok::l_paren)) {
|
||||
// No Matching Paren yet so skip to matching paren
|
||||
TemplateCloser = untilMatchingParen(TemplateCloser);
|
||||
}
|
||||
if (TemplateCloser->is(tok::less))
|
||||
NestingLevel++;
|
||||
if (TemplateCloser->is(tok::greater))
|
||||
NestingLevel--;
|
||||
if (NestingLevel < 1)
|
||||
break;
|
||||
TemplateCloser = TemplateCloser->Next;
|
||||
}
|
||||
// Assuming we have found the end of the template ensure its followed
|
||||
// with a semi-colon.
|
||||
if (TemplateCloser && TemplateCloser->Next &&
|
||||
TemplateCloser->Next->is(tok::semi) &&
|
||||
Current.Previous->MatchingParen) {
|
||||
// Determine if the identifier `A` prior to the A<..>; is the same as
|
||||
// prior to the A(..)
|
||||
FormatToken *LeadingIdentifier =
|
||||
Current.Previous->MatchingParen->Previous;
|
||||
|
||||
// Differentiate a deduction guide by seeing the
|
||||
// > of the template prior to the leading identifier.
|
||||
if (LeadingIdentifier) {
|
||||
FormatToken *PriorLeadingIdentifier = LeadingIdentifier->Previous;
|
||||
// Skip back past explicit decoration
|
||||
if (PriorLeadingIdentifier &&
|
||||
PriorLeadingIdentifier->is(tok::kw_explicit))
|
||||
PriorLeadingIdentifier = PriorLeadingIdentifier->Previous;
|
||||
|
||||
return (PriorLeadingIdentifier &&
|
||||
PriorLeadingIdentifier->is(TT_TemplateCloser) &&
|
||||
LeadingIdentifier->TokenText == Current.Next->TokenText);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void determineTokenType(FormatToken &Current) {
|
||||
if (!Current.is(TT_Unknown))
|
||||
// The token type is already known.
|
||||
@ -1397,6 +1461,10 @@ private:
|
||||
!Current.Previous->is(tok::kw_operator)) {
|
||||
// not auto operator->() -> xxx;
|
||||
Current.Type = TT_TrailingReturnArrow;
|
||||
|
||||
} else if (isDeductionGuide(Current)) {
|
||||
// Deduction guides trailing arrow " A(...) -> A<T>;".
|
||||
Current.Type = TT_TrailingReturnArrow;
|
||||
} else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) {
|
||||
Current.Type = determineStarAmpUsage(Current,
|
||||
Contexts.back().CanBeExpression &&
|
||||
|
@ -4977,6 +4977,29 @@ TEST_F(FormatTest, TrailingReturnType) {
|
||||
verifyFormat("void f() { auto a = b->c(); }");
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, DeductionGuides) {
|
||||
verifyFormat("template <class T> A(const T &, const T &) -> A<T &>;");
|
||||
verifyFormat("template <class T> explicit A(T &, T &&) -> A<T>;");
|
||||
verifyFormat("template <class... Ts> S(Ts...) -> S<Ts...>;");
|
||||
verifyFormat(
|
||||
"template <class... T>\n"
|
||||
"array(T &&... t) -> array<std::common_type_t<T...>, sizeof...(T)>;");
|
||||
verifyFormat("template <class T> A() -> A<decltype(p->foo<3>())>;");
|
||||
verifyFormat("template <class T> A() -> A<decltype(foo<traits<1>>)>;");
|
||||
verifyFormat("template <class T> A() -> A<sizeof(p->foo<1>)>;");
|
||||
verifyFormat("template <class T> A() -> A<(3 < 2)>;");
|
||||
verifyFormat("template <class T> A() -> A<((3) < (2))>;");
|
||||
verifyFormat("template <class T> x() -> x<1>;");
|
||||
verifyFormat("template <class T> explicit x(T &) -> x<1>;");
|
||||
|
||||
// Ensure not deduction guides.
|
||||
verifyFormat("c()->f<int>();");
|
||||
verifyFormat("x()->foo<1>;");
|
||||
verifyFormat("x = p->foo<3>();");
|
||||
verifyFormat("x()->x<1>();");
|
||||
verifyFormat("x()->x<1>;");
|
||||
}
|
||||
|
||||
TEST_F(FormatTest, BreaksFunctionDeclarationsWithTrailingTokens) {
|
||||
// Avoid breaking before trailing 'const' or other trailing annotations, if
|
||||
// they are not function-like.
|
||||
|
Loading…
Reference in New Issue
Block a user