https://github.com/bdunkin updated 
https://github.com/llvm/llvm-project/pull/143781

>From f0a9d10d5306e5f074259c88426725b5adfe6994 Mon Sep 17 00:00:00 2001
From: Ben Dunkin <bdun...@arena.net>
Date: Fri, 6 Jun 2025 14:23:29 -0700
Subject: [PATCH] Rewrite AlignArrayOfStructures implementation to allow
 non-rectangular arrays, and fix numerous formatting bugs.

---
 clang/lib/Format/ContinuationIndenter.cpp |  48 +-
 clang/lib/Format/FormatToken.cpp          |  10 +
 clang/lib/Format/FormatToken.h            |  13 +-
 clang/lib/Format/TokenAnnotator.cpp       |  40 +-
 clang/lib/Format/WhitespaceManager.cpp    | 546 ++++++-------
 clang/lib/Format/WhitespaceManager.h      | 100 +--
 clang/unittests/Format/FormatTest.cpp     | 883 ++++++++++++++++++----
 7 files changed, 1147 insertions(+), 493 deletions(-)

diff --git a/clang/lib/Format/ContinuationIndenter.cpp 
b/clang/lib/Format/ContinuationIndenter.cpp
index 9a10403b858f9..38db977632533 100644
--- a/clang/lib/Format/ContinuationIndenter.cpp
+++ b/clang/lib/Format/ContinuationIndenter.cpp
@@ -304,12 +304,15 @@ bool ContinuationIndenter::canBreak(const LineState 
&State) {
                                    Current.closesBlockOrBlockTypeList(Style))) 
{
     return false;
   }
+
   // The opening "{" of a braced list has to be on the same line as the first
-  // element if it is nested in another braced init list or function call.
+  // element if it is nested in another braced init list or function call,
+  // unless it is an array initializer that needs to be aligned.
   if (!Current.MustBreakBefore && Previous.is(tok::l_brace) &&
       Previous.isNot(TT_DictLiteral) && Previous.is(BK_BracedInit) &&
       Previous.Previous &&
-      Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma)) {
+      Previous.Previous->isOneOf(tok::l_brace, tok::l_paren, tok::comma) &&
+      !Previous.opensAlignedArrayInitializer(Style)) {
     return false;
   }
   // This prevents breaks like:
@@ -411,6 +414,7 @@ bool ContinuationIndenter::mustBreak(const LineState 
&State) {
   }
   if (CurrentState.BreakBeforeClosingBrace &&
       (Current.closesBlockOrBlockTypeList(Style) ||
+       Current.closesAlignedArrayInitializer(Style) ||
        (Current.is(tok::r_brace) &&
         Current.isBlockIndentedInitRBrace(Style)))) {
     return true;
@@ -805,6 +809,13 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState 
&State, bool DryRun,
     CurrentState.NoLineBreak = true;
   }
 
+  // If this is the first element of an array initializer that needs to have
+  // it's columns aligned, do not allow any further elements to break the line.
+  // If we need to break the line for some reason, then this token must be
+  // placed on its own line as well, and the current state should be discarded.
+  if (Previous.opensAlignedArrayInitializer(Style) && Style.ColumnLimit > 0)
+    CurrentState.NoLineBreak = true;
+
   if (Current.is(TT_SelectorName) && !CurrentState.ObjCSelectorNameFound) {
     unsigned MinIndent = std::max(
         State.FirstIndent + Style.ContinuationIndentWidth, 
CurrentState.Indent);
@@ -1959,12 +1970,35 @@ void 
ContinuationIndenter::moveStatePastScopeOpener(LineState &State,
       NewIndent = CurrentState.LastSpace + Style.ContinuationIndentWidth;
     }
     const FormatToken *NextNonComment = Current.getNextNonComment();
-    AvoidBinPacking = EndsInComma || Current.is(TT_DictLiteral) ||
-                      Style.isProto() || !Style.BinPackArguments ||
-                      (NextNonComment && NextNonComment->isOneOf(
-                                             TT_DesignatedInitializerPeriod,
-                                             TT_DesignatedInitializerLSquare));
+
+    bool AlignedArrayInitializer = Current.opensAlignedArrayInitializer(Style);
+
+    AvoidBinPacking =
+        EndsInComma || Current.is(TT_DictLiteral) || Style.isProto() ||
+        !Style.BinPackArguments ||
+        (NextNonComment &&
+         NextNonComment->isOneOf(TT_DesignatedInitializerPeriod,
+                                 TT_DesignatedInitializerLSquare)) ||
+        (Style.AlignArrayOfStructures != FormatStyle::AIAS_None &&
+         State.Line->Type == LineType::LT_ArrayOfStructInitializer) ||
+        AlignedArrayInitializer;
+
     BreakBeforeParameter = EndsInComma;
+
+    // If this is an array initializer that will have it's columns aligned, and
+    // the value is too long to fit on a line, we break before each parameter
+    // because trying to align columns across multiple lines has too many 
corner
+    // cases to do properly. This way, either we align columns all on the same
+    // line, or we don't align columns at all because they are all on their own
+    // line.
+    if (AlignedArrayInitializer && Style.ColumnLimit) {
+      const unsigned LengthToMatchingParen =
+          getLengthToMatchingParen(Current, State.Stack) + State.Column;
+
+      if (LengthToMatchingParen > getColumnLimit(State))
+        BreakBeforeParameter = true;
+    }
+
     if (Current.ParameterCount > 1)
       NestedBlockIndent = std::max(NestedBlockIndent, State.Column + 1);
   } else {
diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp
index 0d8ae1c4a77eb..54b7cbd4c85e1 100644
--- a/clang/lib/Format/FormatToken.cpp
+++ b/clang/lib/Format/FormatToken.cpp
@@ -79,6 +79,16 @@ bool FormatToken::opensBlockOrBlockTypeList(const 
FormatStyle &Style) const {
          (is(tok::less) && Style.isProto());
 }
 
+bool FormatToken::opensAlignedArrayInitializer(const FormatStyle &Style) const 
{
+  if (isNot(tok::l_brace) ||
+      Style.AlignArrayOfStructures == FormatStyle::AIAS_None) {
+    return false;
+  }
+
+  const FormatToken *Next = getNextNonComment();
+  return Next != nullptr && Next->StartsColumn;
+}
+
 TokenRole::~TokenRole() {}
 
 void TokenRole::precomputeFormattingInfos(const FormatToken *Token) {}
diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
index 9252a795a0b5e..c54aac64b3b65 100644
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -580,9 +580,6 @@ struct FormatToken {
   /// The first token in set of column elements.
   bool StartsColumn = false;
 
-  /// This notes the start of the line of an array initializer.
-  bool ArrayInitializerLineStart = false;
-
   /// This starts an array initializer.
   bool IsArrayInitializer = false;
 
@@ -859,6 +856,11 @@ struct FormatToken {
   /// list that should be indented with a block indent.
   [[nodiscard]] bool opensBlockOrBlockTypeList(const FormatStyle &Style) const;
 
+  /// Returns \c true if this tokens starts an array initializer that needs to
+  /// have it's elements be aligned
+  [[nodiscard]] bool
+  opensAlignedArrayInitializer(const FormatStyle &Style) const;
+
   /// Returns whether the token is the left square bracket of a C++
   /// structured binding declaration.
   bool isCppStructuredBinding(bool IsCpp) const {
@@ -879,6 +881,11 @@ struct FormatToken {
     return MatchingParen && MatchingParen->opensBlockOrBlockTypeList(Style);
   }
 
+  /// Same as opensAlignedArrayInitializer, but for the closing token.
+  bool closesAlignedArrayInitializer(const FormatStyle &Style) const {
+    return MatchingParen && MatchingParen->opensAlignedArrayInitializer(Style);
+  }
+
   /// Return the actual namespace token, if this token starts a namespace
   /// block.
   const FormatToken *getNamespaceToken() const {
diff --git a/clang/lib/Format/TokenAnnotator.cpp 
b/clang/lib/Format/TokenAnnotator.cpp
index 4801d27b1395a..3135aa0d22660 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -4227,13 +4227,17 @@ void 
TokenAnnotator::calculateArrayInitializerColumnList(
   if (Line.First == Line.Last)
     return;
   auto *CurrentToken = Line.First;
-  CurrentToken->ArrayInitializerLineStart = true;
   unsigned Depth = 0;
   while (CurrentToken && CurrentToken != Line.Last) {
     if (CurrentToken->is(tok::l_brace)) {
       CurrentToken->IsArrayInitializer = true;
       if (CurrentToken->Next)
         CurrentToken->Next->MustBreakBefore = true;
+
+      // Ensure the end brace of the outer array is on its own line
+      if (CurrentToken->MatchingParen)
+        CurrentToken->MatchingParen->MustBreakBefore = true;
+
       CurrentToken =
           calculateInitializerColumnList(Line, CurrentToken->Next, Depth + 1);
     } else {
@@ -4249,11 +4253,40 @@ FormatToken 
*TokenAnnotator::calculateInitializerColumnList(
       ++Depth;
     else if (CurrentToken->is(tok::r_brace))
       --Depth;
+
+    // Ensure each outer array element starts on its own line
+    if (Depth == 1 && CurrentToken->is(tok::comma)) {
+      auto *NextNonComment = CurrentToken->getNextNonComment();
+      if (NextNonComment)
+        NextNonComment->MustBreakBefore = true;
+    }
+
     if (Depth == 2 && CurrentToken->isOneOf(tok::l_brace, tok::comma)) {
       CurrentToken = CurrentToken->Next;
       if (!CurrentToken)
         break;
-      CurrentToken->StartsColumn = true;
+
+      // Right (closing) braces should not count as starting a column because
+      // they are aligned using separate logic.
+
+      // Note: This uses startsSequence() so that trailing comments are skipped
+      // when checking if the token after a comma/l-brace is a r_brace. We 
can't
+      // just ignore comments in general, because an inline comment with
+      // something else after it should still count as starting a column.
+      // IE:
+      //
+      //        { // a
+      //          4
+      //        }
+      //
+      //   vs.
+      //
+      //        { /* a */ 4 }
+      //
+      // In the first case, the comment does not start a column, but in the
+      // second it does.
+      CurrentToken->StartsColumn = !CurrentToken->startsSequence(tok::r_brace);
+
       CurrentToken = CurrentToken->Previous;
     }
     CurrentToken = CurrentToken->Next;
@@ -6199,7 +6232,8 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine 
&Line,
   // block-indented initialization list.
   if (Right.is(tok::r_brace)) {
     return Right.MatchingParen && (Right.MatchingParen->is(BK_Block) ||
-                                   (Right.isBlockIndentedInitRBrace(Style)));
+                                   Right.isBlockIndentedInitRBrace(Style) ||
+                                   Right.closesAlignedArrayInitializer(Style));
   }
 
   // We only break before r_paren if we're in a block indented context.
diff --git a/clang/lib/Format/WhitespaceManager.cpp 
b/clang/lib/Format/WhitespaceManager.cpp
index cc3cc0f6906cc..da0615a7325cf 100644
--- a/clang/lib/Format/WhitespaceManager.cpp
+++ b/clang/lib/Format/WhitespaceManager.cpp
@@ -31,19 +31,18 @@ bool WhitespaceManager::Change::IsBeforeInFile::operator()(
               C2.OriginalWhitespaceRange.getEnd()));
 }
 
-WhitespaceManager::Change::Change(const FormatToken &Tok,
-                                  bool CreateReplacement,
-                                  SourceRange OriginalWhitespaceRange,
-                                  int Spaces, unsigned StartOfTokenColumn,
-                                  unsigned NewlinesBefore,
-                                  StringRef PreviousLinePostfix,
-                                  StringRef CurrentLinePrefix, bool IsAligned,
-                                  bool ContinuesPPDirective, bool 
IsInsideToken)
+WhitespaceManager::Change::Change(
+    const FormatToken &Tok, bool CreateReplacement,
+    SourceRange OriginalWhitespaceRange, int Spaces,
+    unsigned StartOfTokenColumn, unsigned NewlinesBefore,
+    StringRef PreviousLinePostfix, StringRef CurrentLinePrefix,
+    bool IsIndentationAligned, bool ContinuesPPDirective, bool IsInsideToken)
     : Tok(&Tok), CreateReplacement(CreateReplacement),
       OriginalWhitespaceRange(OriginalWhitespaceRange),
       StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
       PreviousLinePostfix(PreviousLinePostfix),
-      CurrentLinePrefix(CurrentLinePrefix), IsAligned(IsAligned),
+      CurrentLinePrefix(CurrentLinePrefix),
+      IsIndentationAligned(IsIndentationAligned), IsWhitespaceAligned(false),
       ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces),
       IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0),
       PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
@@ -53,13 +52,14 @@ WhitespaceManager::Change::Change(const FormatToken &Tok,
 void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
                                           unsigned Spaces,
                                           unsigned StartOfTokenColumn,
-                                          bool IsAligned, bool InPPDirective) {
+                                          bool IsIndentationAligned,
+                                          bool InPPDirective) {
   if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg))
     return;
   Tok.setDecision((Newlines > 0) ? FD_Break : FD_Continue);
   Changes.push_back(Change(Tok, /*CreateReplacement=*/true, 
Tok.WhitespaceRange,
                            Spaces, StartOfTokenColumn, Newlines, "", "",
-                           IsAligned, InPPDirective && !Tok.IsFirst,
+                           IsIndentationAligned, InPPDirective && !Tok.IsFirst,
                            /*IsInsideToken=*/false));
 }
 
@@ -67,11 +67,11 @@ void WhitespaceManager::addUntouchableToken(const 
FormatToken &Tok,
                                             bool InPPDirective) {
   if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg))
     return;
-  Changes.push_back(Change(Tok, /*CreateReplacement=*/false,
-                           Tok.WhitespaceRange, /*Spaces=*/0,
-                           Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
-                           /*IsAligned=*/false, InPPDirective && !Tok.IsFirst,
-                           /*IsInsideToken=*/false));
+  Changes.push_back(
+      Change(Tok, /*CreateReplacement=*/false, Tok.WhitespaceRange,
+             /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
+             /*IsIndentationAligned=*/false, InPPDirective && !Tok.IsFirst,
+             /*IsInsideToken=*/false));
 }
 
 llvm::Error
@@ -96,7 +96,7 @@ void WhitespaceManager::replaceWhitespaceInToken(
       Change(Tok, /*CreateReplacement=*/true,
              SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces,
              std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,
-             /*IsAligned=*/true, InPPDirective && !Tok.IsFirst,
+             /*IsIndentationAligned=*/true, InPPDirective && !Tok.IsFirst,
              /*IsInsideToken=*/true));
 }
 
@@ -118,9 +118,9 @@ const tooling::Replacements 
&WhitespaceManager::generateReplacements() {
     alignConsecutiveTableGenDefinitions();
   }
   alignChainedConditionals();
+  alignArrayInitializers();
   alignTrailingComments();
   alignEscapedNewlines();
-  alignArrayInitializers();
   generateChanges();
 
   return Replaces;
@@ -278,6 +278,33 @@ void WhitespaceManager::calculateLineBreakInformation() {
   }
 }
 
+// Sets the spaces in front of a Change, and updates the start/end columns of
+// subsequent tokens so that trailing comments and escaped newlines can be
+// aligned properly
+static void
+SetChangeSpaces(unsigned Start, unsigned Spaces,
+                SmallVector<WhitespaceManager::Change, 16> &Changes) {
+  WhitespaceManager::Change &FirstChange = Changes[Start];
+  const int ColumnChange = Spaces - FirstChange.Spaces;
+
+  if (ColumnChange == 0)
+    return;
+
+  FirstChange.Spaces += ColumnChange;
+  FirstChange.StartOfTokenColumn += ColumnChange;
+
+  for (unsigned i = Start + 1; i < Changes.size(); i++) {
+    WhitespaceManager::Change &C = Changes[i];
+
+    C.PreviousEndOfTokenColumn += ColumnChange;
+
+    if (C.NewlinesBefore > 0)
+      break;
+
+    C.StartOfTokenColumn += ColumnChange;
+  }
+}
+
 // Align a single sequence of tokens, see AlignTokens below.
 // Column - The token for which Matches returns true is moved to this column.
 // RightJustify - Whether it is the token's right end or left end that gets
@@ -350,13 +377,15 @@ AlignTokenSequence(const FormatStyle &Style, unsigned 
Start, unsigned End,
       FoundMatchOnLine = true;
       Shift = Column - (RightJustify ? CurrentChange.TokenLength : 0) -
               CurrentChange.StartOfTokenColumn;
-      CurrentChange.Spaces += Shift;
+      SetChangeSpaces(i, CurrentChange.Spaces + Shift, Changes);
       // FIXME: This is a workaround that should be removed when we fix
       // http://llvm.org/PR53699. An assertion later below verifies this.
       if (CurrentChange.NewlinesBefore == 0) {
-        CurrentChange.Spaces =
+        SetChangeSpaces(
+            i,
             std::max(CurrentChange.Spaces,
-                     
static_cast<int>(CurrentChange.Tok->SpacesRequiredBefore));
+                     
static_cast<int>(CurrentChange.Tok->SpacesRequiredBefore)),
+            Changes);
       }
     }
 
@@ -449,11 +478,11 @@ AlignTokenSequence(const FormatStyle &Style, unsigned 
Start, unsigned End,
       };
 
       if (ShouldShiftBeAdded())
-        CurrentChange.Spaces += Shift;
+        SetChangeSpaces(i, CurrentChange.Spaces + Shift, Changes);
     }
 
     if (ContinuedStringLiteral)
-      CurrentChange.Spaces += Shift;
+      SetChangeSpaces(i, CurrentChange.Spaces + Shift, Changes);
 
     // We should not remove required spaces unless we break the line before.
     assert(Shift > 0 || Changes[i].NewlinesBefore > 0 ||
@@ -461,10 +490,6 @@ AlignTokenSequence(const FormatStyle &Style, unsigned 
Start, unsigned End,
                static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) ||
            CurrentChange.Tok->is(tok::eof));
 
-    CurrentChange.StartOfTokenColumn += Shift;
-    if (i + 1 != Changes.size())
-      Changes[i + 1].PreviousEndOfTokenColumn += Shift;
-
     // If PointerAlignment is PAS_Right, keep *s or &s next to the token,
     // except if the token is equal, then a space is needed.
     if ((Style.PointerAlignment == FormatStyle::PAS_Right ||
@@ -485,9 +510,9 @@ AlignTokenSequence(const FormatStyle &Style, unsigned 
Start, unsigned End,
         } else if (Style.PointerAlignment != FormatStyle::PAS_Right) {
           continue;
         }
-        Changes[Previous + 1].Spaces -= Shift;
-        Changes[Previous].Spaces += Shift;
-        Changes[Previous].StartOfTokenColumn += Shift;
+        SetChangeSpaces(Previous + 1, Changes[Previous + 1].Spaces - Shift,
+                        Changes);
+        SetChangeSpaces(Previous, Changes[Previous].Spaces + Shift, Changes);
       }
     }
   }
@@ -1318,175 +1343,188 @@ void 
WhitespaceManager::alignArrayInitializers(unsigned Start, unsigned End) {
 
 void WhitespaceManager::alignArrayInitializersRightJustified(
     CellDescriptions &&CellDescs) {
-  if (!CellDescs.isRectangular())
+
+  // If there are less than two rows, there is nothing to align.
+  if (CellDescs.Rows.size() < 2)
+    return;
+
+  // If there are less than 2 columns, there is nothing to align.
+  const int ColumnCount = CellDescs.ColumnStartingCellIndices.size();
+  if (ColumnCount < 2)
     return;
 
   const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1;
+  auto &ColumnStartingIndices = CellDescs.ColumnStartingCellIndices;
   auto &Cells = CellDescs.Cells;
-  // Now go through and fixup the spaces.
-  auto *CellIter = Cells.begin();
-  for (auto i = 0U; i < CellDescs.CellCounts[0]; ++i, ++CellIter) {
-    unsigned NetWidth = 0U;
-    if (isSplitCell(*CellIter))
-      NetWidth = getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
-    auto CellWidth = getMaximumCellWidth(CellIter, NetWidth);
-
-    if (Changes[CellIter->Index].Tok->is(tok::r_brace)) {
-      // So in here we want to see if there is a brace that falls
-      // on a line that was split. If so on that line we make sure that
-      // the spaces in front of the brace are enough.
-      const auto *Next = CellIter;
-      do {
-        const FormatToken *Previous = Changes[Next->Index].Tok->Previous;
-        if (Previous && Previous->isNot(TT_LineComment)) {
-          Changes[Next->Index].Spaces = BracePadding;
-          Changes[Next->Index].NewlinesBefore = 0;
-        }
-        Next = Next->NextColumnElement;
-      } while (Next);
-      // Unless the array is empty, we need the position of all the
-      // immediately adjacent cells
-      if (CellIter != Cells.begin()) {
-        auto ThisNetWidth =
-            getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
-        auto MaxNetWidth = getMaximumNetWidth(
-            Cells.begin(), CellIter, CellDescs.InitialSpaces,
-            CellDescs.CellCounts[0], CellDescs.CellCounts.size());
-        if (ThisNetWidth < MaxNetWidth)
-          Changes[CellIter->Index].Spaces = (MaxNetWidth - ThisNetWidth);
-        auto RowCount = 1U;
-        auto Offset = std::distance(Cells.begin(), CellIter);
-        for (const auto *Next = CellIter->NextColumnElement; Next;
-             Next = Next->NextColumnElement) {
-          if (RowCount >= CellDescs.CellCounts.size())
-            break;
-          auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]);
-          auto *End = Start + Offset;
-          ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces);
-          if (ThisNetWidth < MaxNetWidth)
-            Changes[Next->Index].Spaces = (MaxNetWidth - ThisNetWidth);
-          ++RowCount;
-        }
-      }
-    } else {
-      auto ThisWidth =
-          calculateCellWidth(CellIter->Index, CellIter->EndIndex, true) +
-          NetWidth;
-      if (Changes[CellIter->Index].NewlinesBefore == 0) {
-        Changes[CellIter->Index].Spaces = (CellWidth - (ThisWidth + NetWidth));
-        Changes[CellIter->Index].Spaces += (i > 0) ? 1 : BracePadding;
-      }
-      alignToStartOfCell(CellIter->Index, CellIter->EndIndex);
-      for (const auto *Next = CellIter->NextColumnElement; Next;
-           Next = Next->NextColumnElement) {
-        ThisWidth =
-            calculateCellWidth(Next->Index, Next->EndIndex, true) + NetWidth;
-        if (Changes[Next->Index].NewlinesBefore == 0) {
-          Changes[Next->Index].Spaces = (CellWidth - ThisWidth);
-          Changes[Next->Index].Spaces += (i > 0) ? 1 : BracePadding;
-        }
-        alignToStartOfCell(Next->Index, Next->EndIndex);
-      }
+
+  // Calculate column widths.
+  SmallVector<unsigned> ColumnWidths;       // Widths from the previous column
+  SmallVector<unsigned> SummedColumnWidths; // Widths from the start of the row
+
+  unsigned CurrentWidth = 0;
+  for (unsigned CellIndex : ColumnStartingIndices) {
+    const CellDescription *current = &Cells[CellIndex];
+
+    unsigned MaxWidth = 0;
+    while (current != nullptr) {
+      unsigned CellWidth = calculateCellWidth(*current);
+
+      // +1 for the space after the comma in the previous column in all but
+      // the first column which has brace padding from the opening
+      // brace instead.
+      CellWidth += (current->Cell > 0) ? 1 : BracePadding;
+
+      MaxWidth = std::max(MaxWidth, CellWidth);
+      current = current->NextColumnElement;
     }
+
+    ColumnWidths.push_back(MaxWidth);
+
+    CurrentWidth += MaxWidth;
+    SummedColumnWidths.push_back(CurrentWidth);
+
+    // +1 for the comma between cells.
+    CurrentWidth++;
+  }
+
+  // Fixup spaces.
+  for (RowDescription &Row : CellDescs.Rows) {
+    unsigned WidthSoFarInRow = 0;
+    for (unsigned i = Row.StartCellIndex; i < Row.EndCellIndex; i++) {
+      const CellDescription &Cell = Cells[i];
+
+      const unsigned CellWidth = calculateCellWidth(Cell);
+      const unsigned AlignmentSpaces = ColumnWidths[Cell.Cell] - CellWidth;
+      setChangeSpaces(Cell.Index, AlignmentSpaces);
+      Changes[Cell.Index].IsWhitespaceAligned = true;
+
+      WidthSoFarInRow = SummedColumnWidths[Cell.Cell];
+
+      // +1 for the comma after columns in all but the last column
+      // Note: this can't check Cell.Cell because a row may not have a full
+      // set of columns.
+      if (i < Row.EndCellIndex - 1)
+        WidthSoFarInRow++;
+    }
+
+    // Align the end brace.
+    const unsigned AlignmentSpaces =
+        (SummedColumnWidths.back() - WidthSoFarInRow) + BracePadding;
+    setChangeSpaces(Row.ClosingBraceChangeIndex, AlignmentSpaces);
+    Changes[Row.ClosingBraceChangeIndex].IsWhitespaceAligned = true;
   }
 }
 
 void WhitespaceManager::alignArrayInitializersLeftJustified(
     CellDescriptions &&CellDescs) {
 
-  if (!CellDescs.isRectangular())
+  // If there are less than two rows, there is nothing to align.
+  if (CellDescs.Rows.size() < 2)
+    return;
+
+  // If there are less than 2 columns, there is nothing to align.
+  const unsigned ColumnCount = CellDescs.ColumnStartingCellIndices.size();
+  if (ColumnCount < 2)
     return;
 
+  const unsigned LastColumnIndex = ColumnCount - 1;
   const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1;
-  auto &Cells = CellDescs.Cells;
-  // Now go through and fixup the spaces.
-  auto *CellIter = Cells.begin();
-  // The first cell of every row needs to be against the left brace.
-  for (const auto *Next = CellIter; Next; Next = Next->NextColumnElement) {
-    auto &Change = Changes[Next->Index];
-    Change.Spaces =
-        Change.NewlinesBefore == 0 ? BracePadding : CellDescs.InitialSpaces;
-  }
-  ++CellIter;
-  for (auto i = 1U; i < CellDescs.CellCounts[0]; i++, ++CellIter) {
-    auto MaxNetWidth = getMaximumNetWidth(
-        Cells.begin(), CellIter, CellDescs.InitialSpaces,
-        CellDescs.CellCounts[0], CellDescs.CellCounts.size());
-    auto ThisNetWidth =
-        getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
-    if (Changes[CellIter->Index].NewlinesBefore == 0) {
-      Changes[CellIter->Index].Spaces =
-          MaxNetWidth - ThisNetWidth +
-          (Changes[CellIter->Index].Tok->isNot(tok::r_brace) ? 1
-                                                             : BracePadding);
-    }
-    auto RowCount = 1U;
-    auto Offset = std::distance(Cells.begin(), CellIter);
-    for (const auto *Next = CellIter->NextColumnElement; Next;
-         Next = Next->NextColumnElement) {
-      if (RowCount >= CellDescs.CellCounts.size())
-        break;
-      auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]);
-      auto *End = Start + Offset;
-      auto ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces);
-      if (Changes[Next->Index].NewlinesBefore == 0) {
-        Changes[Next->Index].Spaces =
-            MaxNetWidth - ThisNetWidth +
-            (Changes[Next->Index].Tok->isNot(tok::r_brace) ? 1 : BracePadding);
-      }
-      ++RowCount;
+  const auto &ColumnStartingIndices = CellDescs.ColumnStartingCellIndices;
+  const auto &Cells = CellDescs.Cells;
+
+  // Calculate column starting widths.
+  SmallVector<unsigned> StartWidths;
+
+  // The first column starts after the opening brace's padding.
+  StartWidths.push_back(BracePadding);
+
+  for (unsigned i = 0; i < ColumnCount; i++) {
+    const CellDescription *current = &Cells[ColumnStartingIndices[i]];
+
+    unsigned MaxWidth = 0;
+    while (current != nullptr) {
+      // calculateCellWidth returns relative column count from the previous
+      // cell, but we want it relative to the opening brace so we add
+      // starting width for this cell.
+      unsigned CellWidth = calculateCellWidth(*current) + StartWidths[i];
+
+      // +1 for the comma after the cell if it exists.
+      if (Changes[current->EndIndex].Tok->is(tok::comma))
+        CellWidth++;
+
+      // +1 for the space after the column if this is not the last column.
+      if (i < LastColumnIndex)
+        CellWidth++;
+
+      MaxWidth = std::max(MaxWidth, CellWidth);
+      current = current->NextColumnElement;
     }
+
+    // If this is the last column, add the brace padding to the width so that
+    // the end brace gets the necessary padding.
+    if (i == LastColumnIndex)
+      MaxWidth += BracePadding;
+
+    StartWidths.push_back(MaxWidth);
   }
-}
 
-bool WhitespaceManager::isSplitCell(const CellDescription &Cell) {
-  if (Cell.HasSplit)
-    return true;
-  for (const auto *Next = Cell.NextColumnElement; Next;
-       Next = Next->NextColumnElement) {
-    if (Next->HasSplit)
-      return true;
+  // Fixup spaces.
+  for (RowDescription &Row : CellDescs.Rows) {
+    unsigned WidthSoFarInRow = 0;
+
+    for (unsigned i = Row.StartCellIndex; i < Row.EndCellIndex; i++) {
+      const CellDescription &Cell = Cells[i];
+
+      Change &Change = Changes[Cell.Index];
+      const unsigned AlignmentSpaces = StartWidths[Cell.Cell] - 
WidthSoFarInRow;
+      setChangeSpaces(Cell.Index, AlignmentSpaces);
+      Change.IsWhitespaceAligned = true;
+
+      WidthSoFarInRow += calculateCellWidth(Cell) + Change.Spaces;
+
+      // +1 for the comma after columns in all but the last column
+      // Note: this can't check Cell.Cell because a row may not have a full
+      // set of columns.
+      if (i < Row.EndCellIndex - 1)
+        WidthSoFarInRow += 1;
+    }
+
+    // Align the end brace.
+    const unsigned AlignmentSpaces = StartWidths.back() - WidthSoFarInRow;
+    setChangeSpaces(Row.ClosingBraceChangeIndex, AlignmentSpaces);
+    Changes[Row.ClosingBraceChangeIndex].IsWhitespaceAligned = true;
   }
-  return false;
 }
 
 WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start,
                                                                 unsigned End) {
-
   unsigned Depth = 0;
   unsigned Cell = 0;
-  SmallVector<unsigned> CellCounts;
-  unsigned InitialSpaces = 0;
-  unsigned InitialTokenLength = 0;
-  unsigned EndSpaces = 0;
   SmallVector<CellDescription> Cells;
+  SmallVector<RowDescription> Rows;
+  SmallVector<unsigned> StartingCellIndices;
   const FormatToken *MatchingParen = nullptr;
+  RowDescription CurrentRow;
+  bool SkipCurrentRow = false;
   for (unsigned i = Start; i < End; ++i) {
     auto &C = Changes[i];
+
     if (C.Tok->is(tok::l_brace))
       ++Depth;
     else if (C.Tok->is(tok::r_brace))
       --Depth;
+
     if (Depth == 2) {
       if (C.Tok->is(tok::l_brace)) {
         Cell = 0;
+        SkipCurrentRow = false;
+        CurrentRow = RowDescription{unsigned(Cells.size()), 0, 0,
+                                    C.StartOfTokenColumn + C.TokenLength};
         MatchingParen = C.Tok->MatchingParen;
-        if (InitialSpaces == 0) {
-          InitialSpaces = C.Spaces + C.TokenLength;
-          InitialTokenLength = C.TokenLength;
-          auto j = i - 1;
-          for (; Changes[j].NewlinesBefore == 0 && j > Start; --j) {
-            InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength;
-            InitialTokenLength += Changes[j].TokenLength;
-          }
-          if (C.NewlinesBefore == 0) {
-            InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength;
-            InitialTokenLength += Changes[j].TokenLength;
-          }
-        }
       } else if (C.Tok->is(tok::comma)) {
         if (!Cells.empty())
           Cells.back().EndIndex = i;
+
         if (const auto *Next = C.Tok->getNextNonComment();
             Next && Next->isNot(tok::r_brace)) { // dangling comma
           ++Cell;
@@ -1494,105 +1532,64 @@ WhitespaceManager::CellDescriptions 
WhitespaceManager::getCells(unsigned Start,
       }
     } else if (Depth == 1) {
       if (C.Tok == MatchingParen) {
-        if (!Cells.empty())
-          Cells.back().EndIndex = i;
-        Cells.push_back(CellDescription{i, ++Cell, i + 1, false, nullptr});
-        CellCounts.push_back(C.Tok->Previous->isNot(tok::comma) ? Cell + 1
-                                                                : Cell);
-        // Go to the next non-comment and ensure there is a break in front
-        const auto *NextNonComment = C.Tok->getNextNonComment();
-        while (NextNonComment && NextNonComment->is(tok::comma))
-          NextNonComment = NextNonComment->getNextNonComment();
-        auto j = i;
-        while (j < End && Changes[j].Tok != NextNonComment)
-          ++j;
-        if (j < End && Changes[j].NewlinesBefore == 0 &&
-            Changes[j].Tok->isNot(tok::r_brace)) {
-          Changes[j].NewlinesBefore = 1;
-          // Account for the added token lengths
-          Changes[j].Spaces = InitialSpaces - InitialTokenLength;
+        // Rows with trailing commas are not aligned because they have each 
cell
+        // on a separate line
+        if (C.Tok->getPreviousNonComment()->is(tok::comma))
+          SkipCurrentRow = true;
+
+        if (SkipCurrentRow) {
+          // If we are skipping this row, we also need to remove the cells. We
+          // may have added cells before we found out the row needed to be
+          // skipped, so we just remove them at the end of the row for
+          // simplicity.
+          Cells.pop_back_n(Cells.size() - CurrentRow.StartCellIndex);
+        } else {
+          CurrentRow.ClosingBraceChangeIndex = i;
+          CurrentRow.EndCellIndex = Cells.size();
+          Rows.push_back(CurrentRow);
+
+          // If this is an empty row, just push back the cell.
+          if (Cell == 0) {
+            Cells.push_back(CellDescription{i, Cell, i + 1, nullptr});
+          } else {
+            if (!Cells.empty())
+              Cells.back().EndIndex = i;
+            Cells.push_back(CellDescription{i, ++Cell, i + 1, nullptr});
+          }
         }
-      } else if (C.Tok->is(tok::comment) && C.Tok->NewlinesBefore == 0) {
-        // Trailing comments stay at a space past the last token
-        C.Spaces = Changes[i - 1].Tok->is(tok::comma) ? 1 : 2;
-      } else if (C.Tok->is(tok::l_brace)) {
-        // We need to make sure that the ending braces is aligned to the
-        // start of our initializer
-        auto j = i - 1;
-        for (; j > 0 && !Changes[j].Tok->ArrayInitializerLineStart; --j)
-          ; // Nothing the loop does the work
-        EndSpaces = Changes[j].Spaces;
       }
-    } else if (Depth == 0 && C.Tok->is(tok::r_brace)) {
-      C.NewlinesBefore = 1;
-      C.Spaces = EndSpaces;
     }
+
     if (C.Tok->StartsColumn) {
-      // This gets us past tokens that have been split over multiple
-      // lines
-      bool HasSplit = false;
-      if (Changes[i].NewlinesBefore > 0) {
-        // So if we split a line previously and the tail line + this token is
-        // less then the column limit we remove the split here and just put
-        // the column start at a space past the comma
-        //
-        // FIXME This if branch covers the cases where the column is not
-        // the first column. This leads to weird pathologies like the 
formatting
-        // auto foo = Items{
-        //     Section{
-        //             0, bar(),
-        //     }
-        // };
-        // Well if it doesn't lead to that it's indicative that the line
-        // breaking should be revisited. Unfortunately alot of other options
-        // interact with this
-        auto j = i - 1;
-        if ((j - 1) > Start && Changes[j].Tok->is(tok::comma) &&
-            Changes[j - 1].NewlinesBefore > 0) {
-          --j;
-          auto LineLimit = Changes[j].Spaces + Changes[j].TokenLength;
-          if (LineLimit < Style.ColumnLimit) {
-            Changes[i].NewlinesBefore = 0;
-            Changes[i].Spaces = 1;
-          }
-        }
-      }
-      while (Changes[i].NewlinesBefore > 0 && Changes[i].Tok == C.Tok) {
-        Changes[i].Spaces = InitialSpaces;
-        ++i;
-        HasSplit = true;
+      if (C.NewlinesBefore > 0) {
+        SkipCurrentRow = true;
+      } else {
+        if (Cell >= StartingCellIndices.size())
+          StartingCellIndices.push_back(Cells.size());
+
+        Cells.push_back(CellDescription{i, Cell, i, nullptr});
       }
-      if (Changes[i].Tok != C.Tok)
-        --i;
-      Cells.push_back(CellDescription{i, Cell, i, HasSplit, nullptr});
     }
   }
 
-  return linkCells({Cells, CellCounts, InitialSpaces});
+  return linkCells({Cells, Rows, StartingCellIndices});
 }
 
-unsigned WhitespaceManager::calculateCellWidth(unsigned Start, unsigned End,
-                                               bool WithSpaces) const {
+unsigned
+WhitespaceManager::calculateCellWidth(const CellDescription &Cell) const {
   unsigned CellWidth = 0;
-  for (auto i = Start; i < End; i++) {
+  for (auto i = Cell.Index; i < Cell.EndIndex; i++) {
     if (Changes[i].NewlinesBefore > 0)
       CellWidth = 0;
+
+    if (CellWidth != 0)
+      CellWidth += Changes[i].Spaces;
+
     CellWidth += Changes[i].TokenLength;
-    CellWidth += (WithSpaces ? Changes[i].Spaces : 0);
   }
   return CellWidth;
 }
 
-void WhitespaceManager::alignToStartOfCell(unsigned Start, unsigned End) {
-  if ((End - Start) <= 1)
-    return;
-  // If the line is broken anywhere in there make sure everything
-  // is aligned to the parent
-  for (auto i = Start + 1; i < End; i++)
-    if (Changes[i].NewlinesBefore > 0)
-      Changes[i].Spaces = Changes[Start].Spaces;
-}
-
 WhitespaceManager::CellDescriptions
 WhitespaceManager::linkCells(CellDescriptions &&CellDesc) {
   auto &Cells = CellDesc.Cells;
@@ -1609,6 +1606,10 @@ WhitespaceManager::linkCells(CellDescriptions 
&&CellDesc) {
   return std::move(CellDesc);
 }
 
+void WhitespaceManager::setChangeSpaces(unsigned Start, unsigned Spaces) {
+  SetChangeSpaces(Start, Spaces, Changes);
+}
+
 void WhitespaceManager::generateChanges() {
   for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
     const Change &C = Changes[i];
@@ -1617,37 +1618,39 @@ void WhitespaceManager::generateChanges() {
       auto New = Changes[i].OriginalWhitespaceRange;
       // Do not generate two replacements for the same location.  As a special
       // case, it is allowed if there is a replacement for the empty range
-      // between 2 tokens and another non-empty range at the start of the 
second
-      // token.  We didn't implement logic to combine replacements for 2
-      // consecutive source ranges into a single replacement, because the
+      // between 2 tokens and another non-empty range at the start of the
+      // second token.  We didn't implement logic to combine replacements for
+      // 2 consecutive source ranges into a single replacement, because the
       // program works fine without it.
       //
-      // We can't eliminate empty original whitespace ranges.  They appear when
-      // 2 tokens have no whitespace in between in the input.  It does not
-      // matter whether whitespace is to be added.  If no whitespace is to be
-      // added, the replacement will be empty, and it gets eliminated after 
this
-      // step in storeReplacement.  For example, if the input is `foo();`,
-      // there will be a replacement for the range between every consecutive
-      // pair of tokens.
+      // We can't eliminate empty original whitespace ranges.  They appear
+      // when 2 tokens have no whitespace in between in the input.  It does
+      // not matter whether whitespace is to be added.  If no whitespace is to
+      // be added, the replacement will be empty, and it gets eliminated after
+      // this step in storeReplacement.  For example, if the input is
+      // `foo();`, there will be a replacement for the range between every
+      // consecutive pair of tokens.
       //
       // A replacement at the start of a token can be added by
       // BreakableStringLiteralUsingOperators::insertBreak when it adds braces
-      // around the string literal.  Say Verilog code is being formatted and 
the
-      // first line is to become the next 2 lines.
+      // around the string literal.  Say Verilog code is being formatted and
+      // the first line is to become the next 2 lines.
       //     x("long string");
       //     x({"long ",
       //        "string"});
-      // There will be a replacement for the empty range between the 
parenthesis
-      // and the string and another replacement for the quote character.  The
-      // replacement for the empty range between the parenthesis and the quote
-      // comes from ContinuationIndenter::addTokenOnCurrentLine when it changes
-      // the original empty range between the parenthesis and the string to
-      // another empty one.  The replacement for the quote character comes from
-      // BreakableStringLiteralUsingOperators::insertBreak when it adds the
-      // brace.  In the example, the replacement for the empty range is the 
same
-      // as the original text.  However, eliminating replacements that are same
-      // as the original does not help in general.  For example, a newline can
-      // be inserted, causing the first line to become the next 3 lines.
+      // There will be a replacement for the empty range between the
+      // parenthesis and the string and another replacement for the quote
+      // character.  The replacement for the empty range between the
+      // parenthesis and the quote comes from
+      // ContinuationIndenter::addTokenOnCurrentLine when it changes the
+      // original empty range between the parenthesis and the string to
+      // another empty one.  The replacement for the quote character comes
+      // from BreakableStringLiteralUsingOperators::insertBreak when it adds
+      // the brace.  In the example, the replacement for the empty range is
+      // the same as the original text.  However, eliminating replacements
+      // that are same as the original does not help in general.  For example,
+      // a newline can be inserted, causing the first line to become the next
+      // 3 lines.
       //     xxxxxxxxxxx("long string");
       //     xxxxxxxxxxx(
       //         {"long ",
@@ -1676,7 +1679,7 @@ void WhitespaceManager::generateChanges() {
       appendIndentText(
           ReplacementText, C.Tok->IndentLevel, std::max(0, C.Spaces),
           std::max((int)C.StartOfTokenColumn, C.Spaces) - std::max(0, 
C.Spaces),
-          C.IsAligned);
+          C.IsIndentationAligned, C.IsWhitespaceAligned);
       ReplacementText.append(C.CurrentLinePrefix);
       storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
     }
@@ -1732,7 +1735,8 @@ void WhitespaceManager::appendEscapedNewlineText(
 void WhitespaceManager::appendIndentText(std::string &Text,
                                          unsigned IndentLevel, unsigned Spaces,
                                          unsigned WhitespaceStartColumn,
-                                         bool IsAligned) {
+                                         bool IsIndentationAligned,
+                                         bool IsWhitespaceAligned) {
   switch (Style.UseTab) {
   case FormatStyle::UT_Never:
     Text.append(Spaces, ' ');
@@ -1772,8 +1776,10 @@ void WhitespaceManager::appendIndentText(std::string 
&Text,
     break;
   case FormatStyle::UT_AlignWithSpaces:
     if (WhitespaceStartColumn == 0) {
-      unsigned Indentation =
-          IsAligned ? IndentLevel * Style.IndentWidth : Spaces;
+      unsigned Indentation = IsWhitespaceAligned ? 0
+                             : IsIndentationAligned
+                                 ? IndentLevel * Style.IndentWidth
+                                 : Spaces;
       Spaces = appendTabIndent(Text, Spaces, Indentation);
     }
     Text.append(Spaces, ' ');
@@ -1783,8 +1789,8 @@ void WhitespaceManager::appendIndentText(std::string 
&Text,
 
 unsigned WhitespaceManager::appendTabIndent(std::string &Text, unsigned Spaces,
                                             unsigned Indentation) {
-  // This happens, e.g. when a line in a block comment is indented less than 
the
-  // first one.
+  // This happens, e.g. when a line in a block comment is indented less than
+  // the first one.
   if (Indentation > Spaces)
     Indentation = Spaces;
   if (Style.TabWidth) {
diff --git a/clang/lib/Format/WhitespaceManager.h 
b/clang/lib/Format/WhitespaceManager.h
index 6d18db74cd2e4..54b9160e9f24a 100644
--- a/clang/lib/Format/WhitespaceManager.h
+++ b/clang/lib/Format/WhitespaceManager.h
@@ -50,7 +50,8 @@ class WhitespaceManager {
   /// this replacement. It is needed for determining how \p Spaces is turned
   /// into tabs and spaces for some format styles.
   void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces,
-                         unsigned StartOfTokenColumn, bool IsAligned = false,
+                         unsigned StartOfTokenColumn,
+                         bool IsIndentationAligned = false,
                          bool InPPDirective = false);
 
   /// Adds information about an unchangeable token's whitespace.
@@ -110,7 +111,8 @@ class WhitespaceManager {
            SourceRange OriginalWhitespaceRange, int Spaces,
            unsigned StartOfTokenColumn, unsigned NewlinesBefore,
            StringRef PreviousLinePostfix, StringRef CurrentLinePrefix,
-           bool IsAligned, bool ContinuesPPDirective, bool IsInsideToken);
+           bool IsIndentationAligned, bool ContinuesPPDirective,
+           bool IsInsideToken);
 
     // The kind of the token whose whitespace this change replaces, or in which
     // this change inserts whitespace.
@@ -126,7 +128,8 @@ class WhitespaceManager {
     unsigned NewlinesBefore;
     std::string PreviousLinePostfix;
     std::string CurrentLinePrefix;
-    bool IsAligned;
+    bool IsIndentationAligned;
+    bool IsWhitespaceAligned;
     bool ContinuesPPDirective;
 
     // The number of spaces in front of the token or broken part of the token.
@@ -177,7 +180,6 @@ class WhitespaceManager {
     unsigned Index = 0;
     unsigned Cell = 0;
     unsigned EndIndex = 0;
-    bool HasSplit = false;
     CellDescription *NextColumnElement = nullptr;
 
     constexpr bool operator==(const CellDescription &Other) const {
@@ -189,22 +191,17 @@ class WhitespaceManager {
     }
   };
 
+  struct RowDescription {
+    unsigned StartCellIndex = 0;
+    unsigned EndCellIndex = 0;
+    unsigned ClosingBraceChangeIndex = 0;
+    unsigned StartColumn = 0;
+  };
+
   struct CellDescriptions {
     SmallVector<CellDescription> Cells;
-    SmallVector<unsigned> CellCounts;
-    unsigned InitialSpaces = 0;
-
-    // Determine if every row in the array
-    // has the same number of columns.
-    bool isRectangular() const {
-      if (CellCounts.size() < 2)
-        return false;
-
-      for (auto NumberOfColumns : CellCounts)
-        if (NumberOfColumns != CellCounts[0])
-          return false;
-      return true;
-    }
+    SmallVector<RowDescription> Rows;
+    SmallVector<unsigned> ColumnStartingCellIndices;
   };
 
   /// Calculate \c IsTrailingComment, \c TokenLength for the last tokens
@@ -274,76 +271,17 @@ class WhitespaceManager {
   void alignArrayInitializersLeftJustified(CellDescriptions &&CellDescs);
 
   /// Calculate the cell width between two indexes.
-  unsigned calculateCellWidth(unsigned Start, unsigned End,
-                              bool WithSpaces = false) const;
+  unsigned calculateCellWidth(const CellDescription &Cell) const;
 
   /// Get a set of fully specified CellDescriptions between \p Start and
   /// \p End of the change list.
   CellDescriptions getCells(unsigned Start, unsigned End);
 
-  /// Does this \p Cell contain a split element?
-  static bool isSplitCell(const CellDescription &Cell);
-
-  /// Get the width of the preceding cells from \p Start to \p End.
-  template <typename I>
-  auto getNetWidth(const I &Start, const I &End, unsigned InitialSpaces) const 
{
-    auto NetWidth = InitialSpaces;
-    for (auto PrevIter = Start; PrevIter != End; ++PrevIter) {
-      // If we broke the line the initial spaces are already
-      // accounted for.
-      assert(PrevIter->Index < Changes.size());
-      if (Changes[PrevIter->Index].NewlinesBefore > 0)
-        NetWidth = 0;
-      NetWidth +=
-          calculateCellWidth(PrevIter->Index, PrevIter->EndIndex, true) + 1;
-    }
-    return NetWidth;
-  }
-
-  /// Get the maximum width of a cell in a sequence of columns.
-  template <typename I>
-  unsigned getMaximumCellWidth(I CellIter, unsigned NetWidth) const {
-    unsigned CellWidth =
-        calculateCellWidth(CellIter->Index, CellIter->EndIndex, true);
-    if (Changes[CellIter->Index].NewlinesBefore == 0)
-      CellWidth += NetWidth;
-    for (const auto *Next = CellIter->NextColumnElement; Next;
-         Next = Next->NextColumnElement) {
-      auto ThisWidth = calculateCellWidth(Next->Index, Next->EndIndex, true);
-      if (Changes[Next->Index].NewlinesBefore == 0)
-        ThisWidth += NetWidth;
-      CellWidth = std::max(CellWidth, ThisWidth);
-    }
-    return CellWidth;
-  }
-
-  /// Get The maximum width of all columns to a given cell.
-  template <typename I>
-  unsigned getMaximumNetWidth(const I &CellStart, const I &CellStop,
-                              unsigned InitialSpaces, unsigned CellCount,
-                              unsigned MaxRowCount) const {
-    auto MaxNetWidth = getNetWidth(CellStart, CellStop, InitialSpaces);
-    auto RowCount = 1U;
-    auto Offset = std::distance(CellStart, CellStop);
-    for (const auto *Next = CellStop->NextColumnElement; Next;
-         Next = Next->NextColumnElement) {
-      if (RowCount >= MaxRowCount)
-        break;
-      auto Start = (CellStart + RowCount * CellCount);
-      auto End = Start + Offset;
-      MaxNetWidth =
-          std::max(MaxNetWidth, getNetWidth(Start, End, InitialSpaces));
-      ++RowCount;
-    }
-    return MaxNetWidth;
-  }
-
-  /// Align a split cell with a newline to the first element in the cell.
-  void alignToStartOfCell(unsigned Start, unsigned End);
-
   /// Link the Cell pointers in the list of Cells.
   static CellDescriptions linkCells(CellDescriptions &&CellDesc);
 
+  void setChangeSpaces(unsigned Start, unsigned Spaces);
+
   /// Fill \c Replaces with the replacements for all effective changes.
   void generateChanges();
 
@@ -355,7 +293,7 @@ class WhitespaceManager {
                                 unsigned EscapedNewlineColumn);
   void appendIndentText(std::string &Text, unsigned IndentLevel,
                         unsigned Spaces, unsigned WhitespaceStartColumn,
-                        bool IsAligned);
+                        bool IsIndentationAligned, bool IsWhitespaceAligned);
   unsigned appendTabIndent(std::string &Text, unsigned Spaces,
                            unsigned Indentation);
 
diff --git a/clang/unittests/Format/FormatTest.cpp 
b/clang/unittests/Format/FormatTest.cpp
index 96cc650f52a5d..860fcaa783946 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -22043,6 +22043,21 @@ TEST_F(FormatTest, CatchExceptionReferenceBinding) {
 TEST_F(FormatTest, CatchAlignArrayOfStructuresRightAlignment) {
   auto Style = getLLVMStyle();
   Style.AlignArrayOfStructures = FormatStyle::AIAS_Right;
+
+  verifyFormat("auto foo = Items{\n"
+               "    Section{0, barbar()},\n"
+               "    Section{\n"
+               "        1,\n"
+               "        boo(),\n"
+               "    }\n"
+               "};",
+               Style);
+
+  verifyFormat("auto foo = Items{\n"
+               "    Section{0, bar()}\n"
+               "};",
+               Style);
+
   verifyNoCrash("f({\n"
                 "table({}, table({{\"\", false}}, {}))\n"
                 "});",
@@ -22118,11 +22133,14 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresRightAlignment) {
 
   verifyFormat(
       "test demo[] = {\n"
-      "    { 7,    23,\n"
-      "     \"hello world i am a very long line that really, in any\"\n"
-      "     \"just world, ought to be split over multiple lines\"},\n"
-      "    {-1, 93463,                                  \"world\"},\n"
-      "    {56,     5,                                     \"!!\"}\n"
+      "    {\n"
+      "        7,\n"
+      "        23,\n"
+      "        \"hello world i am a very long line that really, in any\"\n"
+      "        \"just world, ought to be split over multiple lines\"\n"
+      "    },\n"
+      "    {-1, 93463, \"world\"},\n"
+      "    {56,     5,    \"!!\"}\n"
       "};",
       Style);
 
@@ -22149,7 +22167,7 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresRightAlignment) {
                "  {\"x\", \"dy\"}},\n"
                "                                {  {\"dx\"},  \"Mul\", {\"dy\""
                ", \"sign\"}},\n"
-               "});",
+               "                            });",
                Style);
 
   Style.Cpp11BracedListStyle = false;
@@ -22163,17 +22181,16 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresRightAlignment) {
 
   Style.ColumnLimit = 0;
   verifyFormat(
-      "test demo[] = {\n"
-      "    {56,    23, \"hello world i am a very long line that really, "
-      "in any just world, ought to be split over multiple lines\"},\n"
-      "    {-1, 93463,                                                  "
-      "                                                 \"world\"},\n"
-      "    { 7,     5,                                                  "
-      "                                                    \"!!\"},\n"
-      "};",
-      "test demo[] = {{56, 23, \"hello world i am a very long line "
-      "that really, in any just world, ought to be split over multiple "
-      "lines\"},{-1, 93463, \"world\"},{7, 5, \"!!\"},};",
+      R"(
+test demo[] = {
+    {56,    23, "hello world i am a very long line that really, in any just 
world, ought to be split over multiple lines"},
+    {-1, 93463,                                                                
                                   "world"},
+    { 7,     5,                                                                
                                      "!!"},
+};
+)",
+      R"(
+test demo[] = {{56, 23, "hello world i am a very long line that really, in any 
just world, ought to be split over multiple lines"},{-1, 93463, "world"},{7, 5, 
"!!"},};
+)",
       Style);
 
   Style.ColumnLimit = 80;
@@ -22202,25 +22219,33 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresRightAlignment) {
   verifyFormat("demo = std::array<\n"
                "    struct test, 3>{\n"
                "    test{\n"
-               "         56,    23,\n"
-               "         \"hello \"\n"
-               "         \"world i \"\n"
-               "         \"am a very \"\n"
-               "         \"long line \"\n"
-               "         \"that \"\n"
-               "         \"really, \"\n"
-               "         \"in any \"\n"
-               "         \"just \"\n"
-               "         \"world, \"\n"
-               "         \"ought to \"\n"
-               "         \"be split \"\n"
-               "         \"over \"\n"
-               "         \"multiple \"\n"
-               "         \"lines\"},\n"
-               "    test{-1, 93463,\n"
-               "         \"world\"},\n"
-               "    test{ 7,     5,\n"
-               "         \"!!\"   },\n"
+               "        56,\n"
+               "        23,\n"
+               "        \"hello \"\n"
+               "        \"world i \"\n"
+               "        \"am a very \"\n"
+               "        \"long line \"\n"
+               "        \"that \"\n"
+               "        \"really, \"\n"
+               "        \"in any \"\n"
+               "        \"just \"\n"
+               "        \"world, \"\n"
+               "        \"ought to \"\n"
+               "        \"be split \"\n"
+               "        \"over \"\n"
+               "        \"multiple \"\n"
+               "        \"lines\"\n"
+               "    },\n"
+               "    test{\n"
+               "        -1,\n"
+               "        93463,\n"
+               "        \"world\"\n"
+               "    },\n"
+               "    test{\n"
+               "        7,\n"
+               "        5,\n"
+               "        \"!!\"\n"
+               "    },\n"
                "};",
                "demo = std::array<struct test, 3>{test{56, 23, \"hello world "
                "i am a very long line that really, in any just world, ought "
@@ -22231,8 +22256,10 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresRightAlignment) {
   Style = getLLVMStyleWithColumns(50);
   Style.AlignArrayOfStructures = FormatStyle::AIAS_Right;
   verifyFormat("static A x = {\n"
-               "    {{init1, init2, init3, init4},\n"
-               "     {init1, init2, init3, init4}}\n"
+               "    {\n"
+               "        {init1, init2, init3, init4},\n"
+               "        {init1, init2, init3, init4}\n"
+               "    }\n"
                "};",
                Style);
   // TODO: Fix the indentations below when this option is fully functional.
@@ -22248,10 +22275,13 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresRightAlignment) {
   Style.ColumnLimit = 100;
   verifyFormat(
       "test demo[] = {\n"
-      "    {56,    23,\n"
-      "     \"hello world i am a very long line that really, in any just world"
-      ", ought to be split over \"\n"
-      "     \"multiple lines\"  },\n"
+      "    {\n"
+      "        56,\n"
+      "        23,\n"
+      "        \"hello world i am a very long line that really, in any just "
+      "world, ought to be split over \"\n"
+      "        \"multiple lines\"\n"
+      "    },\n"
       "    {-1, 93463, \"world\"},\n"
       "    { 7,     5,    \"!!\"},\n"
       "};",
@@ -22268,8 +22298,10 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresRightAlignment) {
                "    { 7,     5,    \"!!\"}\n"
                "};\n"
                "static A x = {\n"
-               "    {{init1, init2, init3, init4},\n"
-               "     {init1, init2, init3, init4}}\n"
+               "    {\n"
+               "        {init1, init2, init3, init4},\n"
+               "        {init1, init2, init3, init4}\n"
+               "    }\n"
                "};",
                Style);
   Style.ColumnLimit = 100;
@@ -22287,37 +22319,535 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresRightAlignment) {
                "    {234,     5,  1, \"gracious\"}  // fourth line\n"
                "};",
                Style);
+
+  verifyFormat(R"(
+test demo[] = {
+    {
+        56,
+        "hello world i am a very long line that really, in any just world, 
ought to be split over "
+        "multiple lines",
+        23
+    },
+    {-1, "world", 93463},
+    { 7,    "!!",     5},
+};
+)",
+               R"(
+test demo[] = {{56, "hello world i am a very long line that really, in any 
just world, ought to be split over multiple lines", 23},{-1, "world", 
93463},{7, "!!", 5},};
+)",
+               Style);
+
+  verifyFormat(R"(
+test demo[] = {
+    {-1, "world", 93463},
+    {
+        56,
+        "hello world i am a very long line that really, in any just world, 
ought to be split over "
+        "multiple lines",
+        23
+    },
+    { 7,    "!!",     5},
+};
+)",
+               R"(
+test demo[] = {{-1, "world", 93463},{56, "hello world i am a very long line 
that really, in any just world, ought to be split over multiple lines", 23},{7, 
"!!", 5},};
+)",
+               Style);
+}
+
+TEST_F(FormatTest, AlignArrayOfStructuresGithubIssues) {
+
+  // https://github.com/llvm/llvm-project/issues/148833
+  // Summary: Aligning across macro statments doesn't work
+  //
+  // Notes: It looks like we never even see the tokens in the else branch, so
+  // its not the alignment code thats busted, but the code that collects tokens
+  // to format. See UnwrappedLineParser::addUnwrappedLine for where the tokens
+  // are initially added.
+  FormatStyle Style = getLLVMStyleWithColumns(120);
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+
+  // verifyFormat("const struct reg we_WANT[] = {\n"
+  //              "#if A\n"
+  //              "    {abc,    0, format, code},\n"
+  //              "    {abcd2,  0, format, code},\n"
+  //              "#else\n"
+  //              "    {aaaa,   0, why,    why },\n"
+  //              "    {whyyyy, 0, why,    why },\n"
+  //              "#endif\n"
+  //              "}\n",
+  //              Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/138151
+  // Summary: Aligning arrays of structures with UseTab: AlignWithSpaces does
+  // not use spaces to align columns
+  Style = getGoogleStyle();
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+  Style.UseTab = FormatStyle::UT_AlignWithSpaces;
+  Style.IndentWidth = 4;
+  Style.TabWidth = 4;
+
   verifyFormat(
-      "test demo[] = {\n"
-      "    {56,\n"
-      "     \"hello world i am a very long line that really, in any just world"
-      ", ought to be split over \"\n"
-      "     \"multiple lines\",    23},\n"
-      "    {-1,      \"world\", 93463},\n"
-      "    { 7,         \"!!\",     5},\n"
-      "};",
-      "test demo[] = {{56, \"hello world i am a very long line "
-      "that really, in any just world, ought to be split over multiple "
-      "lines\", 23},{-1, \"world\", 93463},{7, \"!!\", 5},};",
+      "std::vector<Foo> foos = {\n"
+      "\t{LONG_NAME,                0,                        i | j},\n"
+      "\t{LONG_NAME,                0,                        i | j},\n"
+      "\t{LONGER_NAME,              0,                        i | j},\n"
+      "\t{LONGER_NAME,              0,                        i    },\n"
+      "\t{THIS_IS_A_VERY_LONG_NAME, 0,                        j    },\n"
+      "\t{LONGER_NAME,              THIS_IS_A_VERY_LONG_NAME, i    },\n"
+      "\t{LONG_NAME,                THIS_IS_A_VERY_LONG_NAME, j    }\n"
+      "};\n",
+      Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/85937
+  // Summary: Macro escaped newlines are not aligned properly when both
+  // AlignEscapedNewLines and AlignArrayOfStructures are used
+  Style = getLLVMStyleWithColumns(80);
+  Style.AlignEscapedNewlines = FormatStyle::ENAS_Left;
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+
+  verifyFormat(R"(
+#define DEFINE_COMMAND_PROCESS_TABLE(Enum)      \
+  const STExample TCommand::EXPL_MAIN[] = {     \
+      {Enum::GetName(),      " shows help "  }, \
+      {Enum::GetAttribute(), " do something "}, \
+      {Enum::GetState(),     " do whatever " }, \
+  };
+)",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/76803
+  // Summary: constructor member initializer list indentation is weird
+  Style = getLLVMStyle();
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+  Style.IndentWidth = 4;
+
+  verifyFormat("struct Foo {\n"
+               "    explicit Foo()\n"
+               "        : data({\n"
+               "              {1, 2},\n"
+               "          }) {}\n"
+               "    const std::map<int, int> data;\n"
+               "};\n",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/76803
+  // Summary: Array opening and closing brackets are busted even when
+  // AlignArrayOfStructures is None
+  Style = getLLVMStyleWithColumns(100);
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_None;
+  Style.IndentWidth = 2;
+  Style.TabWidth = 2;
+  Style.ContinuationIndentWidth = 2;
+  Style.UseTab = FormatStyle::UT_AlignWithSpaces;
+  Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.PointerAlignment = FormatStyle::PAS_Left;
+  Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
+  Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.AlignOperands = FormatStyle::OAS_DontAlign;
+  Style.BreakBeforeTernaryOperators = true;
+  Style.BreakBeforeBraces = FormatStyle::BS_Attach;
+  Style.BinPackArguments = false;
+  Style.BinPackParameters = FormatStyle::BPPS_AlwaysOnePerLine;
+
+  verifyFormat(
+      R"(VBuffer Renderer::allocateBuffer(AllocateBufferInfo const& info) {
+       VBuffer buf;
+       VkSharingMode sharingMode
+               = info.sharedQueueFamilies.size() >= 2 ? 
VK_SHARING_MODE_CONCURRENT : VK_SHARING_MODE_EXCLUSIVE;
+       CHECKVK(vmaCreateBuffer(
+               allocator_,
+               (VkBufferCreateInfo const[1]){{
+                       .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
+                       .size = info.size,
+                       .usage = info.bufferUsage,
+                       .sharingMode = sharingMode,
+                       .queueFamilyIndexCount = 
uint32_t(info.sharedQueueFamilies.size()),
+                       .pQueueFamilyIndices = info.sharedQueueFamilies.data(),
+               }},
+               (VmaAllocationCreateInfo const[1]){{
+                       .flags = info.allocationFlags,
+                       .usage = info.memoryUsage,
+                       .requiredFlags = info.requiredMemoryPropertyFlags,
+               }},
+               &buf.buffer,
+               &buf.allocation,
+               info.allocationInfo
+       ));
+       return buf;
+}
+)",
       Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/76717
+  // Summary: Braced initializer of struct is badly aligned
+  Style = getLLVMStyle();
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+  Style.ColumnLimit = 0;
+  Style.Cpp11BracedListStyle = false;
+  Style.IndentWidth = 4;
+
+  verifyFormat("static const auto messages = Messages{\n"
+               "    {\n"
+               "        Code::X,\n"
+               "        {\n"
+               "            \"data1\",\n"
+               "            Code::Y,\n"
+               "        },\n"
+               "    },\n"
+               "    {\n"
+               "        Code::Y,\n"
+               "        {\n"
+               "            \"data1\",\n"
+               "            Code::Z,\n"
+               "        },\n"
+               "    },\n"
+               "};\n"
+               "static const Entries entry = {\n"
+               "    { \"\data\",   Code::X },\n"
+               "    { \"\data1\",  Code::Y },\n"
+               "    { \"\data12\", Code::Z },\n"
+               "};\n",
+               Style);
+
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Right;
+
+  verifyFormat("static const auto messages = Messages{\n"
+               "    {\n"
+               "        Code::X,\n"
+               "        {\n"
+               "            \"data1\",\n"
+               "            Code::Y,\n"
+               "        },\n"
+               "    },\n"
+               "    {\n"
+               "        Code::Y,\n"
+               "        {\n"
+               "            \"data1\",\n"
+               "            Code::Z,\n"
+               "        },\n"
+               "    },\n"
+               "};\n"
+               "static const Entries entry = {\n"
+               "    {   \"\data\", Code::X },\n"
+               "    {  \"\data1\", Code::Y },\n"
+               "    { \"\data12\", Code::Z },\n"
+               "};\n",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/55477
+  // Summary: tabs are not used for the indentation of the closing brace in the
+  // following when UseTab: ForContinuationAndIndentation
+  Style = getLLVMStyle();
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Right;
+  Style.AllowAllArgumentsOnNextLine = false;
+  Style.ContinuationIndentWidth = 1;
+  Style.IndentWidth = 1;
+  Style.Standard = FormatStyle::LS_Latest;
+  Style.TabWidth = 1;
+  Style.LineEnding = FormatStyle::LE_LF;
+  Style.UseTab = FormatStyle::UT_ForContinuationAndIndentation;
+
+  verifyFormat("void func() {\n"
+               "\tstd::vector<std::pair<int, std::string>> in = {\n"
+               "\t\t{13, \"13\"},\n"
+               "\t\t{14, \"14\"},\n"
+               "\t\t{ 1,  \"1\"}\n"
+               "\t};\n"
+               "}\n",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/55154
+  // Summary: inconsistent use of tabs vs spaces for indentation when both
+  // SpaceBeforeCpp11BracedList is true and UseTab is
+  // ForContinuationAndIndentation
+  Style = getLLVMStyle();
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+  Style.IndentWidth = 4;
+  Style.SpaceBeforeCpp11BracedList = true;
+  Style.Cpp11BracedListStyle = false;
+  Style.TabWidth = 4;
+  Style.UseTab = FormatStyle::UT_ForContinuationAndIndentation;
+
+  verifyFormat("static type arr[] = {\n"
+               "\t{ fun(arg), arg },\n"
+               "\t{ fun(arg), arg },\n"
+               "\t{ fun(arg), arg },\n"
+               "\t{ fun(arg), arg },\n"
+               "\t{ fun(arg), arg },\n"
+               "\t{ fun(arg), arg },\n"
+               "\t{ fun(arg), arg },\n"
+               "};\n",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/53442
+  // Summary: alignment of columns does not use spaces when UseTab:
+  // AlignWithSpaces
+  Style = getLLVMStyle();
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+  Style.IndentWidth = 4;
+  Style.TabWidth = 4;
+  Style.UseTab = FormatStyle::UT_AlignWithSpaces;
+  Style.BreakBeforeBraces = FormatStyle::BS_Allman;
+
+  verifyFormat(
+      "const map<string, int64_t> CoreReport::GetGameCountersRolloverInfo()\n"
+      "{\n"
+      "\tstatic map<string, int64_t> counterRolloverInfo{\n"
+      "\t\t{\"CashIn\",                   4000000000},\n"
+      "\t\t{\"CoinIn\",                   4000000000},\n"
+      "\t\t{\"QuantityMultiProgressive\", 65535     },\n"
+      "\t};\n"
+      "\treturn counterRolloverInfo;\n"
+      "}\n",
+      Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/55485
+  // Summary: Alignment with tabs is busted
+  Style = getLLVMStyleWithColumns(120);
+  Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Right;
+  Style.BinPackArguments = false;
+  Style.ContinuationIndentWidth = 1;
+  Style.IndentWidth = 1;
+  Style.TabWidth = 1;
+  Style.LineEnding = FormatStyle::LE_LF;
+  Style.UseTab = FormatStyle::UT_ForContinuationAndIndentation;
+
+  verifyFormat("void func() {\n"
+               "\tint array = {\n"
+               "\t\t//\n"
+               "\t\t10,\n"
+               "\t\t20\n"
+               "\t};\n"
+               "\tmy_class a{\n"
+               "\t\t//\n"
+               "\t\t10,\n"
+               "\t\t20\n"
+               "\t};\n"
+               "}\n",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/55477
+  // Summary: Alignment doesn't use tabs
+  Style = getLLVMStyleWithColumns(120);
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Right;
+  Style.AllowAllArgumentsOnNextLine = false;
+  Style.ContinuationIndentWidth = 1;
+  Style.IndentWidth = 1;
+  Style.TabWidth = 1;
+  Style.LineEnding = FormatStyle::LE_LF;
+  Style.UseTab = FormatStyle::UT_ForContinuationAndIndentation;
+
+  verifyFormat("void func() {\n"
+               "\tstd::vector<std::pair<int, std::string>> in = {\n"
+               "\t\t{13, \" 13 \"},\n"
+               "\t\t{14, \" 14 \"},\n"
+               "\t\t{ 1,  \" 1 \"}\n"
+               "\t};\n"
+               "}\n",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/54354
+  // Summary: The comment and array elements do not get indented consistently
+  // Note: The issue does not contain any settings, so these are a guess
+  Style = getLLVMStyleWithColumns(120);
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Right;
+  Style.AllowAllArgumentsOnNextLine = false;
+  Style.ContinuationIndentWidth = 1;
+  Style.TabWidth = 1;
+  Style.LineEnding = FormatStyle::LE_LF;
+  Style.UseTab = FormatStyle::UT_ForContinuationAndIndentation;
+  verifyFormat("std::vector<std::tuple<int, int, int>> input{\n"
+               "\t// Node a, node b, weightage\n"
+               "\t{1, 2, 5},\n"
+               "\t{1, 3, 3},\n"
+               "\t{1, 4, 7},\n"
+               "\t{2, 4, 3},\n"
+               "\t{2, 5, 2},\n"
+               "\t{3, 4, 1},\n"
+               "\t{4, 5, 2}\n"
+               "};\n",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/51766
+  // Summary: Single row does not have it's columns aligned nicely (they bin
+  // pack??)
+  Style = getMicrosoftStyle(FormatStyle::LK_Cpp);
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Right;
+  verifyFormat("LZ4F_preferences_t prefs = {\n"
+               "    {\n"
+               "        LZ4F_default,\n"
+               "        LZ4F_blockLinked,\n"
+               "        LZ4F_contentChecksumEnabled,\n"
+               "        LZ4F_frame,\n"
+               "        cbSource,\n"
+               "        0,\n"
+               "        LZ4F_blockChecksumEnabled,\n"
+               "    }\n"
+               "};\n",
+               Style);
+
+  verifyFormat("class Derived : Base\n"
+               "{\n"
+               "    void foo()\n"
+               "    {\n"
+               "#ifndef _MSC_VER\n"
+               "        const Object object = {\n"
+               "            {\n"
+               "                SOME_MACRO,\n"
+               "                { opt,\n"
+               "                  someMember }\n"
+               "            }\n"
+               "        };\n"
+               "#else\n"
+               "#endif\n"
+               "    }\n"
+               "};\n",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/86439
+  // Summary: Alignment is messed up (appears to be because UseTab: Always)
+  Style = getMicrosoftStyle(FormatStyle::LK_Cpp);
+  Style.IndentWidth = 4;
+  Style.ColumnLimit = 100;
+  Style.SpacesBeforeTrailingComments = 2;
+  Style.BreakBeforeBraces = FormatStyle::BS_Allman;
+  Style.BinPackArguments = false;
+  Style.BinPackParameters = FormatStyle::BPPS_OnePerLine;
+  Style.PackConstructorInitializers = FormatStyle::PCIS_Never;
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+  Style.AlignAfterOpenBracket = FormatStyle::BAS_BlockIndent;
+  Style.ContinuationIndentWidth = 4;
+  Style.Cpp11BracedListStyle = true;
+  Style.UseTab = FormatStyle::UT_Always;
+
+  verifyFormat("struct test demo[] = {\n"
+               "\t{56, 23,\t\" hello \"},\n"
+               "\t{-1, 93463, \" world \"},\n"
+               "\t{7,\t 5,\t\t\" !!\"\t }\n"
+               "};\n",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/142072
+  // Summary: Closing brace is aligned with the return, but should be with the
+  // opening brace
+  Style = getLLVMStyleWithColumns(100);
+  Style.BreakBeforeBraces = FormatStyle::BS_Allman;
+  Style.IndentWidth = 4;
+  Style.UseTab = FormatStyle::UT_Never;
+  Style.AlignAfterOpenBracket = FormatStyle::BAS_AlwaysBreak;
+  Style.BinPackArguments = false;
+  Style.BinPackParameters = FormatStyle::BPPS_OnePerLine;
+  Style.ContinuationIndentWidth = 4;
+  Style.PenaltyReturnTypeOnItsOwnLine = 1000;
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+  Style.PointerAlignment = FormatStyle::PAS_Left;
+  verifyFormat("int test(int argc, char* argv[])\n"
+               "{\n"
+               "    return dispatch(\n"
+               "        argc,\n"
+               "        argv,\n"
+               "        {\n"
+               "            {\"option1\", &test_option1},\n"
+               "            {\"option2\", &test_option2}\n"
+               "        });\n"
+               "}\n",
+               Style);
+
+  // FIXED - https://github.com/llvm/llvm-project/issues/89721
+  // Summary: Really long columns mess up alignment for subsequent columns
+  Style = getLLVMStyleWithColumns(120);
+  Style.AlignAfterOpenBracket = FormatStyle::BAS_Align;
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+  Style.AlignConsecutiveAssignments.Enabled = true;
+  Style.BinPackArguments = false;
+  Style.BinPackParameters = FormatStyle::BPPS_OnePerLine;
+  Style.BreakArrays = true;
+  Style.TabWidth = 4;
+  Style.UseTab = FormatStyle::UT_Never;
+  verifyFormat(R"(const auto test_cases = std::vector<test_configuration>{
+    {
+        
"some_long_path/some_folder/111111/some_other_folder/another_folder/11111111/"
+        "some_really_long_file_name.bin",
+        111e1,
+        -1111111,
+        1.11e1,
+        1111111
+    },
+    {
+        
"some_long_path/some_folder/111111/some_other_folder/another_folder/11111111/"
+        "some_other_really_long_file_name.bin",
+        111e1,
+        11.1111e1,
+        11.11e1,
+        11111111.11
+    },
+    {"short_folder/folder/other/some_long_file_name.bin", 111111111.111111, 
1111111, 111111, 111111},
+};
+)",
+               Style);
+
+  verifyFormat(R"(const auto test_cases = std::vector<test_configuration>{
+    {
+        .filepath_suffix = 
"some_long_path/some_folder/111111/some_other_folder/another_folder/11111111/"
+                           "some_really_long_file_name.bin",
+        .double1         = 111e1,
+        .double2         = -1111111,
+        .double3         = 1.11e1,
+        .double4         = 1111111,
+    },
+    {
+        .filepath_suffix = 
"some_long_path/some_folder/111111/some_other_folder/another_folder/11111111/"
+                           "some_other_really_long_file_name.bin",
+        .double1         = 111e1,
+        .double2         = 11.1111e1,
+        .double3         = 11.11e1,
+        .double4         = 11111111.11,
+    },
+    {
+        .filepath_suffix = "short_folder/folder/other/some_long_file_name.bin",
+        .double1         = 111111111.111111,
+        .double2         = 1111111,
+        .double3         = 111111,
+        .double4         = 111111,
+    },
+};
+)",
+               Style);
 }
 
 TEST_F(FormatTest, CatchAlignArrayOfStructuresLeftAlignment) {
   auto Style = getLLVMStyle();
   Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
-  /* FIXME: This case gets misformatted.
   verifyFormat("auto foo = Items{\n"
-               "    Section{0, bar(), },\n"
-               "    Section{1, boo()  }\n"
+               "    Section{\n"
+               "        0,\n"
+               "        bar(),\n"
+               "    },\n"
+               "    Section{1, boo()}\n"
                "};",
                Style);
-  */
+
   verifyFormat("auto foo = Items{\n"
                "    Section{\n"
-               "            0, bar(),\n"
-               "            }\n"
+               "        0,\n"
+               "        bar(),\n"
+               "    }\n"
+               "};",
+               Style);
+
+  verifyFormat("auto foo = Items{\n"
+               "    Section{0, barbar()},\n"
+               "    Section{1, boo()   }\n"
+               "};",
+               Style);
+
+  verifyFormat("auto foo = Items{\n"
+               "    Section{0, bar()}\n"
                "};",
                Style);
+
   verifyFormat("struct test demo[] = {\n"
                "    {56, 23,    \"hello\"},\n"
                "    {-1, 93463, \"world\"},\n"
@@ -22376,16 +22906,37 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresLeftAlignment) {
                "    {7,  5,     \"!!\"   }\n"
                "};",
                Style);
+
   verifyFormat(
       "test demo[] = {\n"
-      "    {7,  23,\n"
-      "     \"hello world i am a very long line that really, in any\"\n"
-      "     \"just world, ought to be split over multiple lines\"},\n"
-      "    {-1, 93463, \"world\"                                 },\n"
-      "    {56, 5,     \"!!\"                                    }\n"
+      "    {\n"
+      "        7,\n"
+      "        23,\n"
+      "        \"hello world i am a very long line that really, in any\"\n"
+      "        \"just world, ought to be split over multiple lines\"\n"
+      "    },\n"
+      "    {-1, 93463, \"world\"},\n"
+      "    {56, 5,     \"!!\"   }\n"
       "};",
       Style);
 
+  Style = getLLVMStyleWithColumns(100);
+  Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
+  verifyFormat(R"(test demo[] = {
+    {
+        4,
+        5,
+        [](int a) {
+          const char *x = "djdjdjdjdjdjdjdjdjdj";
+          return x;
+        }
+    },
+    {6,     -442,    "asd"                                     },
+    {14124, 4324234, "dasdoijoiajsodijoaisjodijoaisjdoijoaijsd"}
+};
+)",
+               Style);
+
   verifyNoCrash("Foo f[] = {\n"
                 "    [0] = { 1, },\n"
                 "    [i] { 1, },\n"
@@ -22409,7 +22960,7 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresLeftAlignment) {
                "\"dy\"}   },\n"
                "                                {{\"dx\"},   \"Mul\",  "
                "{\"dy\", \"sign\"}},\n"
-               "});",
+               "                            });",
                Style);
 
   Style.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign;
@@ -22430,17 +22981,12 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresLeftAlignment) {
 
   Style.ColumnLimit = 0;
   verifyFormat(
-      "test demo[] = {\n"
-      "    {56, 23,    \"hello world i am a very long line that really, in any 
"
-      "just world, ought to be split over multiple lines\"},\n"
-      "    {-1, 93463, \"world\"                                               
"
-      "                                                   },\n"
-      "    {7,  5,     \"!!\"                                                  
"
-      "                                                   },\n"
-      "};",
-      "test demo[] = {{56, 23, \"hello world i am a very long line "
-      "that really, in any just world, ought to be split over multiple "
-      "lines\"},{-1, 93463, \"world\"},{7, 5, \"!!\"},};",
+      R"(test demo[] = {
+    {56, 23,    "hello world i am a very long line that really, in any just 
world, ought to be split over multiple lines"},
+    {-1, 93463, "world"                                                        
                                          },
+    {7,  5,     "!!"                                                           
                                          },
+};)",
+      R"(test demo[] = {{56, 23, "hello world i am a very long line that 
really, in any just world, ought to be split over multiple lines"},{-1, 93463, 
"world"},{7, 5, "!!"},};)",
       Style);
 
   Style.ColumnLimit = 80;
@@ -22476,25 +23022,33 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresLeftAlignment) {
       "demo = std::array<\n"
       "    struct test, 3>{\n"
       "    test{\n"
-      "         56, 23,\n"
-      "         \"hello \"\n"
-      "         \"world i \"\n"
-      "         \"am a very \"\n"
-      "         \"long line \"\n"
-      "         \"that \"\n"
-      "         \"really, \"\n"
-      "         \"in any \"\n"
-      "         \"just \"\n"
-      "         \"world, \"\n"
-      "         \"ought to \"\n"
-      "         \"be split \"\n"
-      "         \"over \"\n"
-      "         \"multiple \"\n"
-      "         \"lines\"},\n"
-      "    test{-1, 93463,\n"
-      "         \"world\"},\n"
-      "    test{7,  5,\n"
-      "         \"!!\"   },\n"
+      "        56,\n"
+      "        23,\n"
+      "        \"hello \"\n"
+      "        \"world i \"\n"
+      "        \"am a very \"\n"
+      "        \"long line \"\n"
+      "        \"that \"\n"
+      "        \"really, \"\n"
+      "        \"in any \"\n"
+      "        \"just \"\n"
+      "        \"world, \"\n"
+      "        \"ought to \"\n"
+      "        \"be split \"\n"
+      "        \"over \"\n"
+      "        \"multiple \"\n"
+      "        \"lines\"\n"
+      "    },\n"
+      "    test{\n"
+      "        -1,\n"
+      "        93463,\n"
+      "        \"world\"\n"
+      "    },\n"
+      "    test{\n"
+      "        7,\n"
+      "        5,\n"
+      "        \"!!\"\n"
+      "    },\n"
       "};",
       format("demo = std::array<struct test, 3>{test{56, 23, \"hello world "
              "i am a very long line that really, in any just world, ought "
@@ -22506,17 +23060,22 @@ TEST_F(FormatTest, 
CatchAlignArrayOfStructuresLeftAlignment) {
   Style = getLLVMStyleWithColumns(50);
   Style.AlignArrayOfStructures = FormatStyle::AIAS_Left;
   verifyFormat("static A x = {\n"
-               "    {{init1, init2, init3, init4},\n"
-               "     {init1, init2, init3, init4}}\n"
+               "    {\n"
+               "        {init1, init2, init3, init4},\n"
+               "        {init1, init2, init3, init4}\n"
+               "    }\n"
                "};",
                Style);
   Style.ColumnLimit = 100;
   verifyFormat(
       "test demo[] = {\n"
-      "    {56, 23,\n"
-      "     \"hello world i am a very long line that really, in any just world"
-      ", ought to be split over \"\n"
-      "     \"multiple lines\"  },\n"
+      "    {\n"
+      "        56,\n"
+      "        23,\n"
+      "        \"hello world i am a very long line that really, in any just "
+      "world, ought to be split over \"\n"
+      "        \"multiple lines\"\n"
+      "    },\n"
       "    {-1, 93463, \"world\"},\n"
       "    {7,  5,     \"!!\"   },\n"
       "};",
@@ -27955,51 +28514,84 @@ TEST_F(FormatTest, 
AlignArrayOfStructuresLeftAlignmentNonSquare) {
   // crashes, these tests assert that the array is not changed but will
   // also act as regression tests for when it is properly fixed
   verifyFormat("struct test demo[] = {\n"
-               "    {1, 2},\n"
+               "    {1, 2   },\n"
                "    {3, 4, 5},\n"
                "    {6, 7, 8}\n"
                "};",
                Style);
   verifyFormat("struct test demo[] = {\n"
                "    {1, 2, 3, 4, 5},\n"
-               "    {3, 4, 5},\n"
-               "    {6, 7, 8}\n"
+               "    {3, 4, 5      },\n"
+               "    {6, 7, 8      }\n"
                "};",
                Style);
   verifyFormat("struct test demo[] = {\n"
-               "    {1, 2, 3, 4, 5},\n"
-               "    {3, 4, 5},\n"
+               "    {1, 2, 3, 4, 5         },\n"
+               "    {3, 4, 5               },\n"
                "    {6, 7, 8, 9, 10, 11, 12}\n"
                "};",
                Style);
   verifyFormat("struct test demo[] = {\n"
-               "    {1, 2, 3},\n"
-               "    {3, 4, 5},\n"
+               "    {1, 2, 3               },\n"
+               "    {3, 4, 5               },\n"
                "    {6, 7, 8, 9, 10, 11, 12}\n"
                "};",
                Style);
 
   verifyFormat("S{\n"
-               "    {},\n"
-               "    {},\n"
+               "    {    },\n"
+               "    {    },\n"
                "    {a, b}\n"
                "};",
                Style);
   verifyFormat("S{\n"
-               "    {},\n"
-               "    {},\n"
+               "    {    },\n"
+               "    {    },\n"
                "    {a, b},\n"
                "};",
                Style);
   verifyFormat("void foo() {\n"
                "  auto thing = test{\n"
                "      {\n"
-               "       {13},\n"
-               "       {something}, // A\n"
+               "          {13},\n"
+               "          {something}, // A\n"
                "      }\n"
                "  };\n"
                "}",
                Style);
+  verifyFormat("test demo::a[] = {\n"
+               "    {abcde, foo(\"something\"), extra_bit},\n"
+               "    {\n"
+               "        ab,\n"
+               "        foo(\"something else\"),\n"
+               "    },\n"
+               "    {\n"
+               "        abc,\n"
+               "        foo(\"\"),\n"
+               "    }\n"
+               "};",
+               Style);
+  verifyFormat("struct test demo = {\n"
+               "    {abcde, foo(\"something\"),     extra_bit},\n"
+               "    {ab,    foo(\"something else\")          },\n"
+               "    {abc,   foo(\"\")                        }\n"
+               "};",
+               Style);
+  verifyFormat("struct test demo = {\n"
+               "    {abcde, foo(\"something\"),      extra_bit},\n"
+               "    {ab,    foo(\"something else\")           },\n"
+               "    {ad,    foo(\"something else\"), extra    },\n"
+               "    {abc,   foo(\"\")                         }\n"
+               "};",
+               Style);
+  verifyFormat("struct test demo = {\n"
+               "    {\n"
+               "        very_long_identifier_number_1,\n"
+               "        shorter_identifier,\n"
+               "        very_long_identifier_number_3,\n"
+               "    }\n"
+               "};",
+               Style);
 }
 
 TEST_F(FormatTest, AlignArrayOfStructuresRightAlignmentNonSquare) {
@@ -28012,51 +28604,84 @@ TEST_F(FormatTest, 
AlignArrayOfStructuresRightAlignmentNonSquare) {
   // crashes, these tests assert that the array is not changed but will
   // also act as regression tests for when it is properly fixed
   verifyFormat("struct test demo[] = {\n"
-               "    {1, 2},\n"
+               "    {1, 2   },\n"
                "    {3, 4, 5},\n"
                "    {6, 7, 8}\n"
                "};",
                Style);
   verifyFormat("struct test demo[] = {\n"
                "    {1, 2, 3, 4, 5},\n"
-               "    {3, 4, 5},\n"
-               "    {6, 7, 8}\n"
+               "    {3, 4, 5      },\n"
+               "    {6, 7, 8      }\n"
                "};",
                Style);
   verifyFormat("struct test demo[] = {\n"
-               "    {1, 2, 3, 4, 5},\n"
-               "    {3, 4, 5},\n"
+               "    {1, 2, 3, 4,  5        },\n"
+               "    {3, 4, 5               },\n"
                "    {6, 7, 8, 9, 10, 11, 12}\n"
                "};",
                Style);
   verifyFormat("struct test demo[] = {\n"
-               "    {1, 2, 3},\n"
-               "    {3, 4, 5},\n"
+               "    {1, 2, 3               },\n"
+               "    {3, 4, 5               },\n"
                "    {6, 7, 8, 9, 10, 11, 12}\n"
                "};",
                Style);
 
   verifyFormat("S{\n"
-               "    {},\n"
-               "    {},\n"
+               "    {    },\n"
+               "    {    },\n"
                "    {a, b}\n"
                "};",
                Style);
   verifyFormat("S{\n"
-               "    {},\n"
-               "    {},\n"
+               "    {    },\n"
+               "    {    },\n"
                "    {a, b},\n"
                "};",
                Style);
   verifyFormat("void foo() {\n"
                "  auto thing = test{\n"
                "      {\n"
-               "       {13},\n"
-               "       {something}, // A\n"
+               "          {13},\n"
+               "          {something}, // A\n"
                "      }\n"
                "  };\n"
                "}",
                Style);
+  verifyFormat("test demo::a[] = {\n"
+               "    {abcde, foo(\"something\"), extra_bit},\n"
+               "    {\n"
+               "        ab,\n"
+               "        foo(\"something else\"),\n"
+               "    },\n"
+               "    {\n"
+               "        abc,\n"
+               "        foo(\"\"),\n"
+               "    }\n"
+               "};",
+               Style);
+  verifyFormat("struct test demo = {\n"
+               "    {abcde,      foo(\"something\"), extra_bit},\n"
+               "    {   ab, foo(\"something else\")           },\n"
+               "    {  abc,               foo(\"\")           }\n"
+               "};",
+               Style);
+  verifyFormat("struct test demo = {\n"
+               "    {abcde,      foo(\"something\"), extra_bit},\n"
+               "    {   ab, foo(\"something else\")           },\n"
+               "    {   ad, foo(\"something else\"),     extra},\n"
+               "    {  abc,               foo(\"\")           }\n"
+               "};",
+               Style);
+  verifyFormat("struct test demo = {\n"
+               "    {\n"
+               "        very_long_identifier_number_1,\n"
+               "        shorter_identifier,\n"
+               "        very_long_identifier_number_3,\n"
+               "    }\n"
+               "};",
+               Style);
 }
 
 TEST_F(FormatTest, FormatsVariableTemplates) {

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to