summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp68
-rw-r--r--clang/unittests/Format/FormatTest.cpp23
2 files changed, 91 insertions, 0 deletions
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 98b87c0f5a2..3bd415ebd69 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -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 &&
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index ea03ee1c3cc..eacb389400b 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -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.
OpenPOWER on IntegriCloud