MyDeveloperDay updated this revision to Diff 463000.
MyDeveloperDay added a comment.

Fix pointer function arguments
Add release notes
Fix more `TT_TrailingReturnArrow` cases


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D134652/new/

https://reviews.llvm.org/D134652

Files:
  clang/.clang-format
  clang/docs/ClangFormatStyleOptions.rst
  clang/docs/ReleaseNotes.rst
  clang/include/clang/Format/Format.h
  clang/lib/Format/Format.cpp
  clang/lib/Format/FormatToken.h
  clang/lib/Format/TokenAnnotator.cpp
  clang/lib/Format/UnwrappedLineParser.cpp
  clang/tools/clang-format/ClangFormat.cpp
  clang/unittests/Format/CMakeLists.txt
  clang/unittests/Format/FormatTestCarbon.cpp
  clang/unittests/Format/TokenAnnotatorTest.cpp

Index: clang/unittests/Format/TokenAnnotatorTest.cpp
===================================================================
--- clang/unittests/Format/TokenAnnotatorTest.cpp
+++ clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -1045,6 +1045,69 @@
   EXPECT_TOKEN(Tokens[9], tok::colon, TT_GotoLabelColon);
 }
 
+TEST_F(TokenAnnotatorTest, UnderstandsCarbonReturnType) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+
+  auto Tokens = annotate("fn Sum(var a: i32, var b: i32) -> i32 {", Style);
+  ASSERT_EQ(Tokens.size(), 17u) << Tokens;
+  EXPECT_TOKEN(Tokens[13], tok::arrow, TT_TrailingReturnArrow);
+  EXPECT_TOKEN(Tokens[15], tok::l_brace, TT_FunctionLBrace);
+
+  Tokens = annotate("fn Add[me: Self](k: i32)->Self {", Style);
+  ASSERT_EQ(Tokens.size(), 16u) << Tokens;
+  EXPECT_TOKEN(Tokens[12], tok::arrow, TT_TrailingReturnArrow);
+  EXPECT_TOKEN(Tokens[14], tok::l_brace, TT_FunctionLBrace);
+
+  Tokens = annotate("fn Add[me: Self](k: i32)->Self;", Style);
+  ASSERT_EQ(Tokens.size(), 16u) << Tokens;
+  EXPECT_TOKEN(Tokens[12], tok::arrow, TT_TrailingReturnArrow);
+  EXPECT_TOKEN(Tokens[14], tok::semi, TT_Unknown);
+}
+
+TEST_F(TokenAnnotatorTest, UnderstandsCarbonTypeOnColon) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+
+  auto Tokens = annotate("let id: i32 = 57;", Style);
+  ASSERT_EQ(Tokens.size(), 8u) << Tokens;
+  EXPECT_TOKEN(Tokens[2], tok::colon, TT_JsTypeColon);
+}
+
+TEST_F(TokenAnnotatorTest, UnderstandsCarbonPointerTypeOnColon) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+  auto Tokens = annotate("fn GetSetX[addr me: Point*](x: i32) -> i32 {", Style);
+  ASSERT_EQ(Tokens.size(), 18u) << Tokens;
+  EXPECT_TOKEN(Tokens[5], tok::colon, TT_JsTypeColon);
+  EXPECT_TOKEN(Tokens[7], tok::star, TT_PointerOrReference);
+
+  Tokens = annotate(
+      "fn GetSetX[addr me: Point*, addr me: Point*](x: i32) -> i32 {", Style);
+  ASSERT_EQ(Tokens.size(), 24u) << Tokens;
+  EXPECT_TOKEN(Tokens[5], tok::colon, TT_JsTypeColon);
+  EXPECT_TOKEN(Tokens[7], tok::star, TT_PointerOrReference);
+  EXPECT_TOKEN(Tokens[11], tok::colon, TT_JsTypeColon);
+  EXPECT_TOKEN(Tokens[13], tok::star, TT_PointerOrReference);
+}
+
+TEST_F(TokenAnnotatorTest, UnderstandsCarbonTypeOnColonForLoop) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+
+  auto Tokens = annotate("for (var name: String in names) {", Style);
+  ASSERT_EQ(Tokens.size(), 11u) << Tokens;
+  EXPECT_TOKEN(Tokens[4], tok::colon, TT_JsTypeColon);
+}
+
+TEST_F(TokenAnnotatorTest, UnderstandsCarbonTypeExclaim) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+
+  auto Tokens = annotate("(T:! Addable)", Style);
+  ASSERT_EQ(Tokens.size(), 7u) << Tokens;
+  EXPECT_TOKEN(Tokens[2], tok::colon, TT_JsTypeColon);
+  EXPECT_TOKEN(Tokens[3], tok::exclaim, TT_UnaryOperator);
+  ASSERT_EQ(Tokens[3]->SpacesRequiredBefore, false);
+  EXPECT_TOKEN(Tokens[4], tok::identifier, TT_Unknown);
+  ASSERT_EQ(Tokens[4]->SpacesRequiredBefore, true);
+}
+
 } // namespace
 } // namespace format
 } // namespace clang
Index: clang/unittests/Format/FormatTestCarbon.cpp
===================================================================
--- /dev/null
+++ clang/unittests/Format/FormatTestCarbon.cpp
@@ -0,0 +1,108 @@
+//===- unittest/Format/FormatTestCarbon.cpp - Formatting tests for Carbon -===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "FormatTestUtils.h"
+#include "clang/Format/Format.h"
+#include "llvm/Support/Debug.h"
+#include "gtest/gtest.h"
+
+#define DEBUG_TYPE "format-test-json"
+
+namespace clang {
+namespace format {
+
+class FormatTestCarbon : public ::testing::Test {
+protected:
+  static std::string format(llvm::StringRef Code, unsigned Offset,
+                            unsigned Length, const FormatStyle &Style) {
+    LLVM_DEBUG(llvm::errs() << "---\n");
+    LLVM_DEBUG(llvm::errs() << Code << "\n\n");
+    std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
+    tooling::Replacements Replaces = reformat(Style, Code, Ranges);
+    auto Result = applyAllReplacements(Code, Replaces);
+    EXPECT_TRUE(static_cast<bool>(Result));
+    LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
+    return *Result;
+  }
+
+  static std::string
+  format(llvm::StringRef Code,
+         const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_Carbon)) {
+    return format(Code, 0, Code.size(), Style);
+  }
+
+  static FormatStyle getStyleWithColumns(unsigned ColumnLimit) {
+    FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+    Style.ColumnLimit = ColumnLimit;
+    return Style;
+  }
+
+  static void verifyFormatStable(llvm::StringRef Code,
+                                 const FormatStyle &Style) {
+    EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable";
+  }
+
+  static void verifyFormat(
+      llvm::StringRef Code,
+      const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_Carbon)) {
+    verifyFormatStable(Code, Style);
+    EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
+  }
+};
+
+TEST_F(FormatTestCarbon, CarbonBasicFunctions) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+  verifyFormat("fn Sum(var a: i32, var b: i32) -> i32 {\n"
+               "  return a + b;\n"
+               "}",
+               Style);
+  verifyFormat("// Empty or void return type.\n"
+               "fn PrintCount(var count: i32) {\n"
+               "  Print(\" The count is { 0 } \", count);\n"
+               "}\n",
+               Style);
+}
+
+TEST_F(FormatTestCarbon, CarbonFunctionPrototype) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+
+  verifyFormat("fn GetSetX[addr me: Point*](x: i32) -> i32 {", Style);
+  verifyFormat("fn Add[me: Self](k: i32) -> Self;", Style);
+  verifyFormat("fn Add[me: Self](k: i32) -> Self {", Style);
+  verifyFormat("fn Main() -> i32 {", Style);
+}
+
+TEST_F(FormatTestCarbon, CarbonVariable) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+
+  verifyFormat("var name: auto = \"Carbon is an open-source programming\";",
+               Style);
+  verifyFormat("let id: i32 = 57;", Style);
+  verifyFormat("var total_articles_published: i32 = 4500;", Style);
+}
+
+TEST_F(FormatTestCarbon, CarbonVariableInLoop) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+
+  verifyFormat("for (var name: String in names) {", Style);
+}
+
+TEST_F(FormatTestCarbon, CarbonVariableBreakAfterClass) {
+  FormatStyle Style = getGoogleStyle(FormatStyle::LK_Carbon);
+
+  verifyFormat("class Sum {\n"
+               "  var a: i32;\n"
+               "}\n"
+               "fn Main() -> i32 {\n"
+               "  var p1: Sum = {.a = 5};\n"
+               "}",
+               Style);
+}
+
+} // namespace format
+} // end namespace clang
Index: clang/unittests/Format/CMakeLists.txt
===================================================================
--- clang/unittests/Format/CMakeLists.txt
+++ clang/unittests/Format/CMakeLists.txt
@@ -6,6 +6,7 @@
   CleanupTest.cpp
   DefinitionBlockSeparatorTest.cpp
   FormatTest.cpp
+  FormatTestCarbon.cpp
   FormatTestComments.cpp
   FormatTestCSharp.cpp
   FormatTestJS.cpp
Index: clang/tools/clang-format/ClangFormat.cpp
===================================================================
--- clang/tools/clang-format/ClangFormat.cpp
+++ clang/tools/clang-format/ClangFormat.cpp
@@ -582,7 +582,8 @@
   cl::SetVersionPrinter(PrintVersion);
   cl::ParseCommandLineOptions(
       argc, argv,
-      "A tool to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# "
+      "A tool to format "
+      "C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C#/Carbon "
       "code.\n\n"
       "If no arguments are specified, it formats the code from standard input\n"
       "and writes the result to the standard output.\n"
Index: clang/lib/Format/UnwrappedLineParser.cpp
===================================================================
--- clang/lib/Format/UnwrappedLineParser.cpp
+++ clang/lib/Format/UnwrappedLineParser.cpp
@@ -3667,9 +3667,9 @@
   // parseRecord falls through and does not yet add an unwrapped line as a
   // record declaration or definition can start a structural element.
   parseRecord();
-  // This does not apply to Java, JavaScript and C#.
+  // This does not apply to Java, JavaScript and C# or Carbon
   if (Style.Language == FormatStyle::LK_Java || Style.isJavaScript() ||
-      Style.isCSharp()) {
+      Style.isCSharp() || Style.isCarbon()) {
     if (FormatTok->is(tok::semi))
       nextToken();
     addUnwrappedLine();
Index: clang/lib/Format/TokenAnnotator.cpp
===================================================================
--- clang/lib/Format/TokenAnnotator.cpp
+++ clang/lib/Format/TokenAnnotator.cpp
@@ -617,7 +617,10 @@
       Left->setType(TT_StructuredBindingLSquare);
     } else if (Left->is(TT_Unknown)) {
       if (StartsObjCMethodExpr) {
-        Left->setType(TT_ObjCMethodExpr);
+        if (Style.isCarbon())
+          Left->setType(TT_JsTypeColon);
+        else
+          Left->setType(TT_ObjCMethodExpr);
       } else if (InsideInlineASM) {
         Left->setType(TT_InlineASMSymbolicNameLSquare);
       } else if (IsCpp11AttributeSpecifier) {
@@ -765,7 +768,7 @@
           // Remember that this is a [[using ns: foo]] C++ attribute, so we
           // don't add a space before the colon (unlike other colons).
           CurrentToken->setType(TT_AttributeColon);
-        } else if (!Style.isVerilog() &&
+        } else if (!Style.isVerilog() && !Style.isCarbon() &&
                    Left->isOneOf(TT_ArraySubscriptLSquare,
                                  TT_DesignatedInitializerLSquare)) {
           Left->setType(TT_ObjCMethodExpr);
@@ -775,6 +778,8 @@
             // FIXME(bug 36976): ObjC return types shouldn't use TT_CastRParen.
             Parent->setType(TT_CastRParen);
           }
+        } else if (Style.isCarbon()) {
+          CurrentToken->setType(TT_JsTypeColon);
         }
         ColonFound = true;
       }
@@ -1018,7 +1023,10 @@
           ++Contexts.back().FirstObjCSelectorName->ObjCSelectorNameParts;
         }
       } else if (Contexts.back().ColonIsForRangeExpr) {
-        Tok->setType(TT_RangeBasedForLoopColon);
+        if (Style.isCarbon())
+          Tok->setType(TT_JsTypeColon);
+        else
+          Tok->setType(TT_RangeBasedForLoopColon);
       } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) {
         Tok->setType(TT_BitFieldColon);
       } else if (Contexts.size() == 1 &&
@@ -1038,7 +1046,10 @@
           if (PrevPrev && PrevPrev->isOneOf(tok::r_paren, tok::kw_noexcept))
             Tok->setType(TT_CtorInitializerColon);
         } else {
-          Tok->setType(TT_InheritanceColon);
+          if (Style.isCarbon())
+            Tok->setType(TT_JsTypeColon);
+          else
+            Tok->setType(TT_InheritanceColon);
         }
       } else if (canBeObjCSelectorComponent(*Tok->Previous) && Tok->Next &&
                  (Tok->Next->isOneOf(tok::r_paren, tok::comma) ||
@@ -1048,7 +1059,10 @@
         // the colon are passed as macro arguments.
         Tok->setType(TT_ObjCMethodExpr);
       } else if (Contexts.back().ContextKind == tok::l_paren) {
-        Tok->setType(TT_InlineASMColon);
+        if (Style.isCarbon())
+          Tok->setType(TT_JsTypeColon);
+        else
+          Tok->setType(TT_InlineASMColon);
       }
       break;
     case tok::pipe:
@@ -1842,6 +1856,13 @@
       }
     }
 
+    if (Style.isCarbon()) {
+      if (Current.is(tok::arrow) && Current.Next->Next &&
+          Current.Next->Next->isOneOf(TT_FunctionLBrace, tok::semi)) {
+        Current.setType(TT_TrailingReturnArrow);
+      }
+    }
+
     // Line.MightBeFunctionDecl can only be true after the parentheses of a
     // function declaration have been found. In this case, 'Current' is a
     // trailing token of this declaration and thus cannot be a name.
@@ -2333,6 +2354,10 @@
 
     const FormatToken *NextToken = Tok.getNextNonComment();
 
+    // handle [addr me: Point*]
+    if (Style.isCarbon() && NextToken->is(tok::r_square))
+      return TT_PointerOrReference;
+
     if (InTemplateArgument && NextToken && NextToken->is(tok::kw_noexcept))
       return TT_BinaryOperator;
 
@@ -3323,6 +3348,15 @@
       Right.MatchingParen->is(TT_CastRParen)) {
     return true;
   }
+  // (T:! Addable)
+  if (Style.isCarbon()) {
+    if (Left.is(TT_JsTypeColon) && Right.is(tok::exclaim))
+      return false;
+    if (Left.is(tok::exclaim) && Left.Previous &&
+        Left.Previous->is(TT_JsTypeColon)) {
+      return true;
+    }
+  }
   if (Style.isJson() && Left.is(tok::string_literal) && Right.is(tok::colon))
     return false;
   if (Left.is(Keywords.kw_assert) && Style.Language == FormatStyle::LK_Java)
@@ -3398,6 +3432,7 @@
                     tok::kw_true, tok::kw_false)) {
     return false;
   }
+
   if (Left.is(tok::colon))
     return !Left.is(TT_ObjCMethodExpr);
   if (Left.is(tok::coloncolon))
@@ -3504,6 +3539,8 @@
           startsWithInitStatement(Line)))) {
       return false;
     }
+    if (Style.isCarbon() && Right.is(tok::r_square))
+      return false;
     return Left.Previous && !Left.Previous->isOneOf(
                                 tok::l_paren, tok::coloncolon, tok::l_square);
   }
@@ -3908,6 +3945,9 @@
         Right.is(tok::l_paren)) {
       return true;
     }
+  } else if (Style.isCarbon()) {
+    if (Right.is(TT_JsTypeColon))
+      return false;
   } else if (Style.isJavaScript()) {
     if (Left.is(TT_FatArrow))
       return true;
@@ -4092,6 +4132,14 @@
     return false;
   }
 
+  // (T:! Addable)
+  if (Style.isCarbon()) {
+    if (Left.is(tok::exclaim) && Left.Previous &&
+        Left.Previous->is(TT_JsTypeColon)) {
+      return true;
+    }
+  }
+
   if (Right.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow) ||
       Left.isOneOf(TT_TrailingReturnArrow, TT_LambdaArrow)) {
     return true;
Index: clang/lib/Format/FormatToken.h
===================================================================
--- clang/lib/Format/FormatToken.h
+++ clang/lib/Format/FormatToken.h
@@ -1143,6 +1143,10 @@
     kw_with = &IdentTable.get("with");
     kw_wor = &IdentTable.get("wor");
 
+    // Carbon keywords
+    kw_me = &IdentTable.get("me");
+    kw_fn = &IdentTable.get("fn");
+
     // Symbols that are treated as keywords.
     kw_verilogHash = &IdentTable.get("#");
     kw_verilogHashHash = &IdentTable.get("##");
@@ -1172,6 +1176,9 @@
          // Keywords from the Java section.
          kw_abstract, kw_extends, kw_implements, kw_instanceof, kw_interface});
 
+    CarbonExtraKeywords = std::unordered_set<IdentifierInfo *>(
+        {kw_me, kw_package, kw_fn, kw_abstract});
+
     // Some keywords are not included here because they don't need special
     // treatment like `showcancelled` or they should be treated as identifiers
     // like `int` and `logic`.
@@ -1406,6 +1413,10 @@
   IdentifierInfo *kw_when;
   IdentifierInfo *kw_where;
 
+  // Carbon keywords
+  IdentifierInfo *kw_me;
+  IdentifierInfo *kw_fn;
+
   // Verilog keywords
   IdentifierInfo *kw_always;
   IdentifierInfo *kw_always_comb;
@@ -1800,6 +1811,9 @@
 
   /// The Verilog keywords beyond the C++ keyword set.
   std::unordered_set<IdentifierInfo *> VerilogExtraKeywords;
+
+  /// The Carbon keywords beyond the C++ keyword set
+  std::unordered_set<IdentifierInfo *> CarbonExtraKeywords;
 };
 
 } // namespace format
Index: clang/lib/Format/Format.cpp
===================================================================
--- clang/lib/Format/Format.cpp
+++ clang/lib/Format/Format.cpp
@@ -60,14 +60,15 @@
 template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> {
   static void enumeration(IO &IO, FormatStyle::LanguageKind &Value) {
     IO.enumCase(Value, "Cpp", FormatStyle::LK_Cpp);
+    IO.enumCase(Value, "Carbon", FormatStyle::LK_Carbon);
+    IO.enumCase(Value, "CSharp", FormatStyle::LK_CSharp);
     IO.enumCase(Value, "Java", FormatStyle::LK_Java);
     IO.enumCase(Value, "JavaScript", FormatStyle::LK_JavaScript);
+    IO.enumCase(Value, "Json", FormatStyle::LK_Json);
     IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC);
     IO.enumCase(Value, "Proto", FormatStyle::LK_Proto);
     IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen);
     IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto);
-    IO.enumCase(Value, "CSharp", FormatStyle::LK_CSharp);
-    IO.enumCase(Value, "Json", FormatStyle::LK_Json);
   }
 };
 
@@ -1501,6 +1502,11 @@
     GoogleStyle.BreakStringLiterals = false;
     GoogleStyle.ColumnLimit = 100;
     GoogleStyle.NamespaceIndentation = FormatStyle::NI_All;
+  } else if (Language == FormatStyle::LK_Carbon) {
+    GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
+    GoogleStyle.MaxEmptyLinesToKeep = 1;
+    GoogleStyle.PointerAlignment = FormatStyle::PAS_Left;
+    GoogleStyle.ReflowComments = false;
   }
 
   return GoogleStyle;
@@ -3487,6 +3493,8 @@
     return FormatStyle::LK_TableGen;
   if (FileName.endswith_insensitive(".cs"))
     return FormatStyle::LK_CSharp;
+  if (FileName.endswith_insensitive(".carbon"))
+    return FormatStyle::LK_Carbon;
   if (FileName.endswith_insensitive(".json"))
     return FormatStyle::LK_Json;
   if (FileName.endswith_insensitive(".sv") ||
Index: clang/include/clang/Format/Format.h
===================================================================
--- clang/include/clang/Format/Format.h
+++ clang/include/clang/Format/Format.h
@@ -2587,6 +2587,8 @@
   enum LanguageKind : int8_t {
     /// Do not use.
     LK_None,
+    /// Should be used for Carbon
+    LK_Carbon,
     /// Should be used for C, C++.
     LK_Cpp,
     /// Should be used for C#.
@@ -2614,6 +2616,7 @@
   };
   bool isCpp() const { return Language == LK_Cpp || Language == LK_ObjC; }
   bool isCSharp() const { return Language == LK_CSharp; }
+  bool isCarbon() const { return Language == LK_Carbon; }
   bool isJson() const { return Language == LK_Json; }
   bool isJavaScript() const { return Language == LK_JavaScript; }
   bool isVerilog() const { return Language == LK_Verilog; }
@@ -4292,6 +4295,8 @@
   switch (Language) {
   case FormatStyle::LK_Cpp:
     return "C++";
+  case FormatStyle::LK_Carbon:
+    return "Carbon";
   case FormatStyle::LK_CSharp:
     return "CSharp";
   case FormatStyle::LK_ObjC:
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -419,6 +419,7 @@
 
 clang-format
 ------------
+- Basic Carbon Language Support.
 
 clang-extdef-mapping
 --------------------
Index: clang/docs/ClangFormatStyleOptions.rst
===================================================================
--- clang/docs/ClangFormatStyleOptions.rst
+++ clang/docs/ClangFormatStyleOptions.rst
@@ -3184,6 +3184,9 @@
   * ``LK_None`` (in configuration: ``None``)
     Do not use.
 
+  * ``LK_Carbon`` (in configuration: ``Carbon``)
+    Should be used for Carbon
+
   * ``LK_Cpp`` (in configuration: ``Cpp``)
     Should be used for C, C++.
 
Index: clang/.clang-format
===================================================================
--- clang/.clang-format
+++ clang/.clang-format
@@ -1 +1,2 @@
 BasedOnStyle: LLVM
+RemoveBracesLLVM: true
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to