[PATCH] D79773: [clang-format] Improve clang-formats handling of concepts

MyDeveloperDay via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Tue May 12 03:11:30 PDT 2020


MyDeveloperDay created this revision.
MyDeveloperDay added reviewers: krasimir, sammccall, owenpan, jbcoe, mitchell-stellar.
MyDeveloperDay added projects: clang, clang-format.

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.

  requires(R range) {
    typename Iterator_type<R>;
    { begin(range) }
    ->Iterator_type<R>;
    { end(range) }
    ->Iterator_type<R>;
    requires Input_iterator<Iterator_type<R>>();
  };

The revision starts by resolving the additional newline added before the implicit conversion constraint and ensures that the concept keyword is always on the line below template<>

  template <typename T>
  concept bool EqualityComparable = requires(T a, T b) {
    { a == b } -> bool;
  };




Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D79773

Files:
  clang/lib/Format/TokenAnnotator.cpp
  clang/lib/Format/UnwrappedLineParser.cpp
  clang/unittests/Format/FormatTest.cpp


Index: clang/unittests/Format/FormatTest.cpp
===================================================================
--- clang/unittests/Format/FormatTest.cpp
+++ clang/unittests/Format/FormatTest.cpp
@@ -15849,6 +15849,41 @@
   verifyFormat("operator&&(int(&&)(), class Foo);", Style);
 }
 
+TEST_F(FormatTest, ConceptsImplicitConversionConstraint) {
+  FormatStyle Style = getLLVMStyle();
+
+  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 bool EqualityComparable = requires(T a, T b) {\n"
+               "  { a == b } -> bool;\n"
+               "};",
+               Style);
+  verifyFormat("template <typename T>\n"
+               "concept bool EqualityComparable = requires(T a, T b) {\n"
+               "  { a == b } -> bool;\n"
+               "  { a != b } -> bool;\n"
+               "};",
+               Style);
+  verifyFormat("template <typename T>\n"
+               "concept bool EqualityComparable = requires(T a, T b) {\n"
+               "  { a == b } -> bool;\n"
+               "  { a != b } -> bool;\n"
+               "};",
+               Style);
+
+  verifyFormat("requires(R range) {\n"
+               "  typename Iterator_type<R>;\n"
+               "  { begin(range) } -> Iterator_type<R>;\n"
+               "  { end(range) } -> Iterator_type<R>;\n"
+               "  requires Input_iterator<Iterator_type<R>>();\n"
+               "};\n",
+               Style);
+}
+
 } // namespace
 } // namespace format
 } // namespace clang
Index: clang/lib/Format/UnwrappedLineParser.cpp
===================================================================
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -628,6 +628,13 @@
 
   if (MunchSemi && FormatTok->Tok.is(tok::semi))
     nextToken();
+  else if (FormatTok->is(tok::arrow)) {
+    // Following the } we can find a trailing return type arrow
+    // as part of an implicit conversion constraint.
+    nextToken();
+    parseStructuralElement();
+  }
+
   Line->Level = InitialLevel;
 
   if (PPStartHash == PPEndHash) {
Index: clang/lib/Format/TokenAnnotator.cpp
===================================================================
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -1563,7 +1563,11 @@
                !Current.Previous->is(tok::kw_operator)) {
       // not auto operator->() -> xxx;
       Current.Type = TT_TrailingReturnArrow;
-
+    } else if (Current.is(tok::arrow) && Current.Previous &&
+               Current.Previous->is(tok::r_brace)) {
+      // Concept implicit conversion contrain needs to be treated like
+      // a trailing return type  ... } -> <type>.
+      Current.Type = TT_TrailingReturnArrow;
     } else if (isDeductionGuide(Current)) {
       // Deduction guides trailing arrow " A(...) -> A<T>;".
       Current.Type = TT_TrailingReturnArrow;
@@ -3466,6 +3470,12 @@
       return true;
   }
 
+  // Put concepts on the next line e.g.
+  // template<typename T>
+  // concept ...
+  if (Left.is(TT_TemplateCloser) && Right.is(tok::kw_concept))
+    return true;
+
   if (Right.is(tok::comment))
     return Left.BlockKind != BK_BracedInit &&
            Left.isNot(TT_CtorInitializerColon) &&


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D79773.263388.patch
Type: text/x-patch
Size: 3431 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200512/05c0da18/attachment.bin>


More information about the cfe-commits mailing list