r306406 - [clang-format] Support <>-style proto message fields

Krasimir Georgiev via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 27 06:43:07 PDT 2017


Author: krasimir
Date: Tue Jun 27 06:43:07 2017
New Revision: 306406

URL: http://llvm.org/viewvc/llvm-project?rev=306406&view=rev
Log:
[clang-format] Support <>-style proto message fields

Summary:
This patch adds support for <>-style proto message fields inside proto options.
Previously these were wrongly treated as binary operators and as such were
working only by chance for a limited number of cases.

Reviewers: djasper

Reviewed By: djasper

Subscribers: cfe-commits, klimek

Differential Revision: https://reviews.llvm.org/D34621

Modified:
    cfe/trunk/lib/Format/ContinuationIndenter.cpp
    cfe/trunk/lib/Format/FormatToken.h
    cfe/trunk/lib/Format/TokenAnnotator.cpp
    cfe/trunk/lib/Format/UnwrappedLineParser.cpp
    cfe/trunk/lib/Format/UnwrappedLineParser.h
    cfe/trunk/unittests/Format/FormatTestProto.cpp

Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=306406&r1=306405&r2=306406&view=diff
==============================================================================
--- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original)
+++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Tue Jun 27 06:43:07 2017
@@ -56,6 +56,8 @@ static bool startsNextParameter(const Fo
   if (Current.is(TT_CtorInitializerComma) &&
       Style.BreakConstructorInitializers == FormatStyle::BCIS_BeforeComma)
     return true;
+  if (Style.Language == FormatStyle::LK_Proto && Current.is(TT_SelectorName))
+    return true;
   return Previous.is(tok::comma) && !Current.isTrailingComment() &&
          ((Previous.isNot(TT_CtorInitializerComma) ||
            Style.BreakConstructorInitializers !=
@@ -499,6 +501,13 @@ void ContinuationIndenter::addTokenOnCur
   }
 }
 
+static bool lessOpensProtoMessageField(const FormatToken &LessTok,
+                                       const LineState &State) {
+  assert(LessTok.is(tok::less));
+  return LessTok.NestingLevel > 0 ||
+         (LessTok.Previous && LessTok.Previous->is(tok::equal));
+}
+
 unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State,
                                                  bool DryRun) {
   FormatToken &Current = *State.NextToken;
@@ -641,6 +650,9 @@ unsigned ContinuationIndenter::addTokenO
   // before the corresponding } or ].
   if (PreviousNonComment &&
       (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
+      (Style.Language == FormatStyle::LK_Proto &&
+       PreviousNonComment->is(tok::less) &&
+       lessOpensProtoMessageField(*PreviousNonComment, State)) ||
        (PreviousNonComment->is(TT_TemplateString) &&
         PreviousNonComment->opensScope())))
     State.Stack.back().BreakBeforeClosingBrace = true;
@@ -682,7 +694,9 @@ unsigned ContinuationIndenter::getNewLin
   if (NextNonComment->is(tok::l_brace) && NextNonComment->BlockKind == BK_Block)
     return Current.NestingLevel == 0 ? State.FirstIndent
                                      : State.Stack.back().Indent;
-  if (Current.isOneOf(tok::r_brace, tok::r_square) && State.Stack.size() > 1) {
+  if ((Current.isOneOf(tok::r_brace, tok::r_square) ||
+       (Current.is(tok::greater) && Style.Language == FormatStyle::LK_Proto)) &&
+      State.Stack.size() > 1) {
     if (Current.closesBlockOrBlockTypeList(Style))
       return State.Stack[State.Stack.size() - 2].NestedBlockIndent;
     if (Current.MatchingParen &&
@@ -1035,7 +1049,9 @@ void ContinuationIndenter::moveStatePast
   bool BreakBeforeParameter = false;
   unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall,
                                         State.Stack.back().NestedBlockIndent);
-  if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare)) {
+  if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
+      (Style.Language == FormatStyle::LK_Proto && Current.is(tok::less) &&
+       lessOpensProtoMessageField(Current, State))) {
     if (Current.opensBlockOrBlockTypeList(Style)) {
       NewIndent = Style.IndentWidth +
                   std::min(State.Column, State.Stack.back().NestedBlockIndent);

Modified: cfe/trunk/lib/Format/FormatToken.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/FormatToken.h?rev=306406&r1=306405&r2=306406&view=diff
==============================================================================
--- cfe/trunk/lib/Format/FormatToken.h (original)
+++ cfe/trunk/lib/Format/FormatToken.h Tue Jun 27 06:43:07 2017
@@ -465,7 +465,8 @@ struct FormatToken {
     return is(TT_ArrayInitializerLSquare) ||
            (is(tok::l_brace) &&
             (BlockKind == BK_Block || is(TT_DictLiteral) ||
-             (!Style.Cpp11BracedListStyle && NestingLevel == 0)));
+             (!Style.Cpp11BracedListStyle && NestingLevel == 0))) ||
+           (is(tok::less) && Style.Language == FormatStyle::LK_Proto);
   }
 
   /// \brief Same as opensBlockOrBlockTypeList, but for the closing token.

Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=306406&r1=306405&r2=306406&view=diff
==============================================================================
--- cfe/trunk/lib/Format/TokenAnnotator.cpp (original)
+++ cfe/trunk/lib/Format/TokenAnnotator.cpp Tue Jun 27 06:43:07 2017
@@ -89,7 +89,8 @@ private:
         continue;
       }
       if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) ||
-          (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext))
+          (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext &&
+           Style.Language != FormatStyle::LK_Proto))
         return false;
       // If a && or || is found and interpreted as a binary operator, this set
       // of angles is likely part of something like "a < b && c > d". If the
@@ -103,6 +104,14 @@ private:
           !Line.startsWith(tok::kw_template))
         return false;
       updateParameterCount(Left, CurrentToken);
+      if (Style.Language == FormatStyle::LK_Proto) {
+        if (FormatToken *Previous = CurrentToken->getPreviousNonComment()) {
+          if (CurrentToken->is(tok::colon) ||
+              (CurrentToken->isOneOf(tok::l_brace, tok::less) &&
+               Previous->isNot(tok::colon)))
+            Previous->Type = TT_SelectorName;
+        }
+      }
       if (!consumeToken())
         return false;
     }
@@ -440,7 +449,7 @@ private:
         if (CurrentToken->isOneOf(tok::r_paren, tok::r_square))
           return false;
         updateParameterCount(Left, CurrentToken);
-        if (CurrentToken->isOneOf(tok::colon, tok::l_brace)) {
+        if (CurrentToken->isOneOf(tok::colon, tok::l_brace, tok::less)) {
           FormatToken *Previous = CurrentToken->getPreviousNonComment();
           if (((CurrentToken->is(tok::colon) &&
                 (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) ||
@@ -2549,10 +2558,16 @@ bool TokenAnnotator::mustBreakBefore(con
     // deliberate choice and might have aligned the contents of the string
     // literal accordingly. Thus, we try keep existing line breaks.
     return Right.NewlinesBefore > 0;
-  if (Right.Previous->is(tok::l_brace) && Right.NestingLevel == 1 &&
-      Style.Language == FormatStyle::LK_Proto)
-    // Don't put enums onto single lines in protocol buffers.
+  if ((Right.Previous->is(tok::l_brace) ||
+       (Right.Previous->is(tok::less) &&
+        Right.Previous->Previous &&
+        Right.Previous->Previous->is(tok::equal))
+        ) &&
+      Right.NestingLevel == 1 && Style.Language == FormatStyle::LK_Proto) {
+    // Don't put enums or option definitions onto single lines in protocol
+    // buffers.
     return true;
+  }
   if (Right.is(TT_InlineASMBrace))
     return Right.HasUnescapedNewline;
   if (isAllmanBrace(Left) || isAllmanBrace(Right))

Modified: cfe/trunk/lib/Format/UnwrappedLineParser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.cpp?rev=306406&r1=306405&r2=306406&view=diff
==============================================================================
--- cfe/trunk/lib/Format/UnwrappedLineParser.cpp (original)
+++ cfe/trunk/lib/Format/UnwrappedLineParser.cpp Tue Jun 27 06:43:07 2017
@@ -1176,9 +1176,11 @@ void UnwrappedLineParser::parseStructura
       }
 
       nextToken();
-      if (FormatTok->Tok.is(tok::l_brace)) {
+      if (FormatTok->Tok.is(tok::l_brace))
         parseBracedList();
-      }
+      else if (Style.Language == FormatStyle::LK_Proto &&
+               FormatTok->Tok.is(tok::less))
+        parseBracedList(/*ClosingBraceKind=*/tok::greater);
       break;
     case tok::l_square:
       parseSquare();
@@ -1346,7 +1348,8 @@ bool UnwrappedLineParser::tryToParseBrac
   return true;
 }
 
-bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons) {
+bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons,
+                                          tok::TokenKind ClosingBraceKind) {
   bool HasError = false;
   nextToken();
 
@@ -1375,6 +1378,10 @@ bool UnwrappedLineParser::parseBracedLis
         parseChildBlock();
       }
     }
+    if (FormatTok->Tok.getKind() == ClosingBraceKind) {
+      nextToken();
+      return !HasError;
+    }
     switch (FormatTok->Tok.getKind()) {
     case tok::caret:
       nextToken();
@@ -1401,9 +1408,6 @@ bool UnwrappedLineParser::parseBracedLis
       FormatTok->BlockKind = BK_BracedInit;
       parseBracedList();
       break;
-    case tok::r_brace:
-      nextToken();
-      return !HasError;
     case tok::semi:
       // JavaScript (or more precisely TypeScript) can have semicolons in braced
       // lists (in so-called TypeMemberLists). Thus, the semicolon cannot be

Modified: cfe/trunk/lib/Format/UnwrappedLineParser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/UnwrappedLineParser.h?rev=306406&r1=306405&r2=306406&view=diff
==============================================================================
--- cfe/trunk/lib/Format/UnwrappedLineParser.h (original)
+++ cfe/trunk/lib/Format/UnwrappedLineParser.h Tue Jun 27 06:43:07 2017
@@ -93,7 +93,8 @@ private:
   void readTokenWithJavaScriptASI();
   void parseStructuralElement();
   bool tryToParseBracedList();
-  bool parseBracedList(bool ContinueOnSemicolons = false);
+  bool parseBracedList(bool ContinueOnSemicolons = false,
+                       tok::TokenKind ClosingBraceKind = tok::r_brace);
   void parseParens();
   void parseSquare();
   void parseIfThenElse();

Modified: cfe/trunk/unittests/Format/FormatTestProto.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTestProto.cpp?rev=306406&r1=306405&r2=306406&view=diff
==============================================================================
--- cfe/trunk/unittests/Format/FormatTestProto.cpp (original)
+++ cfe/trunk/unittests/Format/FormatTestProto.cpp Tue Jun 27 06:43:07 2017
@@ -207,6 +207,142 @@ TEST_F(FormatTestProto, FormatsOptions)
                "  field_c: \"OK\",\n"
                "  msg_field: <field_d: 123>\n"
                "};");
+
+  verifyFormat("option (MyProto.options) = {\n"
+               "  msg_field: <>\n"
+               "  field_c: \"OK\",\n"
+               "  msg_field: <field_d: 123>\n"
+               "  field_e: OK\n"
+               "  msg_field: <field_d: 12>\n"
+               "};");
+
+  verifyFormat("option (MyProto.options) = <\n"
+               "  field_a: OK\n"
+               "  field_b: \"OK\"\n"
+               "  field_c: 1\n"
+               "  field_d: 12.5\n"
+               "  field_e: OK\n"
+               ">;");
+
+  verifyFormat("option (MyProto.options) = <\n"
+               "  field_a: OK,\n"
+               "  field_b: \"OK\",\n"
+               "  field_c: 1,\n"
+               "  field_d: 12.5,\n"
+               "  field_e: OK,\n"
+               ">;");
+
+  verifyFormat("option (MyProto.options) = <\n"
+               "  field_a: \"OK\"\n"
+               "  msg_field: {field_b: OK}\n"
+               "  field_g: OK\n"
+               "  field_g: OK\n"
+               "  field_g: OK\n"
+               ">;");
+
+  verifyFormat("option (MyProto.options) = <\n"
+               "  field_a: \"OK\"\n"
+               "  msg_field<\n"
+               "    field_b: OK\n"
+               "    field_c: OK\n"
+               "    field_d: OK\n"
+               "    field_e: OK\n"
+               "    field_f: OK\n"
+               "  >\n"
+               "  field_g: OK\n"
+               ">;");
+
+  verifyFormat("option (MyProto.options) = <\n"
+               "  field_a: \"OK\"\n"
+               "  msg_field<\n"
+               "    field_b: OK,\n"
+               "    field_c: OK,\n"
+               "    field_d: OK,\n"
+               "    field_e: OK,\n"
+               "    field_f: OK\n"
+               "  >\n"
+               "  field_g: OK\n"
+               ">;");
+
+  verifyFormat("option (MyProto.options) = <\n"
+               "  field_a: \"OK\"\n"
+               "  msg_field: <\n"
+               "    field_b: OK\n"
+               "    field_c: OK\n"
+               "    field_d: OK\n"
+               "    field_e: OK\n"
+               "    field_f: OK\n"
+               "  >\n"
+               "  field_g: OK\n"
+               ">;");
+
+  verifyFormat("option (MyProto.options) = <\n"
+               "  field_a: \"OK\"\n"
+               "  msg_field: {\n"
+               "    field_b: OK\n"
+               "    field_c: OK\n"
+               "    field_d: OK\n"
+               "    field_e: OK\n"
+               "    field_f: OK\n"
+               "  }\n"
+               "  field_g: OK\n"
+               ">;");
+
+  verifyFormat("option (MyProto.options) = <\n"
+               "  field_a: \"OK\"\n"
+               "  msg_field{\n"
+               "    field_b: OK\n"
+               "    field_c: OK\n"
+               "    field_d: OK\n"
+               "    field_e: OK\n"
+               "    field_f: OK\n"
+               "  }\n"
+               "  field_g: OK\n"
+               ">;");
+
+  verifyFormat("option (MyProto.options) = {\n"
+               "  field_a: \"OK\"\n"
+               "  msg_field<\n"
+               "    field_b: OK\n"
+               "    field_c: OK\n"
+               "    field_d: OK\n"
+               "    field_e: OK\n"
+               "    field_f: OK\n"
+               "  >\n"
+               "  field_g: OK\n"
+               "};");
+
+  verifyFormat("option (MyProto.options) = {\n"
+               "  field_a: \"OK\"\n"
+               "  msg_field: <\n"
+               "    field_b: OK\n"
+               "    field_c: OK\n"
+               "    field_d: OK\n"
+               "    field_e: OK\n"
+               "    field_f: OK\n"
+               "  >\n"
+               "  field_g: OK\n"
+               "};");
+
+  verifyFormat("option (MyProto.options) = <\n"
+               "  field_a: \"OK\"\n"
+               "  msg_field{\n"
+               "    field_b: OK\n"
+               "    field_c: OK\n"
+               "    field_d: OK\n"
+               "    msg_field<\n"
+               "      field_A: 1\n"
+               "      field_B: 2\n"
+               "      field_C: 3\n"
+               "      field_D: 4\n"
+               "      field_E: 5\n"
+               "    >\n"
+               "    msg_field<field_A: 1 field_B: 2 field_C: 3 field_D: 4>\n"
+               "    field_e: OK\n"
+               "    field_f: OK\n"
+               "  }\n"
+               "  field_g: OK\n"
+               ">;");
 }
 
 TEST_F(FormatTestProto, FormatsService) {




More information about the cfe-commits mailing list