Initial support for designated initializers.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@182767 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index f244792..acc7449 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -502,7 +502,8 @@
       } else if (Current.is(tok::lessless) &&
                  State.Stack.back().FirstLessLess != 0) {
         State.Column = State.Stack.back().FirstLessLess;
-      } else if (Current.isOneOf(tok::period, tok::arrow)) {
+      } else if (Current.isOneOf(tok::period, tok::arrow) &&
+                 Current.Type != TT_DesignatedInitializerPeriod) {
         if (State.Stack.back().CallContinuation == 0) {
           State.Column = ContinuationIndent;
           State.Stack.back().CallContinuation = State.Column;
@@ -559,7 +560,8 @@
       }
 
       State.Stack.back().LastSpace = State.Column;
-      if (Current.isOneOf(tok::arrow, tok::period))
+      if (Current.isOneOf(tok::arrow, tok::period) &&
+          Current.Type != TT_DesignatedInitializerPeriod)
         State.Stack.back().LastSpace += Current.FormatTok.TokenLength;
       State.StartOfLineLevel = State.ParenLevel;
       State.LowestLevelOnLine = State.ParenLevel;
@@ -734,7 +736,9 @@
       bool AvoidBinPacking;
       if (Current.is(tok::l_brace)) {
         NewIndent = Style.IndentWidth + LastSpace;
-        AvoidBinPacking = false;
+        const AnnotatedToken *NextNoComment = Current.getNextNoneComment();
+        AvoidBinPacking = NextNoComment &&
+                          NextNoComment->Type == TT_DesignatedInitializerPeriod;
       } else {
         NewIndent =
             4 + std::max(LastSpace, State.Stack.back().StartOfFunctionCall);
diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp
index 2cc4a94..ed39a57 100644
--- a/lib/Format/TokenAnnotator.cpp
+++ b/lib/Format/TokenAnnotator.cpp
@@ -685,6 +685,11 @@
         default:
           break;
         }
+      } else if (Current.is(tok::period)) {
+        AnnotatedToken *PreviousNoComment= Current.getPreviousNoneComment();
+        if (PreviousNoComment &&
+            PreviousNoComment->isOneOf(tok::comma, tok::l_brace))
+          Current.Type = TT_DesignatedInitializerPeriod;
       }
     }
   }
@@ -963,6 +968,11 @@
   const AnnotatedToken &Left = *Tok.Parent;
   const AnnotatedToken &Right = Tok;
 
+  if (Left.is(tok::semi))
+    return 0;
+  if (Left.is(tok::comma))
+    return 1;
+
   if (Right.Type == TT_StartOfName) {
     if (Line.First.is(tok::kw_for) && Right.PartOfMultiVariableDeclStmt)
       return 3;
@@ -983,7 +993,8 @@
       Left.Type == TT_InheritanceColon)
     return 2;
 
-  if (Right.isOneOf(tok::arrow, tok::period)) {
+  if (Right.isOneOf(tok::arrow, tok::period) &&
+      Right.Type != TT_DesignatedInitializerPeriod) {
     if (Line.Type == LT_BuilderTypeCall)
       return prec::PointerToMember;
     if (Left.isOneOf(tok::r_paren, tok::r_square) && Left.MatchingParen &&
@@ -1000,11 +1011,6 @@
   if (Line.First.is(tok::kw_for) && Left.is(tok::equal))
     return 4;
 
-  if (Left.is(tok::semi))
-    return 0;
-  if (Left.is(tok::comma))
-    return 1;
-
   // In Objective-C method expressions, prefer breaking before "param:" over
   // breaking after it.
   if (Right.Type == TT_ObjCSelectorName)
@@ -1087,8 +1093,6 @@
     return Right.Type == TT_ObjCArrayLiteral;
   if (Right.is(tok::l_square) && Right.Type != TT_ObjCMethodExpr)
     return false;
-  if (Left.is(tok::period) || Right.is(tok::period))
-    return false;
   if (Left.is(tok::colon))
     return Left.Type != TT_ObjCMethodExpr;
   if (Right.is(tok::colon))
@@ -1116,6 +1120,8 @@
     return false;
   if (Right.is(tok::ellipsis))
     return false;
+  if (Left.is(tok::period) || Right.is(tok::period))
+    return false;
   return true;
 }
 
diff --git a/lib/Format/TokenAnnotator.h b/lib/Format/TokenAnnotator.h
index 81d660d..37704ad 100644
--- a/lib/Format/TokenAnnotator.h
+++ b/lib/Format/TokenAnnotator.h
@@ -33,6 +33,7 @@
   TT_CastRParen,
   TT_ConditionalExpr,
   TT_CtorInitializerColon,
+  TT_DesignatedInitializerPeriod,
   TT_ImplicitStringLiteral,
   TT_InlineASMColon,
   TT_InheritanceColon,
diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp
index 2af1dd7..3bdf59a 100644
--- a/unittests/Format/FormatTest.cpp
+++ b/unittests/Format/FormatTest.cpp
@@ -1456,6 +1456,24 @@
                getLLVMStyleWithColumns(40));
 }
 
+TEST_F(FormatTest, DesignatedInitializers) {
+  verifyFormat("const struct A a = { .a = 1, .b = 2 };");
+  verifyFormat("const struct A a = { .aaaaaaaaaa = 1,\n"
+               "                     .bbbbbbbbbb = 2,\n"
+               "                     .cccccccccc = 3,\n"
+               "                     .dddddddddd = 4,\n"
+               "                     .eeeeeeeeee = 5 };");
+  verifyFormat("const struct Aaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaa = {\n"
+               "  .aaaaaaaaaaaaaaaaaaaaaaaaaaa = 1,\n"
+               "  .bbbbbbbbbbbbbbbbbbbbbbbbbbb = 2,\n"
+               "  .ccccccccccccccccccccccccccc = 3,\n"
+               "  .ddddddddddddddddddddddddddd = 4,\n"
+               "  .eeeeeeeeeeeeeeeeeeeeeeeeeee = 5\n"
+               "};");
+
+  verifyGoogleFormat("const struct A a = {.a = 1, .b = 2};");
+}
+
 TEST_F(FormatTest, NestedStaticInitializers) {
   verifyFormat("static A x = { { {} } };\n");
   verifyFormat("static A x = { { { init1, init2, init3, init4 },\n"