xref: /freebsd-src/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp (revision 6c4b055cfb6bf549e9145dde6454cc6b178c35e4)
10b57cec5SDimitry Andric //===--- WhitespaceManager.cpp - Format C++ code --------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file implements WhitespaceManager class.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "WhitespaceManager.h"
150b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
16fe6060f1SDimitry Andric #include "llvm/ADT/SmallVector.h"
17fe6060f1SDimitry Andric #include <algorithm>
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric namespace clang {
200b57cec5SDimitry Andric namespace format {
210b57cec5SDimitry Andric 
22a7dea167SDimitry Andric bool WhitespaceManager::Change::IsBeforeInFile::operator()(
23a7dea167SDimitry Andric     const Change &C1, const Change &C2) const {
240b57cec5SDimitry Andric   return SourceMgr.isBeforeInTranslationUnit(
250b57cec5SDimitry Andric              C1.OriginalWhitespaceRange.getBegin(),
265f757f3fSDimitry Andric              C2.OriginalWhitespaceRange.getBegin()) ||
275f757f3fSDimitry Andric          (C1.OriginalWhitespaceRange.getBegin() ==
285f757f3fSDimitry Andric               C2.OriginalWhitespaceRange.getBegin() &&
295f757f3fSDimitry Andric           SourceMgr.isBeforeInTranslationUnit(
305f757f3fSDimitry Andric               C1.OriginalWhitespaceRange.getEnd(),
315f757f3fSDimitry Andric               C2.OriginalWhitespaceRange.getEnd()));
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric WhitespaceManager::Change::Change(const FormatToken &Tok,
350b57cec5SDimitry Andric                                   bool CreateReplacement,
360b57cec5SDimitry Andric                                   SourceRange OriginalWhitespaceRange,
370b57cec5SDimitry Andric                                   int Spaces, unsigned StartOfTokenColumn,
380b57cec5SDimitry Andric                                   unsigned NewlinesBefore,
390b57cec5SDimitry Andric                                   StringRef PreviousLinePostfix,
405ffd83dbSDimitry Andric                                   StringRef CurrentLinePrefix, bool IsAligned,
410b57cec5SDimitry Andric                                   bool ContinuesPPDirective, bool IsInsideToken)
420b57cec5SDimitry Andric     : Tok(&Tok), CreateReplacement(CreateReplacement),
430b57cec5SDimitry Andric       OriginalWhitespaceRange(OriginalWhitespaceRange),
440b57cec5SDimitry Andric       StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
450b57cec5SDimitry Andric       PreviousLinePostfix(PreviousLinePostfix),
465ffd83dbSDimitry Andric       CurrentLinePrefix(CurrentLinePrefix), IsAligned(IsAligned),
470b57cec5SDimitry Andric       ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces),
480b57cec5SDimitry Andric       IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0),
490b57cec5SDimitry Andric       PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
505ffd83dbSDimitry Andric       StartOfBlockComment(nullptr), IndentationOffset(0), ConditionalsLevel(0) {
515ffd83dbSDimitry Andric }
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
540b57cec5SDimitry Andric                                           unsigned Spaces,
550b57cec5SDimitry Andric                                           unsigned StartOfTokenColumn,
565ffd83dbSDimitry Andric                                           bool IsAligned, bool InPPDirective) {
5706c3fb27SDimitry Andric   if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg))
580b57cec5SDimitry Andric     return;
59e8d8bef9SDimitry Andric   Tok.setDecision((Newlines > 0) ? FD_Break : FD_Continue);
600b57cec5SDimitry Andric   Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange,
610b57cec5SDimitry Andric                            Spaces, StartOfTokenColumn, Newlines, "", "",
625ffd83dbSDimitry Andric                            IsAligned, InPPDirective && !Tok.IsFirst,
630b57cec5SDimitry Andric                            /*IsInsideToken=*/false));
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
670b57cec5SDimitry Andric                                             bool InPPDirective) {
6806c3fb27SDimitry Andric   if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg))
690b57cec5SDimitry Andric     return;
700b57cec5SDimitry Andric   Changes.push_back(Change(Tok, /*CreateReplacement=*/false,
710b57cec5SDimitry Andric                            Tok.WhitespaceRange, /*Spaces=*/0,
720b57cec5SDimitry Andric                            Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
735ffd83dbSDimitry Andric                            /*IsAligned=*/false, InPPDirective && !Tok.IsFirst,
740b57cec5SDimitry Andric                            /*IsInsideToken=*/false));
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric llvm::Error
780b57cec5SDimitry Andric WhitespaceManager::addReplacement(const tooling::Replacement &Replacement) {
790b57cec5SDimitry Andric   return Replaces.add(Replacement);
800b57cec5SDimitry Andric }
810b57cec5SDimitry Andric 
8204eeddc0SDimitry Andric bool WhitespaceManager::inputUsesCRLF(StringRef Text, bool DefaultToCRLF) {
8304eeddc0SDimitry Andric   size_t LF = Text.count('\n');
8404eeddc0SDimitry Andric   size_t CR = Text.count('\r') * 2;
8504eeddc0SDimitry Andric   return LF == CR ? DefaultToCRLF : CR > LF;
8604eeddc0SDimitry Andric }
8704eeddc0SDimitry Andric 
880b57cec5SDimitry Andric void WhitespaceManager::replaceWhitespaceInToken(
890b57cec5SDimitry Andric     const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
900b57cec5SDimitry Andric     StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
910b57cec5SDimitry Andric     unsigned Newlines, int Spaces) {
9206c3fb27SDimitry Andric   if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg))
930b57cec5SDimitry Andric     return;
940b57cec5SDimitry Andric   SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
950b57cec5SDimitry Andric   Changes.push_back(
960b57cec5SDimitry Andric       Change(Tok, /*CreateReplacement=*/true,
970b57cec5SDimitry Andric              SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces,
980b57cec5SDimitry Andric              std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,
995ffd83dbSDimitry Andric              /*IsAligned=*/true, InPPDirective && !Tok.IsFirst,
1005ffd83dbSDimitry Andric              /*IsInsideToken=*/true));
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric const tooling::Replacements &WhitespaceManager::generateReplacements() {
1040b57cec5SDimitry Andric   if (Changes.empty())
1050b57cec5SDimitry Andric     return Replaces;
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   llvm::sort(Changes, Change::IsBeforeInFile(SourceMgr));
1080b57cec5SDimitry Andric   calculateLineBreakInformation();
1090b57cec5SDimitry Andric   alignConsecutiveMacros();
1100fca6ea1SDimitry Andric   alignConsecutiveShortCaseStatements(/*IsExpr=*/true);
1110fca6ea1SDimitry Andric   alignConsecutiveShortCaseStatements(/*IsExpr=*/false);
1120b57cec5SDimitry Andric   alignConsecutiveDeclarations();
1135ffd83dbSDimitry Andric   alignConsecutiveBitFields();
1140b57cec5SDimitry Andric   alignConsecutiveAssignments();
1150fca6ea1SDimitry Andric   if (Style.isTableGen()) {
1160fca6ea1SDimitry Andric     alignConsecutiveTableGenBreakingDAGArgColons();
1170fca6ea1SDimitry Andric     alignConsecutiveTableGenCondOperatorColons();
1180fca6ea1SDimitry Andric     alignConsecutiveTableGenDefinitions();
1190fca6ea1SDimitry Andric   }
1205ffd83dbSDimitry Andric   alignChainedConditionals();
1210b57cec5SDimitry Andric   alignTrailingComments();
1220b57cec5SDimitry Andric   alignEscapedNewlines();
123fe6060f1SDimitry Andric   alignArrayInitializers();
1240b57cec5SDimitry Andric   generateChanges();
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   return Replaces;
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric void WhitespaceManager::calculateLineBreakInformation() {
1300b57cec5SDimitry Andric   Changes[0].PreviousEndOfTokenColumn = 0;
1310b57cec5SDimitry Andric   Change *LastOutsideTokenChange = &Changes[0];
1320fca6ea1SDimitry Andric   for (unsigned I = 1, e = Changes.size(); I != e; ++I) {
1330fca6ea1SDimitry Andric     auto &C = Changes[I];
1340fca6ea1SDimitry Andric     auto &P = Changes[I - 1];
1350fca6ea1SDimitry Andric     auto &PrevTokLength = P.TokenLength;
1360b57cec5SDimitry Andric     SourceLocation OriginalWhitespaceStart =
1370fca6ea1SDimitry Andric         C.OriginalWhitespaceRange.getBegin();
1380b57cec5SDimitry Andric     SourceLocation PreviousOriginalWhitespaceEnd =
1390fca6ea1SDimitry Andric         P.OriginalWhitespaceRange.getEnd();
1400b57cec5SDimitry Andric     unsigned OriginalWhitespaceStartOffset =
1410b57cec5SDimitry Andric         SourceMgr.getFileOffset(OriginalWhitespaceStart);
1420b57cec5SDimitry Andric     unsigned PreviousOriginalWhitespaceEndOffset =
1430b57cec5SDimitry Andric         SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd);
1440b57cec5SDimitry Andric     assert(PreviousOriginalWhitespaceEndOffset <=
1450b57cec5SDimitry Andric            OriginalWhitespaceStartOffset);
1460b57cec5SDimitry Andric     const char *const PreviousOriginalWhitespaceEndData =
1470b57cec5SDimitry Andric         SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd);
1480b57cec5SDimitry Andric     StringRef Text(PreviousOriginalWhitespaceEndData,
1490b57cec5SDimitry Andric                    SourceMgr.getCharacterData(OriginalWhitespaceStart) -
1500b57cec5SDimitry Andric                        PreviousOriginalWhitespaceEndData);
1510b57cec5SDimitry Andric     // Usually consecutive changes would occur in consecutive tokens. This is
1520b57cec5SDimitry Andric     // not the case however when analyzing some preprocessor runs of the
1530b57cec5SDimitry Andric     // annotated lines. For example, in this code:
1540b57cec5SDimitry Andric     //
1550b57cec5SDimitry Andric     // #if A // line 1
1560b57cec5SDimitry Andric     // int i = 1;
1570b57cec5SDimitry Andric     // #else B // line 2
1580b57cec5SDimitry Andric     // int i = 2;
1590b57cec5SDimitry Andric     // #endif // line 3
1600b57cec5SDimitry Andric     //
1610b57cec5SDimitry Andric     // one of the runs will produce the sequence of lines marked with line 1, 2
1620b57cec5SDimitry Andric     // and 3. So the two consecutive whitespace changes just before '// line 2'
1630b57cec5SDimitry Andric     // and before '#endif // line 3' span multiple lines and tokens:
1640b57cec5SDimitry Andric     //
1650b57cec5SDimitry Andric     // #else B{change X}[// line 2
1660b57cec5SDimitry Andric     // int i = 2;
1670b57cec5SDimitry Andric     // ]{change Y}#endif // line 3
1680b57cec5SDimitry Andric     //
1690b57cec5SDimitry Andric     // For this reason, if the text between consecutive changes spans multiple
1700b57cec5SDimitry Andric     // newlines, the token length must be adjusted to the end of the original
1710b57cec5SDimitry Andric     // line of the token.
1720b57cec5SDimitry Andric     auto NewlinePos = Text.find_first_of('\n');
1730b57cec5SDimitry Andric     if (NewlinePos == StringRef::npos) {
1740fca6ea1SDimitry Andric       PrevTokLength = OriginalWhitespaceStartOffset -
1750b57cec5SDimitry Andric                       PreviousOriginalWhitespaceEndOffset +
1760fca6ea1SDimitry Andric                       C.PreviousLinePostfix.size() + P.CurrentLinePrefix.size();
1770fca6ea1SDimitry Andric       if (!P.IsInsideToken)
1780fca6ea1SDimitry Andric         PrevTokLength = std::min(PrevTokLength, P.Tok->ColumnWidth);
1790b57cec5SDimitry Andric     } else {
1800fca6ea1SDimitry Andric       PrevTokLength = NewlinePos + P.CurrentLinePrefix.size();
1810b57cec5SDimitry Andric     }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric     // If there are multiple changes in this token, sum up all the changes until
1840b57cec5SDimitry Andric     // the end of the line.
1850fca6ea1SDimitry Andric     if (P.IsInsideToken && P.NewlinesBefore == 0)
1860fca6ea1SDimitry Andric       LastOutsideTokenChange->TokenLength += PrevTokLength + P.Spaces;
1870fca6ea1SDimitry Andric     else
1880fca6ea1SDimitry Andric       LastOutsideTokenChange = &P;
1890b57cec5SDimitry Andric 
1900fca6ea1SDimitry Andric     C.PreviousEndOfTokenColumn = P.StartOfTokenColumn + PrevTokLength;
1910b57cec5SDimitry Andric 
1920fca6ea1SDimitry Andric     P.IsTrailingComment =
1930fca6ea1SDimitry Andric         (C.NewlinesBefore > 0 || C.Tok->is(tok::eof) ||
1940fca6ea1SDimitry Andric          (C.IsInsideToken && C.Tok->is(tok::comment))) &&
1950fca6ea1SDimitry Andric         P.Tok->is(tok::comment) &&
1960b57cec5SDimitry Andric         // FIXME: This is a dirty hack. The problem is that
1970b57cec5SDimitry Andric         // BreakableLineCommentSection does comment reflow changes and here is
1980b57cec5SDimitry Andric         // the aligning of trailing comments. Consider the case where we reflow
1990b57cec5SDimitry Andric         // the second line up in this example:
2000b57cec5SDimitry Andric         //
2010b57cec5SDimitry Andric         // // line 1
2020b57cec5SDimitry Andric         // // line 2
2030b57cec5SDimitry Andric         //
2040b57cec5SDimitry Andric         // That amounts to 2 changes by BreakableLineCommentSection:
2050b57cec5SDimitry Andric         //  - the first, delimited by (), for the whitespace between the tokens,
2060b57cec5SDimitry Andric         //  - and second, delimited by [], for the whitespace at the beginning
2070b57cec5SDimitry Andric         //  of the second token:
2080b57cec5SDimitry Andric         //
2090b57cec5SDimitry Andric         // // line 1(
2100b57cec5SDimitry Andric         // )[// ]line 2
2110b57cec5SDimitry Andric         //
2120b57cec5SDimitry Andric         // So in the end we have two changes like this:
2130b57cec5SDimitry Andric         //
2140b57cec5SDimitry Andric         // // line1()[ ]line 2
2150b57cec5SDimitry Andric         //
2160b57cec5SDimitry Andric         // Note that the OriginalWhitespaceStart of the second change is the
2170b57cec5SDimitry Andric         // same as the PreviousOriginalWhitespaceEnd of the first change.
2180b57cec5SDimitry Andric         // In this case, the below check ensures that the second change doesn't
2190b57cec5SDimitry Andric         // get treated as a trailing comment change here, since this might
2200b57cec5SDimitry Andric         // trigger additional whitespace to be wrongly inserted before "line 2"
2210b57cec5SDimitry Andric         // by the comment aligner here.
2220b57cec5SDimitry Andric         //
2230b57cec5SDimitry Andric         // For a proper solution we need a mechanism to say to WhitespaceManager
2240b57cec5SDimitry Andric         // that a particular change breaks the current sequence of trailing
2250b57cec5SDimitry Andric         // comments.
2260b57cec5SDimitry Andric         OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd;
2270b57cec5SDimitry Andric   }
2280b57cec5SDimitry Andric   // FIXME: The last token is currently not always an eof token; in those
2290b57cec5SDimitry Andric   // cases, setting TokenLength of the last token to 0 is wrong.
2300b57cec5SDimitry Andric   Changes.back().TokenLength = 0;
2310b57cec5SDimitry Andric   Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   const WhitespaceManager::Change *LastBlockComment = nullptr;
2340b57cec5SDimitry Andric   for (auto &Change : Changes) {
2350b57cec5SDimitry Andric     // Reset the IsTrailingComment flag for changes inside of trailing comments
2360b57cec5SDimitry Andric     // so they don't get realigned later. Comment line breaks however still need
2370b57cec5SDimitry Andric     // to be aligned.
2380b57cec5SDimitry Andric     if (Change.IsInsideToken && Change.NewlinesBefore == 0)
2390b57cec5SDimitry Andric       Change.IsTrailingComment = false;
2400b57cec5SDimitry Andric     Change.StartOfBlockComment = nullptr;
2410b57cec5SDimitry Andric     Change.IndentationOffset = 0;
2420b57cec5SDimitry Andric     if (Change.Tok->is(tok::comment)) {
24381ad6265SDimitry Andric       if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken) {
2440b57cec5SDimitry Andric         LastBlockComment = &Change;
24581ad6265SDimitry Andric       } else if ((Change.StartOfBlockComment = LastBlockComment)) {
2460b57cec5SDimitry Andric         Change.IndentationOffset =
2470b57cec5SDimitry Andric             Change.StartOfTokenColumn -
2480b57cec5SDimitry Andric             Change.StartOfBlockComment->StartOfTokenColumn;
2490b57cec5SDimitry Andric       }
2500b57cec5SDimitry Andric     } else {
2510b57cec5SDimitry Andric       LastBlockComment = nullptr;
2520b57cec5SDimitry Andric     }
2530b57cec5SDimitry Andric   }
2545ffd83dbSDimitry Andric 
2555ffd83dbSDimitry Andric   // Compute conditional nesting level
2565ffd83dbSDimitry Andric   // Level is increased for each conditional, unless this conditional continues
2575ffd83dbSDimitry Andric   // a chain of conditional, i.e. starts immediately after the colon of another
2585ffd83dbSDimitry Andric   // conditional.
2595ffd83dbSDimitry Andric   SmallVector<bool, 16> ScopeStack;
2605ffd83dbSDimitry Andric   int ConditionalsLevel = 0;
2615ffd83dbSDimitry Andric   for (auto &Change : Changes) {
2625ffd83dbSDimitry Andric     for (unsigned i = 0, e = Change.Tok->FakeLParens.size(); i != e; ++i) {
2635ffd83dbSDimitry Andric       bool isNestedConditional =
2645ffd83dbSDimitry Andric           Change.Tok->FakeLParens[e - 1 - i] == prec::Conditional &&
2655ffd83dbSDimitry Andric           !(i == 0 && Change.Tok->Previous &&
2665ffd83dbSDimitry Andric             Change.Tok->Previous->is(TT_ConditionalExpr) &&
2675ffd83dbSDimitry Andric             Change.Tok->Previous->is(tok::colon));
2685ffd83dbSDimitry Andric       if (isNestedConditional)
2695ffd83dbSDimitry Andric         ++ConditionalsLevel;
2705ffd83dbSDimitry Andric       ScopeStack.push_back(isNestedConditional);
2715ffd83dbSDimitry Andric     }
2725ffd83dbSDimitry Andric 
2735ffd83dbSDimitry Andric     Change.ConditionalsLevel = ConditionalsLevel;
2745ffd83dbSDimitry Andric 
27581ad6265SDimitry Andric     for (unsigned i = Change.Tok->FakeRParens; i > 0 && ScopeStack.size(); --i)
2765ffd83dbSDimitry Andric       if (ScopeStack.pop_back_val())
2775ffd83dbSDimitry Andric         --ConditionalsLevel;
2785ffd83dbSDimitry Andric   }
2795ffd83dbSDimitry Andric }
2800b57cec5SDimitry Andric 
2810b57cec5SDimitry Andric // Align a single sequence of tokens, see AlignTokens below.
28281ad6265SDimitry Andric // Column - The token for which Matches returns true is moved to this column.
28381ad6265SDimitry Andric // RightJustify - Whether it is the token's right end or left end that gets
28481ad6265SDimitry Andric // moved to that column.
2850b57cec5SDimitry Andric template <typename F>
2860b57cec5SDimitry Andric static void
287fe6060f1SDimitry Andric AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
28881ad6265SDimitry Andric                    unsigned Column, bool RightJustify, F &&Matches,
2890b57cec5SDimitry Andric                    SmallVector<WhitespaceManager::Change, 16> &Changes) {
2900b57cec5SDimitry Andric   bool FoundMatchOnLine = false;
2910b57cec5SDimitry Andric   int Shift = 0;
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric   // ScopeStack keeps track of the current scope depth. It contains indices of
2940b57cec5SDimitry Andric   // the first token on each scope.
2950b57cec5SDimitry Andric   // We only run the "Matches" function on tokens from the outer-most scope.
2960b57cec5SDimitry Andric   // However, we do need to pay special attention to one class of tokens
2970b57cec5SDimitry Andric   // that are not in the outer-most scope, and that is function parameters
2980b57cec5SDimitry Andric   // which are split across multiple lines, as illustrated by this example:
2990b57cec5SDimitry Andric   //   double a(int x);
3000b57cec5SDimitry Andric   //   int    b(int  y,
3010b57cec5SDimitry Andric   //          double z);
3020b57cec5SDimitry Andric   // In the above example, we need to take special care to ensure that
3030b57cec5SDimitry Andric   // 'double z' is indented along with it's owning function 'b'.
304fe6060f1SDimitry Andric   // The same holds for calling a function:
305fe6060f1SDimitry Andric   //   double a = foo(x);
306fe6060f1SDimitry Andric   //   int    b = bar(foo(y),
307fe6060f1SDimitry Andric   //            foor(z));
308fe6060f1SDimitry Andric   // Similar for broken string literals:
309fe6060f1SDimitry Andric   //   double x = 3.14;
310fe6060f1SDimitry Andric   //   auto s   = "Hello"
311fe6060f1SDimitry Andric   //          "World";
3125ffd83dbSDimitry Andric   // Special handling is required for 'nested' ternary operators.
3130b57cec5SDimitry Andric   SmallVector<unsigned, 16> ScopeStack;
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric   for (unsigned i = Start; i != End; ++i) {
3165f757f3fSDimitry Andric     auto &CurrentChange = Changes[i];
3170b57cec5SDimitry Andric     if (ScopeStack.size() != 0 &&
3185f757f3fSDimitry Andric         CurrentChange.indentAndNestingLevel() <
31981ad6265SDimitry Andric             Changes[ScopeStack.back()].indentAndNestingLevel()) {
3200b57cec5SDimitry Andric       ScopeStack.pop_back();
32181ad6265SDimitry Andric     }
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric     // Compare current token to previous non-comment token to ensure whether
3240b57cec5SDimitry Andric     // it is in a deeper scope or not.
3250b57cec5SDimitry Andric     unsigned PreviousNonComment = i - 1;
3260b57cec5SDimitry Andric     while (PreviousNonComment > Start &&
32781ad6265SDimitry Andric            Changes[PreviousNonComment].Tok->is(tok::comment)) {
32804eeddc0SDimitry Andric       --PreviousNonComment;
32981ad6265SDimitry Andric     }
3305f757f3fSDimitry Andric     if (i != Start && CurrentChange.indentAndNestingLevel() >
33181ad6265SDimitry Andric                           Changes[PreviousNonComment].indentAndNestingLevel()) {
3320b57cec5SDimitry Andric       ScopeStack.push_back(i);
33381ad6265SDimitry Andric     }
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric     bool InsideNestedScope = ScopeStack.size() != 0;
336fe6060f1SDimitry Andric     bool ContinuedStringLiteral = i > Start &&
3375f757f3fSDimitry Andric                                   CurrentChange.Tok->is(tok::string_literal) &&
338fe6060f1SDimitry Andric                                   Changes[i - 1].Tok->is(tok::string_literal);
339fe6060f1SDimitry Andric     bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral;
3400b57cec5SDimitry Andric 
3415f757f3fSDimitry Andric     if (CurrentChange.NewlinesBefore > 0 && !SkipMatchCheck) {
3420b57cec5SDimitry Andric       Shift = 0;
3430b57cec5SDimitry Andric       FoundMatchOnLine = false;
3440b57cec5SDimitry Andric     }
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric     // If this is the first matching token to be aligned, remember by how many
3470b57cec5SDimitry Andric     // spaces it has to be shifted, so the rest of the changes on the line are
3480b57cec5SDimitry Andric     // shifted by the same amount
3495f757f3fSDimitry Andric     if (!FoundMatchOnLine && !SkipMatchCheck && Matches(CurrentChange)) {
3500b57cec5SDimitry Andric       FoundMatchOnLine = true;
3515f757f3fSDimitry Andric       Shift = Column - (RightJustify ? CurrentChange.TokenLength : 0) -
3525f757f3fSDimitry Andric               CurrentChange.StartOfTokenColumn;
3535f757f3fSDimitry Andric       CurrentChange.Spaces += Shift;
35481ad6265SDimitry Andric       // FIXME: This is a workaround that should be removed when we fix
35581ad6265SDimitry Andric       // http://llvm.org/PR53699. An assertion later below verifies this.
3565f757f3fSDimitry Andric       if (CurrentChange.NewlinesBefore == 0) {
3575f757f3fSDimitry Andric         CurrentChange.Spaces =
3585f757f3fSDimitry Andric             std::max(CurrentChange.Spaces,
3595f757f3fSDimitry Andric                      static_cast<int>(CurrentChange.Tok->SpacesRequiredBefore));
36081ad6265SDimitry Andric       }
3610b57cec5SDimitry Andric     }
3620b57cec5SDimitry Andric 
3635f757f3fSDimitry Andric     if (Shift == 0)
3645f757f3fSDimitry Andric       continue;
3655f757f3fSDimitry Andric 
3660b57cec5SDimitry Andric     // This is for function parameters that are split across multiple lines,
3670b57cec5SDimitry Andric     // as mentioned in the ScopeStack comment.
3685f757f3fSDimitry Andric     if (InsideNestedScope && CurrentChange.NewlinesBefore > 0) {
3690b57cec5SDimitry Andric       unsigned ScopeStart = ScopeStack.back();
370fe6060f1SDimitry Andric       auto ShouldShiftBeAdded = [&] {
371fe6060f1SDimitry Andric         // Function declaration
372fe6060f1SDimitry Andric         if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName))
373fe6060f1SDimitry Andric           return true;
374fe6060f1SDimitry Andric 
3751fd87a68SDimitry Andric         // Lambda.
3761fd87a68SDimitry Andric         if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace))
3771fd87a68SDimitry Andric           return false;
3781fd87a68SDimitry Andric 
379fe6060f1SDimitry Andric         // Continued function declaration
380fe6060f1SDimitry Andric         if (ScopeStart > Start + 1 &&
38181ad6265SDimitry Andric             Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) {
382fe6060f1SDimitry Andric           return true;
38381ad6265SDimitry Andric         }
384fe6060f1SDimitry Andric 
3855f757f3fSDimitry Andric         // Continued (template) function call.
386fe6060f1SDimitry Andric         if (ScopeStart > Start + 1 &&
3875f757f3fSDimitry Andric             Changes[ScopeStart - 2].Tok->isOneOf(tok::identifier,
3885f757f3fSDimitry Andric                                                  TT_TemplateCloser) &&
3891fd87a68SDimitry Andric             Changes[ScopeStart - 1].Tok->is(tok::l_paren) &&
3901fd87a68SDimitry Andric             Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) {
3915f757f3fSDimitry Andric           if (CurrentChange.Tok->MatchingParen &&
3925f757f3fSDimitry Andric               CurrentChange.Tok->MatchingParen->is(TT_LambdaLBrace)) {
3931fd87a68SDimitry Andric             return false;
39481ad6265SDimitry Andric           }
39581ad6265SDimitry Andric           if (Changes[ScopeStart].NewlinesBefore > 0)
39681ad6265SDimitry Andric             return false;
3975f757f3fSDimitry Andric           if (CurrentChange.Tok->is(tok::l_brace) &&
3985f757f3fSDimitry Andric               CurrentChange.Tok->is(BK_BracedInit)) {
39981ad6265SDimitry Andric             return true;
40081ad6265SDimitry Andric           }
4016e75b2fbSDimitry Andric           return Style.BinPackArguments;
4021fd87a68SDimitry Andric         }
403fe6060f1SDimitry Andric 
404fe6060f1SDimitry Andric         // Ternary operator
4055f757f3fSDimitry Andric         if (CurrentChange.Tok->is(TT_ConditionalExpr))
406fe6060f1SDimitry Andric           return true;
407fe6060f1SDimitry Andric 
408fe6060f1SDimitry Andric         // Period Initializer .XXX = 1.
4095f757f3fSDimitry Andric         if (CurrentChange.Tok->is(TT_DesignatedInitializerPeriod))
410fe6060f1SDimitry Andric           return true;
411fe6060f1SDimitry Andric 
412fe6060f1SDimitry Andric         // Continued ternary operator
4135f757f3fSDimitry Andric         if (CurrentChange.Tok->Previous &&
4145f757f3fSDimitry Andric             CurrentChange.Tok->Previous->is(TT_ConditionalExpr)) {
415fe6060f1SDimitry Andric           return true;
41681ad6265SDimitry Andric         }
41781ad6265SDimitry Andric 
41881ad6265SDimitry Andric         // Continued direct-list-initialization using braced list.
41981ad6265SDimitry Andric         if (ScopeStart > Start + 1 &&
42081ad6265SDimitry Andric             Changes[ScopeStart - 2].Tok->is(tok::identifier) &&
42181ad6265SDimitry Andric             Changes[ScopeStart - 1].Tok->is(tok::l_brace) &&
4225f757f3fSDimitry Andric             CurrentChange.Tok->is(tok::l_brace) &&
4235f757f3fSDimitry Andric             CurrentChange.Tok->is(BK_BracedInit)) {
42481ad6265SDimitry Andric           return true;
42581ad6265SDimitry Andric         }
426fe6060f1SDimitry Andric 
42704eeddc0SDimitry Andric         // Continued braced list.
42804eeddc0SDimitry Andric         if (ScopeStart > Start + 1 &&
42904eeddc0SDimitry Andric             Changes[ScopeStart - 2].Tok->isNot(tok::identifier) &&
43004eeddc0SDimitry Andric             Changes[ScopeStart - 1].Tok->is(tok::l_brace) &&
4315f757f3fSDimitry Andric             CurrentChange.Tok->isNot(tok::r_brace)) {
4321fd87a68SDimitry Andric           for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) {
4331fd87a68SDimitry Andric             // Lambda.
4341fd87a68SDimitry Andric             if (OuterScopeStart > Start &&
43581ad6265SDimitry Andric                 Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) {
4361fd87a68SDimitry Andric               return false;
4371fd87a68SDimitry Andric             }
43881ad6265SDimitry Andric           }
43981ad6265SDimitry Andric           if (Changes[ScopeStart].NewlinesBefore > 0)
44081ad6265SDimitry Andric             return false;
44104eeddc0SDimitry Andric           return true;
4421fd87a68SDimitry Andric         }
44304eeddc0SDimitry Andric 
4445f757f3fSDimitry Andric         // Continued template parameter.
4455f757f3fSDimitry Andric         if (Changes[ScopeStart - 1].Tok->is(TT_TemplateOpener))
4465f757f3fSDimitry Andric           return true;
4475f757f3fSDimitry Andric 
448fe6060f1SDimitry Andric         return false;
449fe6060f1SDimitry Andric       };
450fe6060f1SDimitry Andric 
451fe6060f1SDimitry Andric       if (ShouldShiftBeAdded())
4525f757f3fSDimitry Andric         CurrentChange.Spaces += Shift;
4530b57cec5SDimitry Andric     }
4540b57cec5SDimitry Andric 
455fe6060f1SDimitry Andric     if (ContinuedStringLiteral)
4565f757f3fSDimitry Andric       CurrentChange.Spaces += Shift;
457fe6060f1SDimitry Andric 
45881ad6265SDimitry Andric     // We should not remove required spaces unless we break the line before.
4595f757f3fSDimitry Andric     assert(Shift > 0 || Changes[i].NewlinesBefore > 0 ||
4605f757f3fSDimitry Andric            CurrentChange.Spaces >=
46181ad6265SDimitry Andric                static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) ||
4625f757f3fSDimitry Andric            CurrentChange.Tok->is(tok::eof));
46381ad6265SDimitry Andric 
4645f757f3fSDimitry Andric     CurrentChange.StartOfTokenColumn += Shift;
4650b57cec5SDimitry Andric     if (i + 1 != Changes.size())
4660b57cec5SDimitry Andric       Changes[i + 1].PreviousEndOfTokenColumn += Shift;
467fe6060f1SDimitry Andric 
4680fca6ea1SDimitry Andric     // If PointerAlignment is PAS_Right, keep *s or &s next to the token,
4690fca6ea1SDimitry Andric     // except if the token is equal, then a space is needed.
47006c3fb27SDimitry Andric     if ((Style.PointerAlignment == FormatStyle::PAS_Right ||
47106c3fb27SDimitry Andric          Style.ReferenceAlignment == FormatStyle::RAS_Right) &&
472*6c4b055cSDimitry Andric         CurrentChange.Spaces != 0 &&
473*6c4b055cSDimitry Andric         !CurrentChange.Tok->isOneOf(tok::equal, tok::r_paren,
474*6c4b055cSDimitry Andric                                     TT_TemplateCloser)) {
47506c3fb27SDimitry Andric       const bool ReferenceNotRightAligned =
47606c3fb27SDimitry Andric           Style.ReferenceAlignment != FormatStyle::RAS_Right &&
47706c3fb27SDimitry Andric           Style.ReferenceAlignment != FormatStyle::RAS_Pointer;
478fe6060f1SDimitry Andric       for (int Previous = i - 1;
4790fca6ea1SDimitry Andric            Previous >= 0 && Changes[Previous].Tok->is(TT_PointerOrReference);
480fe6060f1SDimitry Andric            --Previous) {
4815f757f3fSDimitry Andric         assert(Changes[Previous].Tok->isPointerOrReference());
48206c3fb27SDimitry Andric         if (Changes[Previous].Tok->isNot(tok::star)) {
48306c3fb27SDimitry Andric           if (ReferenceNotRightAligned)
48406c3fb27SDimitry Andric             continue;
48506c3fb27SDimitry Andric         } else if (Style.PointerAlignment != FormatStyle::PAS_Right) {
48606c3fb27SDimitry Andric           continue;
48706c3fb27SDimitry Andric         }
488fe6060f1SDimitry Andric         Changes[Previous + 1].Spaces -= Shift;
489fe6060f1SDimitry Andric         Changes[Previous].Spaces += Shift;
49056f451bbSDimitry Andric         Changes[Previous].StartOfTokenColumn += Shift;
491fe6060f1SDimitry Andric       }
492fe6060f1SDimitry Andric     }
4930b57cec5SDimitry Andric   }
4940b57cec5SDimitry Andric }
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric // Walk through a subset of the changes, starting at StartAt, and find
4970b57cec5SDimitry Andric // sequences of matching tokens to align. To do so, keep track of the lines and
4980b57cec5SDimitry Andric // whether or not a matching token was found on a line. If a matching token is
4990b57cec5SDimitry Andric // found, extend the current sequence. If the current line cannot be part of a
5000b57cec5SDimitry Andric // sequence, e.g. because there is an empty line before it or it contains only
5010b57cec5SDimitry Andric // non-matching tokens, finalize the previous sequence.
5020b57cec5SDimitry Andric // The value returned is the token on which we stopped, either because we
5030b57cec5SDimitry Andric // exhausted all items inside Changes, or because we hit a scope level higher
5040b57cec5SDimitry Andric // than our initial scope.
5050b57cec5SDimitry Andric // This function is recursive. Each invocation processes only the scope level
5060b57cec5SDimitry Andric // equal to the initial level, which is the level of Changes[StartAt].
5070b57cec5SDimitry Andric // If we encounter a scope level greater than the initial level, then we call
5080b57cec5SDimitry Andric // ourselves recursively, thereby avoiding the pollution of the current state
5090b57cec5SDimitry Andric // with the alignment requirements of the nested sub-level. This recursive
5100b57cec5SDimitry Andric // behavior is necessary for aligning function prototypes that have one or more
5110b57cec5SDimitry Andric // arguments.
5120b57cec5SDimitry Andric // If this function encounters a scope level less than the initial level,
5130b57cec5SDimitry Andric // it returns the current position.
5140b57cec5SDimitry Andric // There is a non-obvious subtlety in the recursive behavior: Even though we
5150b57cec5SDimitry Andric // defer processing of nested levels to recursive invocations of this
5160b57cec5SDimitry Andric // function, when it comes time to align a sequence of tokens, we run the
5170b57cec5SDimitry Andric // alignment on the entire sequence, including the nested levels.
5180b57cec5SDimitry Andric // When doing so, most of the nested tokens are skipped, because their
5190b57cec5SDimitry Andric // alignment was already handled by the recursive invocations of this function.
5200b57cec5SDimitry Andric // However, the special exception is that we do NOT skip function parameters
5210b57cec5SDimitry Andric // that are split across multiple lines. See the test case in FormatTest.cpp
5220b57cec5SDimitry Andric // that mentions "split function parameter alignment" for an example of this.
52381ad6265SDimitry Andric // When the parameter RightJustify is true, the operator will be
52481ad6265SDimitry Andric // right-justified. It is used to align compound assignments like `+=` and `=`.
52581ad6265SDimitry Andric // When RightJustify and ACS.PadOperators are true, operators in each block to
52681ad6265SDimitry Andric // be aligned will be padded on the left to the same length before aligning.
5270b57cec5SDimitry Andric template <typename F>
52881ad6265SDimitry Andric static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
52981ad6265SDimitry Andric                             SmallVector<WhitespaceManager::Change, 16> &Changes,
53081ad6265SDimitry Andric                             unsigned StartAt,
53181ad6265SDimitry Andric                             const FormatStyle::AlignConsecutiveStyle &ACS = {},
53281ad6265SDimitry Andric                             bool RightJustify = false) {
53381ad6265SDimitry Andric   // We arrange each line in 3 parts. The operator to be aligned (the anchor),
53481ad6265SDimitry Andric   // and text to its left and right. In the aligned text the width of each part
53581ad6265SDimitry Andric   // will be the maximum of that over the block that has been aligned. Maximum
53681ad6265SDimitry Andric   // widths of each part so far. When RightJustify is true and ACS.PadOperators
53781ad6265SDimitry Andric   // is false, the part from start of line to the right end of the anchor.
53881ad6265SDimitry Andric   // Otherwise, only the part to the left of the anchor. Including the space
53981ad6265SDimitry Andric   // that exists on its left from the start. Not including the padding added on
54081ad6265SDimitry Andric   // the left to right-justify the anchor.
54181ad6265SDimitry Andric   unsigned WidthLeft = 0;
54281ad6265SDimitry Andric   // The operator to be aligned when RightJustify is true and ACS.PadOperators
54381ad6265SDimitry Andric   // is false. 0 otherwise.
54481ad6265SDimitry Andric   unsigned WidthAnchor = 0;
54581ad6265SDimitry Andric   // Width to the right of the anchor. Plus width of the anchor when
54681ad6265SDimitry Andric   // RightJustify is false.
54781ad6265SDimitry Andric   unsigned WidthRight = 0;
5480b57cec5SDimitry Andric 
5490b57cec5SDimitry Andric   // Line number of the start and the end of the current token sequence.
5500b57cec5SDimitry Andric   unsigned StartOfSequence = 0;
5510b57cec5SDimitry Andric   unsigned EndOfSequence = 0;
5520b57cec5SDimitry Andric 
5530b57cec5SDimitry Andric   // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
5540b57cec5SDimitry Andric   // abort when we hit any token in a higher scope than the starting one.
5550b57cec5SDimitry Andric   auto IndentAndNestingLevel = StartAt < Changes.size()
5560b57cec5SDimitry Andric                                    ? Changes[StartAt].indentAndNestingLevel()
5575ffd83dbSDimitry Andric                                    : std::tuple<unsigned, unsigned, unsigned>();
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric   // Keep track of the number of commas before the matching tokens, we will only
5600b57cec5SDimitry Andric   // align a sequence of matching tokens if they are preceded by the same number
5610b57cec5SDimitry Andric   // of commas.
5620b57cec5SDimitry Andric   unsigned CommasBeforeLastMatch = 0;
5630b57cec5SDimitry Andric   unsigned CommasBeforeMatch = 0;
5640b57cec5SDimitry Andric 
5650b57cec5SDimitry Andric   // Whether a matching token has been found on the current line.
5660b57cec5SDimitry Andric   bool FoundMatchOnLine = false;
5670b57cec5SDimitry Andric 
568e8d8bef9SDimitry Andric   // Whether the current line consists purely of comments.
569e8d8bef9SDimitry Andric   bool LineIsComment = true;
570e8d8bef9SDimitry Andric 
5710b57cec5SDimitry Andric   // Aligns a sequence of matching tokens, on the MinColumn column.
5720b57cec5SDimitry Andric   //
5730b57cec5SDimitry Andric   // Sequences start from the first matching token to align, and end at the
5740b57cec5SDimitry Andric   // first token of the first line that doesn't need to be aligned.
5750b57cec5SDimitry Andric   //
5760b57cec5SDimitry Andric   // We need to adjust the StartOfTokenColumn of each Change that is on a line
5770b57cec5SDimitry Andric   // containing any matching token to be aligned and located after such token.
5780b57cec5SDimitry Andric   auto AlignCurrentSequence = [&] {
57981ad6265SDimitry Andric     if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {
58081ad6265SDimitry Andric       AlignTokenSequence(Style, StartOfSequence, EndOfSequence,
58181ad6265SDimitry Andric                          WidthLeft + WidthAnchor, RightJustify, Matches,
58281ad6265SDimitry Andric                          Changes);
58381ad6265SDimitry Andric     }
58481ad6265SDimitry Andric     WidthLeft = 0;
58581ad6265SDimitry Andric     WidthAnchor = 0;
58681ad6265SDimitry Andric     WidthRight = 0;
5870b57cec5SDimitry Andric     StartOfSequence = 0;
5880b57cec5SDimitry Andric     EndOfSequence = 0;
5890b57cec5SDimitry Andric   };
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric   unsigned i = StartAt;
5920b57cec5SDimitry Andric   for (unsigned e = Changes.size(); i != e; ++i) {
5935f757f3fSDimitry Andric     auto &CurrentChange = Changes[i];
5945f757f3fSDimitry Andric     if (CurrentChange.indentAndNestingLevel() < IndentAndNestingLevel)
5950b57cec5SDimitry Andric       break;
5960b57cec5SDimitry Andric 
5975f757f3fSDimitry Andric     if (CurrentChange.NewlinesBefore != 0) {
5980b57cec5SDimitry Andric       CommasBeforeMatch = 0;
5990b57cec5SDimitry Andric       EndOfSequence = i;
600e8d8bef9SDimitry Andric 
601e8d8bef9SDimitry Andric       // Whether to break the alignment sequence because of an empty line.
602e8d8bef9SDimitry Andric       bool EmptyLineBreak =
6035f757f3fSDimitry Andric           (CurrentChange.NewlinesBefore > 1) && !ACS.AcrossEmptyLines;
604e8d8bef9SDimitry Andric 
605e8d8bef9SDimitry Andric       // Whether to break the alignment sequence because of a line without a
606e8d8bef9SDimitry Andric       // match.
607e8d8bef9SDimitry Andric       bool NoMatchBreak =
60881ad6265SDimitry Andric           !FoundMatchOnLine && !(LineIsComment && ACS.AcrossComments);
609e8d8bef9SDimitry Andric 
610e8d8bef9SDimitry Andric       if (EmptyLineBreak || NoMatchBreak)
6110b57cec5SDimitry Andric         AlignCurrentSequence();
6120b57cec5SDimitry Andric 
613e8d8bef9SDimitry Andric       // A new line starts, re-initialize line status tracking bools.
614fe6060f1SDimitry Andric       // Keep the match state if a string literal is continued on this line.
6155f757f3fSDimitry Andric       if (i == 0 || CurrentChange.Tok->isNot(tok::string_literal) ||
6165f757f3fSDimitry Andric           Changes[i - 1].Tok->isNot(tok::string_literal)) {
6170b57cec5SDimitry Andric         FoundMatchOnLine = false;
61881ad6265SDimitry Andric       }
619e8d8bef9SDimitry Andric       LineIsComment = true;
620e8d8bef9SDimitry Andric     }
621e8d8bef9SDimitry Andric 
6225f757f3fSDimitry Andric     if (CurrentChange.Tok->isNot(tok::comment))
623e8d8bef9SDimitry Andric       LineIsComment = false;
6240b57cec5SDimitry Andric 
6255f757f3fSDimitry Andric     if (CurrentChange.Tok->is(tok::comma)) {
6260b57cec5SDimitry Andric       ++CommasBeforeMatch;
6275f757f3fSDimitry Andric     } else if (CurrentChange.indentAndNestingLevel() > IndentAndNestingLevel) {
6280b57cec5SDimitry Andric       // Call AlignTokens recursively, skipping over this scope block.
629bdd1243dSDimitry Andric       unsigned StoppedAt =
630bdd1243dSDimitry Andric           AlignTokens(Style, Matches, Changes, i, ACS, RightJustify);
6310b57cec5SDimitry Andric       i = StoppedAt - 1;
6320b57cec5SDimitry Andric       continue;
6330b57cec5SDimitry Andric     }
6340b57cec5SDimitry Andric 
6355f757f3fSDimitry Andric     if (!Matches(CurrentChange))
6360b57cec5SDimitry Andric       continue;
6370b57cec5SDimitry Andric 
6380b57cec5SDimitry Andric     // If there is more than one matching token per line, or if the number of
6390b57cec5SDimitry Andric     // preceding commas, do not match anymore, end the sequence.
6400b57cec5SDimitry Andric     if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)
6410b57cec5SDimitry Andric       AlignCurrentSequence();
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric     CommasBeforeLastMatch = CommasBeforeMatch;
6440b57cec5SDimitry Andric     FoundMatchOnLine = true;
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric     if (StartOfSequence == 0)
6470b57cec5SDimitry Andric       StartOfSequence = i;
6480b57cec5SDimitry Andric 
6495f757f3fSDimitry Andric     unsigned ChangeWidthLeft = CurrentChange.StartOfTokenColumn;
65081ad6265SDimitry Andric     unsigned ChangeWidthAnchor = 0;
65181ad6265SDimitry Andric     unsigned ChangeWidthRight = 0;
65281ad6265SDimitry Andric     if (RightJustify)
65381ad6265SDimitry Andric       if (ACS.PadOperators)
6545f757f3fSDimitry Andric         ChangeWidthAnchor = CurrentChange.TokenLength;
65581ad6265SDimitry Andric       else
6565f757f3fSDimitry Andric         ChangeWidthLeft += CurrentChange.TokenLength;
65781ad6265SDimitry Andric     else
6585f757f3fSDimitry Andric       ChangeWidthRight = CurrentChange.TokenLength;
6595ffd83dbSDimitry Andric     for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 0; ++j) {
66081ad6265SDimitry Andric       ChangeWidthRight += Changes[j].Spaces;
6615ffd83dbSDimitry Andric       // Changes are generally 1:1 with the tokens, but a change could also be
6625ffd83dbSDimitry Andric       // inside of a token, in which case it's counted more than once: once for
6635ffd83dbSDimitry Andric       // the whitespace surrounding the token (!IsInsideToken) and once for
6645ffd83dbSDimitry Andric       // each whitespace change within it (IsInsideToken).
6655ffd83dbSDimitry Andric       // Therefore, changes inside of a token should only count the space.
6665ffd83dbSDimitry Andric       if (!Changes[j].IsInsideToken)
66781ad6265SDimitry Andric         ChangeWidthRight += Changes[j].TokenLength;
6685ffd83dbSDimitry Andric     }
6690b57cec5SDimitry Andric 
6700b57cec5SDimitry Andric     // If we are restricted by the maximum column width, end the sequence.
67181ad6265SDimitry Andric     unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft);
67281ad6265SDimitry Andric     unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor);
67381ad6265SDimitry Andric     unsigned NewRight = std::max(ChangeWidthRight, WidthRight);
67481ad6265SDimitry Andric     // `ColumnLimit == 0` means there is no column limit.
67581ad6265SDimitry Andric     if (Style.ColumnLimit != 0 &&
67681ad6265SDimitry Andric         Style.ColumnLimit < NewLeft + NewAnchor + NewRight) {
6770b57cec5SDimitry Andric       AlignCurrentSequence();
6780b57cec5SDimitry Andric       StartOfSequence = i;
67981ad6265SDimitry Andric       WidthLeft = ChangeWidthLeft;
68081ad6265SDimitry Andric       WidthAnchor = ChangeWidthAnchor;
68181ad6265SDimitry Andric       WidthRight = ChangeWidthRight;
68281ad6265SDimitry Andric     } else {
68381ad6265SDimitry Andric       WidthLeft = NewLeft;
68481ad6265SDimitry Andric       WidthAnchor = NewAnchor;
68581ad6265SDimitry Andric       WidthRight = NewRight;
6860b57cec5SDimitry Andric     }
6870b57cec5SDimitry Andric   }
6880b57cec5SDimitry Andric 
6890b57cec5SDimitry Andric   EndOfSequence = i;
6900b57cec5SDimitry Andric   AlignCurrentSequence();
6910b57cec5SDimitry Andric   return i;
6920b57cec5SDimitry Andric }
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric // Aligns a sequence of matching tokens, on the MinColumn column.
6950b57cec5SDimitry Andric //
6960b57cec5SDimitry Andric // Sequences start from the first matching token to align, and end at the
6970b57cec5SDimitry Andric // first token of the first line that doesn't need to be aligned.
6980b57cec5SDimitry Andric //
6990b57cec5SDimitry Andric // We need to adjust the StartOfTokenColumn of each Change that is on a line
7000b57cec5SDimitry Andric // containing any matching token to be aligned and located after such token.
70106c3fb27SDimitry Andric static void AlignMatchingTokenSequence(
7020b57cec5SDimitry Andric     unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn,
70306c3fb27SDimitry Andric     std::function<bool(const WhitespaceManager::Change &C)> Matches,
7040b57cec5SDimitry Andric     SmallVector<WhitespaceManager::Change, 16> &Changes) {
7050b57cec5SDimitry Andric   if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {
70606c3fb27SDimitry Andric     bool FoundMatchOnLine = false;
7070b57cec5SDimitry Andric     int Shift = 0;
7080b57cec5SDimitry Andric 
7090b57cec5SDimitry Andric     for (unsigned I = StartOfSequence; I != EndOfSequence; ++I) {
7100b57cec5SDimitry Andric       if (Changes[I].NewlinesBefore > 0) {
7110b57cec5SDimitry Andric         Shift = 0;
7120b57cec5SDimitry Andric         FoundMatchOnLine = false;
7130b57cec5SDimitry Andric       }
7140b57cec5SDimitry Andric 
7150b57cec5SDimitry Andric       // If this is the first matching token to be aligned, remember by how many
7160b57cec5SDimitry Andric       // spaces it has to be shifted, so the rest of the changes on the line are
71706c3fb27SDimitry Andric       // shifted by the same amount.
71806c3fb27SDimitry Andric       if (!FoundMatchOnLine && Matches(Changes[I])) {
7190b57cec5SDimitry Andric         FoundMatchOnLine = true;
7200b57cec5SDimitry Andric         Shift = MinColumn - Changes[I].StartOfTokenColumn;
7210b57cec5SDimitry Andric         Changes[I].Spaces += Shift;
7220b57cec5SDimitry Andric       }
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric       assert(Shift >= 0);
7250b57cec5SDimitry Andric       Changes[I].StartOfTokenColumn += Shift;
7260b57cec5SDimitry Andric       if (I + 1 != Changes.size())
7270b57cec5SDimitry Andric         Changes[I + 1].PreviousEndOfTokenColumn += Shift;
7280b57cec5SDimitry Andric     }
7290b57cec5SDimitry Andric   }
7300b57cec5SDimitry Andric 
7310b57cec5SDimitry Andric   MinColumn = 0;
7320b57cec5SDimitry Andric   StartOfSequence = 0;
7330b57cec5SDimitry Andric   EndOfSequence = 0;
7340b57cec5SDimitry Andric }
7350b57cec5SDimitry Andric 
7360b57cec5SDimitry Andric void WhitespaceManager::alignConsecutiveMacros() {
73781ad6265SDimitry Andric   if (!Style.AlignConsecutiveMacros.Enabled)
7380b57cec5SDimitry Andric     return;
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric   auto AlignMacrosMatches = [](const Change &C) {
7410b57cec5SDimitry Andric     const FormatToken *Current = C.Tok;
7420b57cec5SDimitry Andric     unsigned SpacesRequiredBefore = 1;
7430b57cec5SDimitry Andric 
7440b57cec5SDimitry Andric     if (Current->SpacesRequiredBefore == 0 || !Current->Previous)
7450b57cec5SDimitry Andric       return false;
7460b57cec5SDimitry Andric 
7470b57cec5SDimitry Andric     Current = Current->Previous;
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric     // If token is a ")", skip over the parameter list, to the
7500b57cec5SDimitry Andric     // token that precedes the "("
7510b57cec5SDimitry Andric     if (Current->is(tok::r_paren) && Current->MatchingParen) {
7520b57cec5SDimitry Andric       Current = Current->MatchingParen->Previous;
7530b57cec5SDimitry Andric       SpacesRequiredBefore = 0;
7540b57cec5SDimitry Andric     }
7550b57cec5SDimitry Andric 
7565f757f3fSDimitry Andric     if (!Current || Current->isNot(tok::identifier))
7570b57cec5SDimitry Andric       return false;
7580b57cec5SDimitry Andric 
7595f757f3fSDimitry Andric     if (!Current->Previous || Current->Previous->isNot(tok::pp_define))
7600b57cec5SDimitry Andric       return false;
7610b57cec5SDimitry Andric 
7620b57cec5SDimitry Andric     // For a macro function, 0 spaces are required between the
7630b57cec5SDimitry Andric     // identifier and the lparen that opens the parameter list.
7640b57cec5SDimitry Andric     // For a simple macro, 1 space is required between the
7650b57cec5SDimitry Andric     // identifier and the first token of the defined value.
7660b57cec5SDimitry Andric     return Current->Next->SpacesRequiredBefore == SpacesRequiredBefore;
7670b57cec5SDimitry Andric   };
7680b57cec5SDimitry Andric 
7690b57cec5SDimitry Andric   unsigned MinColumn = 0;
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric   // Start and end of the token sequence we're processing.
7720b57cec5SDimitry Andric   unsigned StartOfSequence = 0;
7730b57cec5SDimitry Andric   unsigned EndOfSequence = 0;
7740b57cec5SDimitry Andric 
7750b57cec5SDimitry Andric   // Whether a matching token has been found on the current line.
7760b57cec5SDimitry Andric   bool FoundMatchOnLine = false;
7770b57cec5SDimitry Andric 
778e8d8bef9SDimitry Andric   // Whether the current line consists only of comments
779e8d8bef9SDimitry Andric   bool LineIsComment = true;
780e8d8bef9SDimitry Andric 
7810b57cec5SDimitry Andric   unsigned I = 0;
7820b57cec5SDimitry Andric   for (unsigned E = Changes.size(); I != E; ++I) {
7830b57cec5SDimitry Andric     if (Changes[I].NewlinesBefore != 0) {
7840b57cec5SDimitry Andric       EndOfSequence = I;
785e8d8bef9SDimitry Andric 
786e8d8bef9SDimitry Andric       // Whether to break the alignment sequence because of an empty line.
78781ad6265SDimitry Andric       bool EmptyLineBreak = (Changes[I].NewlinesBefore > 1) &&
78881ad6265SDimitry Andric                             !Style.AlignConsecutiveMacros.AcrossEmptyLines;
789e8d8bef9SDimitry Andric 
790e8d8bef9SDimitry Andric       // Whether to break the alignment sequence because of a line without a
791e8d8bef9SDimitry Andric       // match.
792e8d8bef9SDimitry Andric       bool NoMatchBreak =
793e8d8bef9SDimitry Andric           !FoundMatchOnLine &&
79481ad6265SDimitry Andric           !(LineIsComment && Style.AlignConsecutiveMacros.AcrossComments);
795e8d8bef9SDimitry Andric 
79681ad6265SDimitry Andric       if (EmptyLineBreak || NoMatchBreak) {
79706c3fb27SDimitry Andric         AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
79806c3fb27SDimitry Andric                                    AlignMacrosMatches, Changes);
79981ad6265SDimitry Andric       }
8000b57cec5SDimitry Andric 
801e8d8bef9SDimitry Andric       // A new line starts, re-initialize line status tracking bools.
8020b57cec5SDimitry Andric       FoundMatchOnLine = false;
803e8d8bef9SDimitry Andric       LineIsComment = true;
804e8d8bef9SDimitry Andric     }
805e8d8bef9SDimitry Andric 
8065f757f3fSDimitry Andric     if (Changes[I].Tok->isNot(tok::comment))
807e8d8bef9SDimitry Andric       LineIsComment = false;
8080b57cec5SDimitry Andric 
8090b57cec5SDimitry Andric     if (!AlignMacrosMatches(Changes[I]))
8100b57cec5SDimitry Andric       continue;
8110b57cec5SDimitry Andric 
8120b57cec5SDimitry Andric     FoundMatchOnLine = true;
8130b57cec5SDimitry Andric 
8140b57cec5SDimitry Andric     if (StartOfSequence == 0)
8150b57cec5SDimitry Andric       StartOfSequence = I;
8160b57cec5SDimitry Andric 
8170b57cec5SDimitry Andric     unsigned ChangeMinColumn = Changes[I].StartOfTokenColumn;
8180b57cec5SDimitry Andric     MinColumn = std::max(MinColumn, ChangeMinColumn);
8190b57cec5SDimitry Andric   }
8200b57cec5SDimitry Andric 
8210b57cec5SDimitry Andric   EndOfSequence = I;
82206c3fb27SDimitry Andric   AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
82306c3fb27SDimitry Andric                              AlignMacrosMatches, Changes);
8240b57cec5SDimitry Andric }
8250b57cec5SDimitry Andric 
8260b57cec5SDimitry Andric void WhitespaceManager::alignConsecutiveAssignments() {
82781ad6265SDimitry Andric   if (!Style.AlignConsecutiveAssignments.Enabled)
8280b57cec5SDimitry Andric     return;
8290b57cec5SDimitry Andric 
8300b57cec5SDimitry Andric   AlignTokens(
8310b57cec5SDimitry Andric       Style,
8320b57cec5SDimitry Andric       [&](const Change &C) {
8330b57cec5SDimitry Andric         // Do not align on equal signs that are first on a line.
8340b57cec5SDimitry Andric         if (C.NewlinesBefore > 0)
8350b57cec5SDimitry Andric           return false;
8360b57cec5SDimitry Andric 
8370b57cec5SDimitry Andric         // Do not align on equal signs that are last on a line.
8380b57cec5SDimitry Andric         if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
8390b57cec5SDimitry Andric           return false;
8400b57cec5SDimitry Andric 
84104eeddc0SDimitry Andric         // Do not align operator= overloads.
84204eeddc0SDimitry Andric         FormatToken *Previous = C.Tok->getPreviousNonComment();
84304eeddc0SDimitry Andric         if (Previous && Previous->is(tok::kw_operator))
84404eeddc0SDimitry Andric           return false;
84504eeddc0SDimitry Andric 
84681ad6265SDimitry Andric         return Style.AlignConsecutiveAssignments.AlignCompound
84781ad6265SDimitry Andric                    ? C.Tok->getPrecedence() == prec::Assignment
84806c3fb27SDimitry Andric                    : (C.Tok->is(tok::equal) ||
84906c3fb27SDimitry Andric                       // In Verilog the '<=' is not a compound assignment, thus
85006c3fb27SDimitry Andric                       // it is aligned even when the AlignCompound option is not
85106c3fb27SDimitry Andric                       // set.
85206c3fb27SDimitry Andric                       (Style.isVerilog() && C.Tok->is(tok::lessequal) &&
85306c3fb27SDimitry Andric                        C.Tok->getPrecedence() == prec::Assignment));
8540b57cec5SDimitry Andric       },
85581ad6265SDimitry Andric       Changes, /*StartAt=*/0, Style.AlignConsecutiveAssignments,
85681ad6265SDimitry Andric       /*RightJustify=*/true);
8570b57cec5SDimitry Andric }
8580b57cec5SDimitry Andric 
8595ffd83dbSDimitry Andric void WhitespaceManager::alignConsecutiveBitFields() {
8600fca6ea1SDimitry Andric   alignConsecutiveColons(Style.AlignConsecutiveBitFields, TT_BitFieldColon);
8610fca6ea1SDimitry Andric }
8620fca6ea1SDimitry Andric 
8630fca6ea1SDimitry Andric void WhitespaceManager::alignConsecutiveColons(
8640fca6ea1SDimitry Andric     const FormatStyle::AlignConsecutiveStyle &AlignStyle, TokenType Type) {
8650fca6ea1SDimitry Andric   if (!AlignStyle.Enabled)
8665ffd83dbSDimitry Andric     return;
8675ffd83dbSDimitry Andric 
8685ffd83dbSDimitry Andric   AlignTokens(
8695ffd83dbSDimitry Andric       Style,
8705ffd83dbSDimitry Andric       [&](Change const &C) {
8715ffd83dbSDimitry Andric         // Do not align on ':' that is first on a line.
8725ffd83dbSDimitry Andric         if (C.NewlinesBefore > 0)
8735ffd83dbSDimitry Andric           return false;
8745ffd83dbSDimitry Andric 
8755ffd83dbSDimitry Andric         // Do not align on ':' that is last on a line.
8765ffd83dbSDimitry Andric         if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
8775ffd83dbSDimitry Andric           return false;
8785ffd83dbSDimitry Andric 
8790fca6ea1SDimitry Andric         return C.Tok->is(Type);
8805ffd83dbSDimitry Andric       },
8810fca6ea1SDimitry Andric       Changes, /*StartAt=*/0, AlignStyle);
8825ffd83dbSDimitry Andric }
8835ffd83dbSDimitry Andric 
8840fca6ea1SDimitry Andric void WhitespaceManager::alignConsecutiveShortCaseStatements(bool IsExpr) {
88506c3fb27SDimitry Andric   if (!Style.AlignConsecutiveShortCaseStatements.Enabled ||
8860fca6ea1SDimitry Andric       !(IsExpr ? Style.AllowShortCaseExpressionOnASingleLine
8870fca6ea1SDimitry Andric                : Style.AllowShortCaseLabelsOnASingleLine)) {
88806c3fb27SDimitry Andric     return;
88906c3fb27SDimitry Andric   }
89006c3fb27SDimitry Andric 
8910fca6ea1SDimitry Andric   const auto Type = IsExpr ? TT_CaseLabelArrow : TT_CaseLabelColon;
8920fca6ea1SDimitry Andric   const auto &Option = Style.AlignConsecutiveShortCaseStatements;
8930fca6ea1SDimitry Andric   const bool AlignArrowOrColon =
8940fca6ea1SDimitry Andric       IsExpr ? Option.AlignCaseArrows : Option.AlignCaseColons;
8950fca6ea1SDimitry Andric 
89606c3fb27SDimitry Andric   auto Matches = [&](const Change &C) {
8970fca6ea1SDimitry Andric     if (AlignArrowOrColon)
8980fca6ea1SDimitry Andric       return C.Tok->is(Type);
89906c3fb27SDimitry Andric 
90006c3fb27SDimitry Andric     // Ignore 'IsInsideToken' to allow matching trailing comments which
90106c3fb27SDimitry Andric     // need to be reflowed as that causes the token to appear in two
90206c3fb27SDimitry Andric     // different changes, which will cause incorrect alignment as we'll
90306c3fb27SDimitry Andric     // reflow early due to detecting multiple aligning tokens per line.
9040fca6ea1SDimitry Andric     return !C.IsInsideToken && C.Tok->Previous && C.Tok->Previous->is(Type);
90506c3fb27SDimitry Andric   };
90606c3fb27SDimitry Andric 
90706c3fb27SDimitry Andric   unsigned MinColumn = 0;
90806c3fb27SDimitry Andric 
90906c3fb27SDimitry Andric   // Empty case statements don't break the alignment, but don't necessarily
91006c3fb27SDimitry Andric   // match our predicate, so we need to track their column so they can push out
91106c3fb27SDimitry Andric   // our alignment.
91206c3fb27SDimitry Andric   unsigned MinEmptyCaseColumn = 0;
91306c3fb27SDimitry Andric 
91406c3fb27SDimitry Andric   // Start and end of the token sequence we're processing.
91506c3fb27SDimitry Andric   unsigned StartOfSequence = 0;
91606c3fb27SDimitry Andric   unsigned EndOfSequence = 0;
91706c3fb27SDimitry Andric 
91806c3fb27SDimitry Andric   // Whether a matching token has been found on the current line.
91906c3fb27SDimitry Andric   bool FoundMatchOnLine = false;
92006c3fb27SDimitry Andric 
92106c3fb27SDimitry Andric   bool LineIsComment = true;
92206c3fb27SDimitry Andric   bool LineIsEmptyCase = false;
92306c3fb27SDimitry Andric 
92406c3fb27SDimitry Andric   unsigned I = 0;
92506c3fb27SDimitry Andric   for (unsigned E = Changes.size(); I != E; ++I) {
92606c3fb27SDimitry Andric     if (Changes[I].NewlinesBefore != 0) {
92706c3fb27SDimitry Andric       // Whether to break the alignment sequence because of an empty line.
92806c3fb27SDimitry Andric       bool EmptyLineBreak =
92906c3fb27SDimitry Andric           (Changes[I].NewlinesBefore > 1) &&
93006c3fb27SDimitry Andric           !Style.AlignConsecutiveShortCaseStatements.AcrossEmptyLines;
93106c3fb27SDimitry Andric 
93206c3fb27SDimitry Andric       // Whether to break the alignment sequence because of a line without a
93306c3fb27SDimitry Andric       // match.
93406c3fb27SDimitry Andric       bool NoMatchBreak =
93506c3fb27SDimitry Andric           !FoundMatchOnLine &&
93606c3fb27SDimitry Andric           !(LineIsComment &&
93706c3fb27SDimitry Andric             Style.AlignConsecutiveShortCaseStatements.AcrossComments) &&
93806c3fb27SDimitry Andric           !LineIsEmptyCase;
93906c3fb27SDimitry Andric 
94006c3fb27SDimitry Andric       if (EmptyLineBreak || NoMatchBreak) {
94106c3fb27SDimitry Andric         AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
94206c3fb27SDimitry Andric                                    Matches, Changes);
94306c3fb27SDimitry Andric         MinEmptyCaseColumn = 0;
94406c3fb27SDimitry Andric       }
94506c3fb27SDimitry Andric 
94606c3fb27SDimitry Andric       // A new line starts, re-initialize line status tracking bools.
94706c3fb27SDimitry Andric       FoundMatchOnLine = false;
94806c3fb27SDimitry Andric       LineIsComment = true;
94906c3fb27SDimitry Andric       LineIsEmptyCase = false;
95006c3fb27SDimitry Andric     }
95106c3fb27SDimitry Andric 
95206c3fb27SDimitry Andric     if (Changes[I].Tok->isNot(tok::comment))
95306c3fb27SDimitry Andric       LineIsComment = false;
95406c3fb27SDimitry Andric 
9550fca6ea1SDimitry Andric     if (Changes[I].Tok->is(Type)) {
95606c3fb27SDimitry Andric       LineIsEmptyCase =
95706c3fb27SDimitry Andric           !Changes[I].Tok->Next || Changes[I].Tok->Next->isTrailingComment();
95806c3fb27SDimitry Andric 
95906c3fb27SDimitry Andric       if (LineIsEmptyCase) {
96006c3fb27SDimitry Andric         if (Style.AlignConsecutiveShortCaseStatements.AlignCaseColons) {
96106c3fb27SDimitry Andric           MinEmptyCaseColumn =
96206c3fb27SDimitry Andric               std::max(MinEmptyCaseColumn, Changes[I].StartOfTokenColumn);
96306c3fb27SDimitry Andric         } else {
96406c3fb27SDimitry Andric           MinEmptyCaseColumn =
96506c3fb27SDimitry Andric               std::max(MinEmptyCaseColumn, Changes[I].StartOfTokenColumn + 2);
96606c3fb27SDimitry Andric         }
96706c3fb27SDimitry Andric       }
96806c3fb27SDimitry Andric     }
96906c3fb27SDimitry Andric 
97006c3fb27SDimitry Andric     if (!Matches(Changes[I]))
97106c3fb27SDimitry Andric       continue;
97206c3fb27SDimitry Andric 
97306c3fb27SDimitry Andric     if (LineIsEmptyCase)
97406c3fb27SDimitry Andric       continue;
97506c3fb27SDimitry Andric 
97606c3fb27SDimitry Andric     FoundMatchOnLine = true;
97706c3fb27SDimitry Andric 
97806c3fb27SDimitry Andric     if (StartOfSequence == 0)
97906c3fb27SDimitry Andric       StartOfSequence = I;
98006c3fb27SDimitry Andric 
98106c3fb27SDimitry Andric     EndOfSequence = I + 1;
98206c3fb27SDimitry Andric 
98306c3fb27SDimitry Andric     MinColumn = std::max(MinColumn, Changes[I].StartOfTokenColumn);
98406c3fb27SDimitry Andric 
98506c3fb27SDimitry Andric     // Allow empty case statements to push out our alignment.
98606c3fb27SDimitry Andric     MinColumn = std::max(MinColumn, MinEmptyCaseColumn);
98706c3fb27SDimitry Andric   }
98806c3fb27SDimitry Andric 
98906c3fb27SDimitry Andric   AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
99006c3fb27SDimitry Andric                              Changes);
99106c3fb27SDimitry Andric }
99206c3fb27SDimitry Andric 
9930fca6ea1SDimitry Andric void WhitespaceManager::alignConsecutiveTableGenBreakingDAGArgColons() {
9940fca6ea1SDimitry Andric   alignConsecutiveColons(Style.AlignConsecutiveTableGenBreakingDAGArgColons,
9950fca6ea1SDimitry Andric                          TT_TableGenDAGArgListColonToAlign);
9960fca6ea1SDimitry Andric }
9970fca6ea1SDimitry Andric 
9980fca6ea1SDimitry Andric void WhitespaceManager::alignConsecutiveTableGenCondOperatorColons() {
9990fca6ea1SDimitry Andric   alignConsecutiveColons(Style.AlignConsecutiveTableGenCondOperatorColons,
10000fca6ea1SDimitry Andric                          TT_TableGenCondOperatorColon);
10010fca6ea1SDimitry Andric }
10020fca6ea1SDimitry Andric 
10030fca6ea1SDimitry Andric void WhitespaceManager::alignConsecutiveTableGenDefinitions() {
10040fca6ea1SDimitry Andric   alignConsecutiveColons(Style.AlignConsecutiveTableGenDefinitionColons,
10050fca6ea1SDimitry Andric                          TT_InheritanceColon);
10060fca6ea1SDimitry Andric }
10070fca6ea1SDimitry Andric 
10080b57cec5SDimitry Andric void WhitespaceManager::alignConsecutiveDeclarations() {
100981ad6265SDimitry Andric   if (!Style.AlignConsecutiveDeclarations.Enabled)
10100b57cec5SDimitry Andric     return;
10110b57cec5SDimitry Andric 
10120b57cec5SDimitry Andric   AlignTokens(
10130b57cec5SDimitry Andric       Style,
1014297eecfbSDimitry Andric       [&](Change const &C) {
1015297eecfbSDimitry Andric         if (Style.AlignConsecutiveDeclarations.AlignFunctionPointers) {
1016297eecfbSDimitry Andric           for (const auto *Prev = C.Tok->Previous; Prev; Prev = Prev->Previous)
1017297eecfbSDimitry Andric             if (Prev->is(tok::equal))
1018297eecfbSDimitry Andric               return false;
1019297eecfbSDimitry Andric           if (C.Tok->is(TT_FunctionTypeLParen))
1020297eecfbSDimitry Andric             return true;
1021297eecfbSDimitry Andric         }
1022b121cb00SDimitry Andric         if (C.Tok->is(TT_FunctionDeclarationName))
10230b57cec5SDimitry Andric           return true;
10240b57cec5SDimitry Andric         if (C.Tok->isNot(TT_StartOfName))
10250b57cec5SDimitry Andric           return false;
1026e8d8bef9SDimitry Andric         if (C.Tok->Previous &&
1027e8d8bef9SDimitry Andric             C.Tok->Previous->is(TT_StatementAttributeLikeMacro))
1028e8d8bef9SDimitry Andric           return false;
10290b57cec5SDimitry Andric         // Check if there is a subsequent name that starts the same declaration.
10300b57cec5SDimitry Andric         for (FormatToken *Next = C.Tok->Next; Next; Next = Next->Next) {
10310b57cec5SDimitry Andric           if (Next->is(tok::comment))
10320b57cec5SDimitry Andric             continue;
1033fe6060f1SDimitry Andric           if (Next->is(TT_PointerOrReference))
1034fe6060f1SDimitry Andric             return false;
10350b57cec5SDimitry Andric           if (!Next->Tok.getIdentifierInfo())
10360b57cec5SDimitry Andric             break;
10370b57cec5SDimitry Andric           if (Next->isOneOf(TT_StartOfName, TT_FunctionDeclarationName,
103881ad6265SDimitry Andric                             tok::kw_operator)) {
10390b57cec5SDimitry Andric             return false;
10400b57cec5SDimitry Andric           }
104181ad6265SDimitry Andric         }
10420b57cec5SDimitry Andric         return true;
10430b57cec5SDimitry Andric       },
1044e8d8bef9SDimitry Andric       Changes, /*StartAt=*/0, Style.AlignConsecutiveDeclarations);
10450b57cec5SDimitry Andric }
10460b57cec5SDimitry Andric 
10475ffd83dbSDimitry Andric void WhitespaceManager::alignChainedConditionals() {
10485ffd83dbSDimitry Andric   if (Style.BreakBeforeTernaryOperators) {
10495ffd83dbSDimitry Andric     AlignTokens(
10505ffd83dbSDimitry Andric         Style,
10515ffd83dbSDimitry Andric         [](Change const &C) {
10525ffd83dbSDimitry Andric           // Align question operators and last colon
10535ffd83dbSDimitry Andric           return C.Tok->is(TT_ConditionalExpr) &&
10545ffd83dbSDimitry Andric                  ((C.Tok->is(tok::question) && !C.NewlinesBefore) ||
10555ffd83dbSDimitry Andric                   (C.Tok->is(tok::colon) && C.Tok->Next &&
10565ffd83dbSDimitry Andric                    (C.Tok->Next->FakeLParens.size() == 0 ||
10575ffd83dbSDimitry Andric                     C.Tok->Next->FakeLParens.back() != prec::Conditional)));
10585ffd83dbSDimitry Andric         },
10595ffd83dbSDimitry Andric         Changes, /*StartAt=*/0);
10605ffd83dbSDimitry Andric   } else {
10615ffd83dbSDimitry Andric     static auto AlignWrappedOperand = [](Change const &C) {
1062fe6060f1SDimitry Andric       FormatToken *Previous = C.Tok->getPreviousNonComment();
10635ffd83dbSDimitry Andric       return C.NewlinesBefore && Previous && Previous->is(TT_ConditionalExpr) &&
10645ffd83dbSDimitry Andric              (Previous->is(tok::colon) &&
10655ffd83dbSDimitry Andric               (C.Tok->FakeLParens.size() == 0 ||
1066fe6060f1SDimitry Andric                C.Tok->FakeLParens.back() != prec::Conditional));
10675ffd83dbSDimitry Andric     };
10685ffd83dbSDimitry Andric     // Ensure we keep alignment of wrapped operands with non-wrapped operands
10695ffd83dbSDimitry Andric     // Since we actually align the operators, the wrapped operands need the
10705ffd83dbSDimitry Andric     // extra offset to be properly aligned.
107181ad6265SDimitry Andric     for (Change &C : Changes)
10725ffd83dbSDimitry Andric       if (AlignWrappedOperand(C))
10735ffd83dbSDimitry Andric         C.StartOfTokenColumn -= 2;
10745ffd83dbSDimitry Andric     AlignTokens(
10755ffd83dbSDimitry Andric         Style,
10765ffd83dbSDimitry Andric         [this](Change const &C) {
10775ffd83dbSDimitry Andric           // Align question operators if next operand is not wrapped, as
10785ffd83dbSDimitry Andric           // well as wrapped operands after question operator or last
10795ffd83dbSDimitry Andric           // colon in conditional sequence
10805ffd83dbSDimitry Andric           return (C.Tok->is(TT_ConditionalExpr) && C.Tok->is(tok::question) &&
10815ffd83dbSDimitry Andric                   &C != &Changes.back() && (&C + 1)->NewlinesBefore == 0 &&
10825ffd83dbSDimitry Andric                   !(&C + 1)->IsTrailingComment) ||
10835ffd83dbSDimitry Andric                  AlignWrappedOperand(C);
10845ffd83dbSDimitry Andric         },
10855ffd83dbSDimitry Andric         Changes, /*StartAt=*/0);
10865ffd83dbSDimitry Andric   }
10875ffd83dbSDimitry Andric }
10885ffd83dbSDimitry Andric 
10890b57cec5SDimitry Andric void WhitespaceManager::alignTrailingComments() {
10905f757f3fSDimitry Andric   if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Never)
10915f757f3fSDimitry Andric     return;
10925f757f3fSDimitry Andric 
10935f757f3fSDimitry Andric   const int Size = Changes.size();
10945f757f3fSDimitry Andric   int MinColumn = 0;
10955f757f3fSDimitry Andric   int StartOfSequence = 0;
10960b57cec5SDimitry Andric   bool BreakBeforeNext = false;
10975f757f3fSDimitry Andric   int NewLineThreshold = 1;
1098bdd1243dSDimitry Andric   if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Always)
1099bdd1243dSDimitry Andric     NewLineThreshold = Style.AlignTrailingComments.OverEmptyLines + 1;
1100bdd1243dSDimitry Andric 
11015f757f3fSDimitry Andric   for (int I = 0, MaxColumn = INT_MAX, Newlines = 0; I < Size; ++I) {
11025f757f3fSDimitry Andric     auto &C = Changes[I];
11035f757f3fSDimitry Andric     if (C.StartOfBlockComment)
11040b57cec5SDimitry Andric       continue;
11055f757f3fSDimitry Andric     Newlines += C.NewlinesBefore;
11065f757f3fSDimitry Andric     if (!C.IsTrailingComment)
11070b57cec5SDimitry Andric       continue;
11080b57cec5SDimitry Andric 
1109bdd1243dSDimitry Andric     if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Leave) {
11105f757f3fSDimitry Andric       const int OriginalSpaces =
11115f757f3fSDimitry Andric           C.OriginalWhitespaceRange.getEnd().getRawEncoding() -
11125f757f3fSDimitry Andric           C.OriginalWhitespaceRange.getBegin().getRawEncoding() -
11135f757f3fSDimitry Andric           C.Tok->LastNewlineOffset;
11145f757f3fSDimitry Andric       assert(OriginalSpaces >= 0);
11155f757f3fSDimitry Andric       const auto RestoredLineLength =
11165f757f3fSDimitry Andric           C.StartOfTokenColumn + C.TokenLength + OriginalSpaces;
1117bdd1243dSDimitry Andric       // If leaving comments makes the line exceed the column limit, give up to
1118bdd1243dSDimitry Andric       // leave the comments.
11195f757f3fSDimitry Andric       if (RestoredLineLength >= Style.ColumnLimit && Style.ColumnLimit > 0)
1120bdd1243dSDimitry Andric         break;
11210fca6ea1SDimitry Andric       C.Spaces = C.NewlinesBefore > 0 ? C.Tok->OriginalColumn : OriginalSpaces;
1122bdd1243dSDimitry Andric       continue;
1123bdd1243dSDimitry Andric     }
1124bdd1243dSDimitry Andric 
11255f757f3fSDimitry Andric     const int ChangeMinColumn = C.StartOfTokenColumn;
11265f757f3fSDimitry Andric     int ChangeMaxColumn;
11270b57cec5SDimitry Andric 
11280b57cec5SDimitry Andric     // If we don't create a replacement for this change, we have to consider
11290b57cec5SDimitry Andric     // it to be immovable.
11305f757f3fSDimitry Andric     if (!C.CreateReplacement)
11315f757f3fSDimitry Andric       ChangeMaxColumn = ChangeMinColumn;
11325f757f3fSDimitry Andric     else if (Style.ColumnLimit == 0)
11335f757f3fSDimitry Andric       ChangeMaxColumn = INT_MAX;
11345f757f3fSDimitry Andric     else if (Style.ColumnLimit >= C.TokenLength)
11355f757f3fSDimitry Andric       ChangeMaxColumn = Style.ColumnLimit - C.TokenLength;
11365f757f3fSDimitry Andric     else
11370b57cec5SDimitry Andric       ChangeMaxColumn = ChangeMinColumn;
11380b57cec5SDimitry Andric 
11395f757f3fSDimitry Andric     if (I + 1 < Size && Changes[I + 1].ContinuesPPDirective &&
11405f757f3fSDimitry Andric         ChangeMaxColumn >= 2) {
11410b57cec5SDimitry Andric       ChangeMaxColumn -= 2;
11425f757f3fSDimitry Andric     }
11435f757f3fSDimitry Andric 
11440b57cec5SDimitry Andric     bool WasAlignedWithStartOfNextLine = false;
11455f757f3fSDimitry Andric     if (C.NewlinesBefore >= 1) { // A comment on its own line.
11465f757f3fSDimitry Andric       const auto CommentColumn =
11475f757f3fSDimitry Andric           SourceMgr.getSpellingColumnNumber(C.OriginalWhitespaceRange.getEnd());
11485f757f3fSDimitry Andric       for (int J = I + 1; J < Size; ++J) {
11495f757f3fSDimitry Andric         if (Changes[J].Tok->is(tok::comment))
11500b57cec5SDimitry Andric           continue;
11510b57cec5SDimitry Andric 
11525f757f3fSDimitry Andric         const auto NextColumn = SourceMgr.getSpellingColumnNumber(
11535f757f3fSDimitry Andric             Changes[J].OriginalWhitespaceRange.getEnd());
11540b57cec5SDimitry Andric         // The start of the next token was previously aligned with the
11550b57cec5SDimitry Andric         // start of this comment.
11560b57cec5SDimitry Andric         WasAlignedWithStartOfNextLine =
11570b57cec5SDimitry Andric             CommentColumn == NextColumn ||
11580b57cec5SDimitry Andric             CommentColumn == NextColumn + Style.IndentWidth;
11590b57cec5SDimitry Andric         break;
11600b57cec5SDimitry Andric       }
11610b57cec5SDimitry Andric     }
11625f757f3fSDimitry Andric 
11635f757f3fSDimitry Andric     // We don't want to align comments which end a scope, which are here
11645f757f3fSDimitry Andric     // identified by most closing braces.
11655f757f3fSDimitry Andric     auto DontAlignThisComment = [](const auto *Tok) {
11665f757f3fSDimitry Andric       if (Tok->is(tok::semi)) {
11675f757f3fSDimitry Andric         Tok = Tok->getPreviousNonComment();
11685f757f3fSDimitry Andric         if (!Tok)
11695f757f3fSDimitry Andric           return false;
11705f757f3fSDimitry Andric       }
11715f757f3fSDimitry Andric       if (Tok->is(tok::r_paren)) {
11725f757f3fSDimitry Andric         // Back up past the parentheses and a `TT_DoWhile` that may precede.
11735f757f3fSDimitry Andric         Tok = Tok->MatchingParen;
11745f757f3fSDimitry Andric         if (!Tok)
11755f757f3fSDimitry Andric           return false;
11765f757f3fSDimitry Andric         Tok = Tok->getPreviousNonComment();
11775f757f3fSDimitry Andric         if (!Tok)
11785f757f3fSDimitry Andric           return false;
11795f757f3fSDimitry Andric         if (Tok->is(TT_DoWhile)) {
11805f757f3fSDimitry Andric           const auto *Prev = Tok->getPreviousNonComment();
11815f757f3fSDimitry Andric           if (!Prev) {
11825f757f3fSDimitry Andric             // A do-while-loop without braces.
11835f757f3fSDimitry Andric             return true;
11845f757f3fSDimitry Andric           }
11855f757f3fSDimitry Andric           Tok = Prev;
11865f757f3fSDimitry Andric         }
11875f757f3fSDimitry Andric       }
11885f757f3fSDimitry Andric 
11895f757f3fSDimitry Andric       if (Tok->isNot(tok::r_brace))
11905f757f3fSDimitry Andric         return false;
11915f757f3fSDimitry Andric 
11925f757f3fSDimitry Andric       while (Tok->Previous && Tok->Previous->is(tok::r_brace))
11935f757f3fSDimitry Andric         Tok = Tok->Previous;
11945f757f3fSDimitry Andric       return Tok->NewlinesBefore > 0;
11955f757f3fSDimitry Andric     };
11965f757f3fSDimitry Andric 
11975f757f3fSDimitry Andric     if (I > 0 && C.NewlinesBefore == 0 &&
11985f757f3fSDimitry Andric         DontAlignThisComment(Changes[I - 1].Tok)) {
11995f757f3fSDimitry Andric       alignTrailingComments(StartOfSequence, I, MinColumn);
12005f757f3fSDimitry Andric       // Reset to initial values, but skip this change for the next alignment
12015f757f3fSDimitry Andric       // pass.
12025f757f3fSDimitry Andric       MinColumn = 0;
12035f757f3fSDimitry Andric       MaxColumn = INT_MAX;
12045f757f3fSDimitry Andric       StartOfSequence = I + 1;
1205bdd1243dSDimitry Andric     } else if (BreakBeforeNext || Newlines > NewLineThreshold ||
12060b57cec5SDimitry Andric                (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
12070b57cec5SDimitry Andric                // Break the comment sequence if the previous line did not end
12080b57cec5SDimitry Andric                // in a trailing comment.
12095f757f3fSDimitry Andric                (C.NewlinesBefore == 1 && I > 0 &&
12105f757f3fSDimitry Andric                 !Changes[I - 1].IsTrailingComment) ||
12110b57cec5SDimitry Andric                WasAlignedWithStartOfNextLine) {
12125f757f3fSDimitry Andric       alignTrailingComments(StartOfSequence, I, MinColumn);
12130b57cec5SDimitry Andric       MinColumn = ChangeMinColumn;
12140b57cec5SDimitry Andric       MaxColumn = ChangeMaxColumn;
12155f757f3fSDimitry Andric       StartOfSequence = I;
12160b57cec5SDimitry Andric     } else {
12170b57cec5SDimitry Andric       MinColumn = std::max(MinColumn, ChangeMinColumn);
12180b57cec5SDimitry Andric       MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
12190b57cec5SDimitry Andric     }
12205f757f3fSDimitry Andric     BreakBeforeNext = (I == 0) || (C.NewlinesBefore > 1) ||
12210b57cec5SDimitry Andric                       // Never start a sequence with a comment at the beginning
12220b57cec5SDimitry Andric                       // of the line.
12235f757f3fSDimitry Andric                       (C.NewlinesBefore == 1 && StartOfSequence == I);
12240b57cec5SDimitry Andric     Newlines = 0;
12250b57cec5SDimitry Andric   }
12265f757f3fSDimitry Andric   alignTrailingComments(StartOfSequence, Size, MinColumn);
12270b57cec5SDimitry Andric }
12280b57cec5SDimitry Andric 
12290b57cec5SDimitry Andric void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
12300b57cec5SDimitry Andric                                               unsigned Column) {
12310b57cec5SDimitry Andric   for (unsigned i = Start; i != End; ++i) {
12320b57cec5SDimitry Andric     int Shift = 0;
123381ad6265SDimitry Andric     if (Changes[i].IsTrailingComment)
12340b57cec5SDimitry Andric       Shift = Column - Changes[i].StartOfTokenColumn;
12350b57cec5SDimitry Andric     if (Changes[i].StartOfBlockComment) {
12360b57cec5SDimitry Andric       Shift = Changes[i].IndentationOffset +
12370b57cec5SDimitry Andric               Changes[i].StartOfBlockComment->StartOfTokenColumn -
12380b57cec5SDimitry Andric               Changes[i].StartOfTokenColumn;
12390b57cec5SDimitry Andric     }
1240bdd1243dSDimitry Andric     if (Shift <= 0)
12414824e7fdSDimitry Andric       continue;
12420b57cec5SDimitry Andric     Changes[i].Spaces += Shift;
12430b57cec5SDimitry Andric     if (i + 1 != Changes.size())
12440b57cec5SDimitry Andric       Changes[i + 1].PreviousEndOfTokenColumn += Shift;
12450b57cec5SDimitry Andric     Changes[i].StartOfTokenColumn += Shift;
12460b57cec5SDimitry Andric   }
12470b57cec5SDimitry Andric }
12480b57cec5SDimitry Andric 
12490b57cec5SDimitry Andric void WhitespaceManager::alignEscapedNewlines() {
12500fca6ea1SDimitry Andric   const auto Align = Style.AlignEscapedNewlines;
12510fca6ea1SDimitry Andric   if (Align == FormatStyle::ENAS_DontAlign)
12520b57cec5SDimitry Andric     return;
12530b57cec5SDimitry Andric 
12540fca6ea1SDimitry Andric   const bool WithLastLine = Align == FormatStyle::ENAS_LeftWithLastLine;
12550fca6ea1SDimitry Andric   const bool AlignLeft = Align == FormatStyle::ENAS_Left || WithLastLine;
12560fca6ea1SDimitry Andric   const auto MaxColumn = Style.ColumnLimit;
12570fca6ea1SDimitry Andric   unsigned MaxEndOfLine = AlignLeft ? 0 : MaxColumn;
12580b57cec5SDimitry Andric   unsigned StartOfMacro = 0;
12590b57cec5SDimitry Andric   for (unsigned i = 1, e = Changes.size(); i < e; ++i) {
12600b57cec5SDimitry Andric     Change &C = Changes[i];
12610fca6ea1SDimitry Andric     if (C.NewlinesBefore == 0 && (!WithLastLine || C.Tok->isNot(tok::eof)))
12620fca6ea1SDimitry Andric       continue;
12630fca6ea1SDimitry Andric     const bool InPPDirective = C.ContinuesPPDirective;
12640fca6ea1SDimitry Andric     const auto BackslashColumn = C.PreviousEndOfTokenColumn + 2;
12650fca6ea1SDimitry Andric     if (InPPDirective ||
12660fca6ea1SDimitry Andric         (WithLastLine && (MaxColumn == 0 || BackslashColumn <= MaxColumn))) {
12670fca6ea1SDimitry Andric       MaxEndOfLine = std::max(BackslashColumn, MaxEndOfLine);
12680b57cec5SDimitry Andric     }
12690fca6ea1SDimitry Andric     if (!InPPDirective) {
12700fca6ea1SDimitry Andric       alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
12710fca6ea1SDimitry Andric       MaxEndOfLine = AlignLeft ? 0 : MaxColumn;
12720fca6ea1SDimitry Andric       StartOfMacro = i;
12730b57cec5SDimitry Andric     }
12740b57cec5SDimitry Andric   }
12750b57cec5SDimitry Andric   alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
12760b57cec5SDimitry Andric }
12770b57cec5SDimitry Andric 
12780b57cec5SDimitry Andric void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End,
12790b57cec5SDimitry Andric                                              unsigned Column) {
12800b57cec5SDimitry Andric   for (unsigned i = Start; i < End; ++i) {
12810b57cec5SDimitry Andric     Change &C = Changes[i];
12820b57cec5SDimitry Andric     if (C.NewlinesBefore > 0) {
12830b57cec5SDimitry Andric       assert(C.ContinuesPPDirective);
12840b57cec5SDimitry Andric       if (C.PreviousEndOfTokenColumn + 1 > Column)
12850b57cec5SDimitry Andric         C.EscapedNewlineColumn = 0;
12860b57cec5SDimitry Andric       else
12870b57cec5SDimitry Andric         C.EscapedNewlineColumn = Column;
12880b57cec5SDimitry Andric     }
12890b57cec5SDimitry Andric   }
12900b57cec5SDimitry Andric }
12910b57cec5SDimitry Andric 
1292fe6060f1SDimitry Andric void WhitespaceManager::alignArrayInitializers() {
1293fe6060f1SDimitry Andric   if (Style.AlignArrayOfStructures == FormatStyle::AIAS_None)
1294fe6060f1SDimitry Andric     return;
1295fe6060f1SDimitry Andric 
1296fe6060f1SDimitry Andric   for (unsigned ChangeIndex = 1U, ChangeEnd = Changes.size();
1297fe6060f1SDimitry Andric        ChangeIndex < ChangeEnd; ++ChangeIndex) {
1298fe6060f1SDimitry Andric     auto &C = Changes[ChangeIndex];
1299fe6060f1SDimitry Andric     if (C.Tok->IsArrayInitializer) {
1300fe6060f1SDimitry Andric       bool FoundComplete = false;
1301fe6060f1SDimitry Andric       for (unsigned InsideIndex = ChangeIndex + 1; InsideIndex < ChangeEnd;
1302fe6060f1SDimitry Andric            ++InsideIndex) {
1303fe6060f1SDimitry Andric         if (Changes[InsideIndex].Tok == C.Tok->MatchingParen) {
1304fe6060f1SDimitry Andric           alignArrayInitializers(ChangeIndex, InsideIndex + 1);
1305fe6060f1SDimitry Andric           ChangeIndex = InsideIndex + 1;
1306fe6060f1SDimitry Andric           FoundComplete = true;
1307fe6060f1SDimitry Andric           break;
1308fe6060f1SDimitry Andric         }
1309fe6060f1SDimitry Andric       }
1310fe6060f1SDimitry Andric       if (!FoundComplete)
1311fe6060f1SDimitry Andric         ChangeIndex = ChangeEnd;
1312fe6060f1SDimitry Andric     }
1313fe6060f1SDimitry Andric   }
1314fe6060f1SDimitry Andric }
1315fe6060f1SDimitry Andric 
1316fe6060f1SDimitry Andric void WhitespaceManager::alignArrayInitializers(unsigned Start, unsigned End) {
1317fe6060f1SDimitry Andric 
1318fe6060f1SDimitry Andric   if (Style.AlignArrayOfStructures == FormatStyle::AIAS_Right)
1319fe6060f1SDimitry Andric     alignArrayInitializersRightJustified(getCells(Start, End));
1320fe6060f1SDimitry Andric   else if (Style.AlignArrayOfStructures == FormatStyle::AIAS_Left)
1321fe6060f1SDimitry Andric     alignArrayInitializersLeftJustified(getCells(Start, End));
1322fe6060f1SDimitry Andric }
1323fe6060f1SDimitry Andric 
1324fe6060f1SDimitry Andric void WhitespaceManager::alignArrayInitializersRightJustified(
1325fe6060f1SDimitry Andric     CellDescriptions &&CellDescs) {
132681ad6265SDimitry Andric   if (!CellDescs.isRectangular())
132781ad6265SDimitry Andric     return;
1328fe6060f1SDimitry Andric 
13295f757f3fSDimitry Andric   const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1;
133081ad6265SDimitry Andric   auto &Cells = CellDescs.Cells;
1331fe6060f1SDimitry Andric   // Now go through and fixup the spaces.
1332fe6060f1SDimitry Andric   auto *CellIter = Cells.begin();
133381ad6265SDimitry Andric   for (auto i = 0U; i < CellDescs.CellCounts[0]; ++i, ++CellIter) {
1334fe6060f1SDimitry Andric     unsigned NetWidth = 0U;
1335fe6060f1SDimitry Andric     if (isSplitCell(*CellIter))
1336fe6060f1SDimitry Andric       NetWidth = getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
1337fe6060f1SDimitry Andric     auto CellWidth = getMaximumCellWidth(CellIter, NetWidth);
1338fe6060f1SDimitry Andric 
1339fe6060f1SDimitry Andric     if (Changes[CellIter->Index].Tok->is(tok::r_brace)) {
1340fe6060f1SDimitry Andric       // So in here we want to see if there is a brace that falls
1341fe6060f1SDimitry Andric       // on a line that was split. If so on that line we make sure that
1342fe6060f1SDimitry Andric       // the spaces in front of the brace are enough.
134381ad6265SDimitry Andric       const auto *Next = CellIter;
134481ad6265SDimitry Andric       do {
134581ad6265SDimitry Andric         const FormatToken *Previous = Changes[Next->Index].Tok->Previous;
134681ad6265SDimitry Andric         if (Previous && Previous->isNot(TT_LineComment)) {
13475f757f3fSDimitry Andric           Changes[Next->Index].Spaces = BracePadding;
1348fe6060f1SDimitry Andric           Changes[Next->Index].NewlinesBefore = 0;
1349fe6060f1SDimitry Andric         }
135081ad6265SDimitry Andric         Next = Next->NextColumnElement;
135181ad6265SDimitry Andric       } while (Next);
1352fe6060f1SDimitry Andric       // Unless the array is empty, we need the position of all the
1353fe6060f1SDimitry Andric       // immediately adjacent cells
1354fe6060f1SDimitry Andric       if (CellIter != Cells.begin()) {
1355fe6060f1SDimitry Andric         auto ThisNetWidth =
1356fe6060f1SDimitry Andric             getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
135781ad6265SDimitry Andric         auto MaxNetWidth = getMaximumNetWidth(
135881ad6265SDimitry Andric             Cells.begin(), CellIter, CellDescs.InitialSpaces,
135981ad6265SDimitry Andric             CellDescs.CellCounts[0], CellDescs.CellCounts.size());
1360fe6060f1SDimitry Andric         if (ThisNetWidth < MaxNetWidth)
1361fe6060f1SDimitry Andric           Changes[CellIter->Index].Spaces = (MaxNetWidth - ThisNetWidth);
1362fe6060f1SDimitry Andric         auto RowCount = 1U;
1363fe6060f1SDimitry Andric         auto Offset = std::distance(Cells.begin(), CellIter);
136406c3fb27SDimitry Andric         for (const auto *Next = CellIter->NextColumnElement; Next;
1365fe6060f1SDimitry Andric              Next = Next->NextColumnElement) {
13665c16e71dSDimitry Andric           if (RowCount >= CellDescs.CellCounts.size())
13675c16e71dSDimitry Andric             break;
136881ad6265SDimitry Andric           auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]);
1369fe6060f1SDimitry Andric           auto *End = Start + Offset;
1370fe6060f1SDimitry Andric           ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces);
1371fe6060f1SDimitry Andric           if (ThisNetWidth < MaxNetWidth)
1372fe6060f1SDimitry Andric             Changes[Next->Index].Spaces = (MaxNetWidth - ThisNetWidth);
1373fe6060f1SDimitry Andric           ++RowCount;
1374fe6060f1SDimitry Andric         }
1375fe6060f1SDimitry Andric       }
1376fe6060f1SDimitry Andric     } else {
1377fe6060f1SDimitry Andric       auto ThisWidth =
1378fe6060f1SDimitry Andric           calculateCellWidth(CellIter->Index, CellIter->EndIndex, true) +
1379fe6060f1SDimitry Andric           NetWidth;
1380fe6060f1SDimitry Andric       if (Changes[CellIter->Index].NewlinesBefore == 0) {
1381fe6060f1SDimitry Andric         Changes[CellIter->Index].Spaces = (CellWidth - (ThisWidth + NetWidth));
13825f757f3fSDimitry Andric         Changes[CellIter->Index].Spaces += (i > 0) ? 1 : BracePadding;
1383fe6060f1SDimitry Andric       }
1384fe6060f1SDimitry Andric       alignToStartOfCell(CellIter->Index, CellIter->EndIndex);
138506c3fb27SDimitry Andric       for (const auto *Next = CellIter->NextColumnElement; Next;
1386fe6060f1SDimitry Andric            Next = Next->NextColumnElement) {
1387fe6060f1SDimitry Andric         ThisWidth =
1388fe6060f1SDimitry Andric             calculateCellWidth(Next->Index, Next->EndIndex, true) + NetWidth;
1389fe6060f1SDimitry Andric         if (Changes[Next->Index].NewlinesBefore == 0) {
1390fe6060f1SDimitry Andric           Changes[Next->Index].Spaces = (CellWidth - ThisWidth);
13915f757f3fSDimitry Andric           Changes[Next->Index].Spaces += (i > 0) ? 1 : BracePadding;
1392fe6060f1SDimitry Andric         }
1393fe6060f1SDimitry Andric         alignToStartOfCell(Next->Index, Next->EndIndex);
1394fe6060f1SDimitry Andric       }
1395fe6060f1SDimitry Andric     }
1396fe6060f1SDimitry Andric   }
1397fe6060f1SDimitry Andric }
1398fe6060f1SDimitry Andric 
1399fe6060f1SDimitry Andric void WhitespaceManager::alignArrayInitializersLeftJustified(
1400fe6060f1SDimitry Andric     CellDescriptions &&CellDescs) {
1401fe6060f1SDimitry Andric 
140281ad6265SDimitry Andric   if (!CellDescs.isRectangular())
140381ad6265SDimitry Andric     return;
140481ad6265SDimitry Andric 
14055f757f3fSDimitry Andric   const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1;
140681ad6265SDimitry Andric   auto &Cells = CellDescs.Cells;
1407fe6060f1SDimitry Andric   // Now go through and fixup the spaces.
1408fe6060f1SDimitry Andric   auto *CellIter = Cells.begin();
14097a6dacacSDimitry Andric   // The first cell of every row needs to be against the left brace.
14107a6dacacSDimitry Andric   for (const auto *Next = CellIter; Next; Next = Next->NextColumnElement) {
14117a6dacacSDimitry Andric     auto &Change = Changes[Next->Index];
14127a6dacacSDimitry Andric     Change.Spaces =
14137a6dacacSDimitry Andric         Change.NewlinesBefore == 0 ? BracePadding : CellDescs.InitialSpaces;
14147a6dacacSDimitry Andric   }
1415fe6060f1SDimitry Andric   ++CellIter;
141681ad6265SDimitry Andric   for (auto i = 1U; i < CellDescs.CellCounts[0]; i++, ++CellIter) {
1417fe6060f1SDimitry Andric     auto MaxNetWidth = getMaximumNetWidth(
141881ad6265SDimitry Andric         Cells.begin(), CellIter, CellDescs.InitialSpaces,
141981ad6265SDimitry Andric         CellDescs.CellCounts[0], CellDescs.CellCounts.size());
1420fe6060f1SDimitry Andric     auto ThisNetWidth =
1421fe6060f1SDimitry Andric         getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
1422fe6060f1SDimitry Andric     if (Changes[CellIter->Index].NewlinesBefore == 0) {
1423fe6060f1SDimitry Andric       Changes[CellIter->Index].Spaces =
1424fe6060f1SDimitry Andric           MaxNetWidth - ThisNetWidth +
14255f757f3fSDimitry Andric           (Changes[CellIter->Index].Tok->isNot(tok::r_brace) ? 1
14265f757f3fSDimitry Andric                                                              : BracePadding);
1427fe6060f1SDimitry Andric     }
1428fe6060f1SDimitry Andric     auto RowCount = 1U;
1429fe6060f1SDimitry Andric     auto Offset = std::distance(Cells.begin(), CellIter);
143006c3fb27SDimitry Andric     for (const auto *Next = CellIter->NextColumnElement; Next;
1431fe6060f1SDimitry Andric          Next = Next->NextColumnElement) {
14325c16e71dSDimitry Andric       if (RowCount >= CellDescs.CellCounts.size())
143381ad6265SDimitry Andric         break;
143481ad6265SDimitry Andric       auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]);
1435fe6060f1SDimitry Andric       auto *End = Start + Offset;
1436fe6060f1SDimitry Andric       auto ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces);
1437fe6060f1SDimitry Andric       if (Changes[Next->Index].NewlinesBefore == 0) {
1438fe6060f1SDimitry Andric         Changes[Next->Index].Spaces =
1439fe6060f1SDimitry Andric             MaxNetWidth - ThisNetWidth +
14405f757f3fSDimitry Andric             (Changes[Next->Index].Tok->isNot(tok::r_brace) ? 1 : BracePadding);
1441fe6060f1SDimitry Andric       }
1442fe6060f1SDimitry Andric       ++RowCount;
1443fe6060f1SDimitry Andric     }
1444fe6060f1SDimitry Andric   }
1445fe6060f1SDimitry Andric }
1446fe6060f1SDimitry Andric 
1447fe6060f1SDimitry Andric bool WhitespaceManager::isSplitCell(const CellDescription &Cell) {
1448fe6060f1SDimitry Andric   if (Cell.HasSplit)
1449fe6060f1SDimitry Andric     return true;
145006c3fb27SDimitry Andric   for (const auto *Next = Cell.NextColumnElement; Next;
1451fe6060f1SDimitry Andric        Next = Next->NextColumnElement) {
1452fe6060f1SDimitry Andric     if (Next->HasSplit)
1453fe6060f1SDimitry Andric       return true;
1454fe6060f1SDimitry Andric   }
1455fe6060f1SDimitry Andric   return false;
1456fe6060f1SDimitry Andric }
1457fe6060f1SDimitry Andric 
1458fe6060f1SDimitry Andric WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start,
1459fe6060f1SDimitry Andric                                                                 unsigned End) {
1460fe6060f1SDimitry Andric 
1461fe6060f1SDimitry Andric   unsigned Depth = 0;
1462fe6060f1SDimitry Andric   unsigned Cell = 0;
146381ad6265SDimitry Andric   SmallVector<unsigned> CellCounts;
1464fe6060f1SDimitry Andric   unsigned InitialSpaces = 0;
1465fe6060f1SDimitry Andric   unsigned InitialTokenLength = 0;
1466fe6060f1SDimitry Andric   unsigned EndSpaces = 0;
1467fe6060f1SDimitry Andric   SmallVector<CellDescription> Cells;
1468fe6060f1SDimitry Andric   const FormatToken *MatchingParen = nullptr;
1469fe6060f1SDimitry Andric   for (unsigned i = Start; i < End; ++i) {
1470fe6060f1SDimitry Andric     auto &C = Changes[i];
1471fe6060f1SDimitry Andric     if (C.Tok->is(tok::l_brace))
1472fe6060f1SDimitry Andric       ++Depth;
1473fe6060f1SDimitry Andric     else if (C.Tok->is(tok::r_brace))
1474fe6060f1SDimitry Andric       --Depth;
1475fe6060f1SDimitry Andric     if (Depth == 2) {
1476fe6060f1SDimitry Andric       if (C.Tok->is(tok::l_brace)) {
1477fe6060f1SDimitry Andric         Cell = 0;
1478fe6060f1SDimitry Andric         MatchingParen = C.Tok->MatchingParen;
1479fe6060f1SDimitry Andric         if (InitialSpaces == 0) {
1480fe6060f1SDimitry Andric           InitialSpaces = C.Spaces + C.TokenLength;
1481fe6060f1SDimitry Andric           InitialTokenLength = C.TokenLength;
1482fe6060f1SDimitry Andric           auto j = i - 1;
1483fe6060f1SDimitry Andric           for (; Changes[j].NewlinesBefore == 0 && j > Start; --j) {
1484fe6060f1SDimitry Andric             InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength;
1485fe6060f1SDimitry Andric             InitialTokenLength += Changes[j].TokenLength;
1486fe6060f1SDimitry Andric           }
1487fe6060f1SDimitry Andric           if (C.NewlinesBefore == 0) {
1488fe6060f1SDimitry Andric             InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength;
1489fe6060f1SDimitry Andric             InitialTokenLength += Changes[j].TokenLength;
1490fe6060f1SDimitry Andric           }
1491fe6060f1SDimitry Andric         }
1492fe6060f1SDimitry Andric       } else if (C.Tok->is(tok::comma)) {
1493fe6060f1SDimitry Andric         if (!Cells.empty())
1494fe6060f1SDimitry Andric           Cells.back().EndIndex = i;
14957a6dacacSDimitry Andric         if (const auto *Next = C.Tok->getNextNonComment();
14967a6dacacSDimitry Andric             Next && Next->isNot(tok::r_brace)) { // dangling comma
1497349cc55cSDimitry Andric           ++Cell;
1498fe6060f1SDimitry Andric         }
14997a6dacacSDimitry Andric       }
1500fe6060f1SDimitry Andric     } else if (Depth == 1) {
1501fe6060f1SDimitry Andric       if (C.Tok == MatchingParen) {
1502fe6060f1SDimitry Andric         if (!Cells.empty())
1503fe6060f1SDimitry Andric           Cells.back().EndIndex = i;
1504fe6060f1SDimitry Andric         Cells.push_back(CellDescription{i, ++Cell, i + 1, false, nullptr});
150581ad6265SDimitry Andric         CellCounts.push_back(C.Tok->Previous->isNot(tok::comma) ? Cell + 1
150681ad6265SDimitry Andric                                                                 : Cell);
1507fe6060f1SDimitry Andric         // Go to the next non-comment and ensure there is a break in front
1508fe6060f1SDimitry Andric         const auto *NextNonComment = C.Tok->getNextNonComment();
15093a079333SDimitry Andric         while (NextNonComment && NextNonComment->is(tok::comma))
1510fe6060f1SDimitry Andric           NextNonComment = NextNonComment->getNextNonComment();
1511fe6060f1SDimitry Andric         auto j = i;
15120fca6ea1SDimitry Andric         while (j < End && Changes[j].Tok != NextNonComment)
151304eeddc0SDimitry Andric           ++j;
1514fe6060f1SDimitry Andric         if (j < End && Changes[j].NewlinesBefore == 0 &&
1515fe6060f1SDimitry Andric             Changes[j].Tok->isNot(tok::r_brace)) {
1516fe6060f1SDimitry Andric           Changes[j].NewlinesBefore = 1;
1517fe6060f1SDimitry Andric           // Account for the added token lengths
1518fe6060f1SDimitry Andric           Changes[j].Spaces = InitialSpaces - InitialTokenLength;
1519fe6060f1SDimitry Andric         }
15205f757f3fSDimitry Andric       } else if (C.Tok->is(tok::comment) && C.Tok->NewlinesBefore == 0) {
1521fe6060f1SDimitry Andric         // Trailing comments stay at a space past the last token
1522fe6060f1SDimitry Andric         C.Spaces = Changes[i - 1].Tok->is(tok::comma) ? 1 : 2;
1523fe6060f1SDimitry Andric       } else if (C.Tok->is(tok::l_brace)) {
1524fe6060f1SDimitry Andric         // We need to make sure that the ending braces is aligned to the
1525fe6060f1SDimitry Andric         // start of our initializer
1526fe6060f1SDimitry Andric         auto j = i - 1;
1527fe6060f1SDimitry Andric         for (; j > 0 && !Changes[j].Tok->ArrayInitializerLineStart; --j)
1528fe6060f1SDimitry Andric           ; // Nothing the loop does the work
1529fe6060f1SDimitry Andric         EndSpaces = Changes[j].Spaces;
1530fe6060f1SDimitry Andric       }
1531fe6060f1SDimitry Andric     } else if (Depth == 0 && C.Tok->is(tok::r_brace)) {
1532fe6060f1SDimitry Andric       C.NewlinesBefore = 1;
1533fe6060f1SDimitry Andric       C.Spaces = EndSpaces;
1534fe6060f1SDimitry Andric     }
1535fe6060f1SDimitry Andric     if (C.Tok->StartsColumn) {
1536fe6060f1SDimitry Andric       // This gets us past tokens that have been split over multiple
1537fe6060f1SDimitry Andric       // lines
1538fe6060f1SDimitry Andric       bool HasSplit = false;
1539fe6060f1SDimitry Andric       if (Changes[i].NewlinesBefore > 0) {
1540fe6060f1SDimitry Andric         // So if we split a line previously and the tail line + this token is
1541fe6060f1SDimitry Andric         // less then the column limit we remove the split here and just put
1542fe6060f1SDimitry Andric         // the column start at a space past the comma
1543349cc55cSDimitry Andric         //
1544349cc55cSDimitry Andric         // FIXME This if branch covers the cases where the column is not
1545349cc55cSDimitry Andric         // the first column. This leads to weird pathologies like the formatting
1546349cc55cSDimitry Andric         // auto foo = Items{
1547349cc55cSDimitry Andric         //     Section{
1548349cc55cSDimitry Andric         //             0, bar(),
1549349cc55cSDimitry Andric         //     }
1550349cc55cSDimitry Andric         // };
1551349cc55cSDimitry Andric         // Well if it doesn't lead to that it's indicative that the line
1552349cc55cSDimitry Andric         // breaking should be revisited. Unfortunately alot of other options
1553349cc55cSDimitry Andric         // interact with this
1554fe6060f1SDimitry Andric         auto j = i - 1;
1555fe6060f1SDimitry Andric         if ((j - 1) > Start && Changes[j].Tok->is(tok::comma) &&
1556fe6060f1SDimitry Andric             Changes[j - 1].NewlinesBefore > 0) {
1557fe6060f1SDimitry Andric           --j;
1558fe6060f1SDimitry Andric           auto LineLimit = Changes[j].Spaces + Changes[j].TokenLength;
1559fe6060f1SDimitry Andric           if (LineLimit < Style.ColumnLimit) {
1560fe6060f1SDimitry Andric             Changes[i].NewlinesBefore = 0;
1561fe6060f1SDimitry Andric             Changes[i].Spaces = 1;
1562fe6060f1SDimitry Andric           }
1563fe6060f1SDimitry Andric         }
1564fe6060f1SDimitry Andric       }
1565fe6060f1SDimitry Andric       while (Changes[i].NewlinesBefore > 0 && Changes[i].Tok == C.Tok) {
1566fe6060f1SDimitry Andric         Changes[i].Spaces = InitialSpaces;
1567fe6060f1SDimitry Andric         ++i;
1568fe6060f1SDimitry Andric         HasSplit = true;
1569fe6060f1SDimitry Andric       }
1570fe6060f1SDimitry Andric       if (Changes[i].Tok != C.Tok)
1571fe6060f1SDimitry Andric         --i;
1572fe6060f1SDimitry Andric       Cells.push_back(CellDescription{i, Cell, i, HasSplit, nullptr});
1573fe6060f1SDimitry Andric     }
1574fe6060f1SDimitry Andric   }
1575fe6060f1SDimitry Andric 
157681ad6265SDimitry Andric   return linkCells({Cells, CellCounts, InitialSpaces});
1577fe6060f1SDimitry Andric }
1578fe6060f1SDimitry Andric 
1579fe6060f1SDimitry Andric unsigned WhitespaceManager::calculateCellWidth(unsigned Start, unsigned End,
1580fe6060f1SDimitry Andric                                                bool WithSpaces) const {
1581fe6060f1SDimitry Andric   unsigned CellWidth = 0;
1582fe6060f1SDimitry Andric   for (auto i = Start; i < End; i++) {
1583fe6060f1SDimitry Andric     if (Changes[i].NewlinesBefore > 0)
1584fe6060f1SDimitry Andric       CellWidth = 0;
1585fe6060f1SDimitry Andric     CellWidth += Changes[i].TokenLength;
1586fe6060f1SDimitry Andric     CellWidth += (WithSpaces ? Changes[i].Spaces : 0);
1587fe6060f1SDimitry Andric   }
1588fe6060f1SDimitry Andric   return CellWidth;
1589fe6060f1SDimitry Andric }
1590fe6060f1SDimitry Andric 
1591fe6060f1SDimitry Andric void WhitespaceManager::alignToStartOfCell(unsigned Start, unsigned End) {
1592fe6060f1SDimitry Andric   if ((End - Start) <= 1)
1593fe6060f1SDimitry Andric     return;
1594fe6060f1SDimitry Andric   // If the line is broken anywhere in there make sure everything
1595fe6060f1SDimitry Andric   // is aligned to the parent
159681ad6265SDimitry Andric   for (auto i = Start + 1; i < End; i++)
1597fe6060f1SDimitry Andric     if (Changes[i].NewlinesBefore > 0)
1598fe6060f1SDimitry Andric       Changes[i].Spaces = Changes[Start].Spaces;
1599fe6060f1SDimitry Andric }
1600fe6060f1SDimitry Andric 
1601fe6060f1SDimitry Andric WhitespaceManager::CellDescriptions
1602fe6060f1SDimitry Andric WhitespaceManager::linkCells(CellDescriptions &&CellDesc) {
1603fe6060f1SDimitry Andric   auto &Cells = CellDesc.Cells;
1604fe6060f1SDimitry Andric   for (auto *CellIter = Cells.begin(); CellIter != Cells.end(); ++CellIter) {
160506c3fb27SDimitry Andric     if (!CellIter->NextColumnElement && (CellIter + 1) != Cells.end()) {
1606fe6060f1SDimitry Andric       for (auto *NextIter = CellIter + 1; NextIter != Cells.end(); ++NextIter) {
1607fe6060f1SDimitry Andric         if (NextIter->Cell == CellIter->Cell) {
1608fe6060f1SDimitry Andric           CellIter->NextColumnElement = &(*NextIter);
1609fe6060f1SDimitry Andric           break;
1610fe6060f1SDimitry Andric         }
1611fe6060f1SDimitry Andric       }
1612fe6060f1SDimitry Andric     }
1613fe6060f1SDimitry Andric   }
1614fe6060f1SDimitry Andric   return std::move(CellDesc);
1615fe6060f1SDimitry Andric }
1616fe6060f1SDimitry Andric 
16170b57cec5SDimitry Andric void WhitespaceManager::generateChanges() {
16180b57cec5SDimitry Andric   for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
16190b57cec5SDimitry Andric     const Change &C = Changes[i];
16205f757f3fSDimitry Andric     if (i > 0) {
16215f757f3fSDimitry Andric       auto Last = Changes[i - 1].OriginalWhitespaceRange;
16225f757f3fSDimitry Andric       auto New = Changes[i].OriginalWhitespaceRange;
16235f757f3fSDimitry Andric       // Do not generate two replacements for the same location.  As a special
16245f757f3fSDimitry Andric       // case, it is allowed if there is a replacement for the empty range
16255f757f3fSDimitry Andric       // between 2 tokens and another non-empty range at the start of the second
16265f757f3fSDimitry Andric       // token.  We didn't implement logic to combine replacements for 2
16275f757f3fSDimitry Andric       // consecutive source ranges into a single replacement, because the
16285f757f3fSDimitry Andric       // program works fine without it.
16295f757f3fSDimitry Andric       //
16305f757f3fSDimitry Andric       // We can't eliminate empty original whitespace ranges.  They appear when
16315f757f3fSDimitry Andric       // 2 tokens have no whitespace in between in the input.  It does not
16325f757f3fSDimitry Andric       // matter whether whitespace is to be added.  If no whitespace is to be
16335f757f3fSDimitry Andric       // added, the replacement will be empty, and it gets eliminated after this
16345f757f3fSDimitry Andric       // step in storeReplacement.  For example, if the input is `foo();`,
16355f757f3fSDimitry Andric       // there will be a replacement for the range between every consecutive
16365f757f3fSDimitry Andric       // pair of tokens.
16375f757f3fSDimitry Andric       //
16385f757f3fSDimitry Andric       // A replacement at the start of a token can be added by
16395f757f3fSDimitry Andric       // BreakableStringLiteralUsingOperators::insertBreak when it adds braces
16405f757f3fSDimitry Andric       // around the string literal.  Say Verilog code is being formatted and the
16415f757f3fSDimitry Andric       // first line is to become the next 2 lines.
16425f757f3fSDimitry Andric       //     x("long string");
16435f757f3fSDimitry Andric       //     x({"long ",
16445f757f3fSDimitry Andric       //        "string"});
16455f757f3fSDimitry Andric       // There will be a replacement for the empty range between the parenthesis
16465f757f3fSDimitry Andric       // and the string and another replacement for the quote character.  The
16475f757f3fSDimitry Andric       // replacement for the empty range between the parenthesis and the quote
16485f757f3fSDimitry Andric       // comes from ContinuationIndenter::addTokenOnCurrentLine when it changes
16495f757f3fSDimitry Andric       // the original empty range between the parenthesis and the string to
16505f757f3fSDimitry Andric       // another empty one.  The replacement for the quote character comes from
16515f757f3fSDimitry Andric       // BreakableStringLiteralUsingOperators::insertBreak when it adds the
16525f757f3fSDimitry Andric       // brace.  In the example, the replacement for the empty range is the same
16535f757f3fSDimitry Andric       // as the original text.  However, eliminating replacements that are same
16545f757f3fSDimitry Andric       // as the original does not help in general.  For example, a newline can
16555f757f3fSDimitry Andric       // be inserted, causing the first line to become the next 3 lines.
16565f757f3fSDimitry Andric       //     xxxxxxxxxxx("long string");
16575f757f3fSDimitry Andric       //     xxxxxxxxxxx(
16585f757f3fSDimitry Andric       //         {"long ",
16595f757f3fSDimitry Andric       //          "string"});
16605f757f3fSDimitry Andric       // In that case, the empty range between the parenthesis and the string
16615f757f3fSDimitry Andric       // will be replaced by a newline and 4 spaces.  So we will still have to
16625f757f3fSDimitry Andric       // deal with a replacement for an empty source range followed by a
16635f757f3fSDimitry Andric       // replacement for a non-empty source range.
16645f757f3fSDimitry Andric       if (Last.getBegin() == New.getBegin() &&
16655f757f3fSDimitry Andric           (Last.getEnd() != Last.getBegin() ||
16665f757f3fSDimitry Andric            New.getEnd() == New.getBegin())) {
16674824e7fdSDimitry Andric         continue;
16680b57cec5SDimitry Andric       }
16695f757f3fSDimitry Andric     }
16700b57cec5SDimitry Andric     if (C.CreateReplacement) {
16710b57cec5SDimitry Andric       std::string ReplacementText = C.PreviousLinePostfix;
167281ad6265SDimitry Andric       if (C.ContinuesPPDirective) {
16730b57cec5SDimitry Andric         appendEscapedNewlineText(ReplacementText, C.NewlinesBefore,
16740b57cec5SDimitry Andric                                  C.PreviousEndOfTokenColumn,
16750b57cec5SDimitry Andric                                  C.EscapedNewlineColumn);
167681ad6265SDimitry Andric       } else {
16770b57cec5SDimitry Andric         appendNewlineText(ReplacementText, C.NewlinesBefore);
167881ad6265SDimitry Andric       }
16790eae32dcSDimitry Andric       // FIXME: This assert should hold if we computed the column correctly.
16800eae32dcSDimitry Andric       // assert((int)C.StartOfTokenColumn >= C.Spaces);
16815ffd83dbSDimitry Andric       appendIndentText(
16825ffd83dbSDimitry Andric           ReplacementText, C.Tok->IndentLevel, std::max(0, C.Spaces),
16830eae32dcSDimitry Andric           std::max((int)C.StartOfTokenColumn, C.Spaces) - std::max(0, C.Spaces),
16840eae32dcSDimitry Andric           C.IsAligned);
16850b57cec5SDimitry Andric       ReplacementText.append(C.CurrentLinePrefix);
16860b57cec5SDimitry Andric       storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
16870b57cec5SDimitry Andric     }
16880b57cec5SDimitry Andric   }
16890b57cec5SDimitry Andric }
16900b57cec5SDimitry Andric 
16910b57cec5SDimitry Andric void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) {
16920b57cec5SDimitry Andric   unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) -
16930b57cec5SDimitry Andric                               SourceMgr.getFileOffset(Range.getBegin());
16940b57cec5SDimitry Andric   // Don't create a replacement, if it does not change anything.
16950b57cec5SDimitry Andric   if (StringRef(SourceMgr.getCharacterData(Range.getBegin()),
169681ad6265SDimitry Andric                 WhitespaceLength) == Text) {
16970b57cec5SDimitry Andric     return;
169881ad6265SDimitry Andric   }
16990b57cec5SDimitry Andric   auto Err = Replaces.add(tooling::Replacement(
17000b57cec5SDimitry Andric       SourceMgr, CharSourceRange::getCharRange(Range), Text));
17010b57cec5SDimitry Andric   // FIXME: better error handling. For now, just print an error message in the
17020b57cec5SDimitry Andric   // release version.
17030b57cec5SDimitry Andric   if (Err) {
17040b57cec5SDimitry Andric     llvm::errs() << llvm::toString(std::move(Err)) << "\n";
17050b57cec5SDimitry Andric     assert(false);
17060b57cec5SDimitry Andric   }
17070b57cec5SDimitry Andric }
17080b57cec5SDimitry Andric 
17090b57cec5SDimitry Andric void WhitespaceManager::appendNewlineText(std::string &Text,
17100b57cec5SDimitry Andric                                           unsigned Newlines) {
17111fd87a68SDimitry Andric   if (UseCRLF) {
17121fd87a68SDimitry Andric     Text.reserve(Text.size() + 2 * Newlines);
17130b57cec5SDimitry Andric     for (unsigned i = 0; i < Newlines; ++i)
17141fd87a68SDimitry Andric       Text.append("\r\n");
17151fd87a68SDimitry Andric   } else {
17161fd87a68SDimitry Andric     Text.append(Newlines, '\n');
17171fd87a68SDimitry Andric   }
17180b57cec5SDimitry Andric }
17190b57cec5SDimitry Andric 
17200b57cec5SDimitry Andric void WhitespaceManager::appendEscapedNewlineText(
17210b57cec5SDimitry Andric     std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn,
17220b57cec5SDimitry Andric     unsigned EscapedNewlineColumn) {
17230b57cec5SDimitry Andric   if (Newlines > 0) {
17240b57cec5SDimitry Andric     unsigned Spaces =
17250b57cec5SDimitry Andric         std::max<int>(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1);
17260b57cec5SDimitry Andric     for (unsigned i = 0; i < Newlines; ++i) {
17270b57cec5SDimitry Andric       Text.append(Spaces, ' ');
17280b57cec5SDimitry Andric       Text.append(UseCRLF ? "\\\r\n" : "\\\n");
17290b57cec5SDimitry Andric       Spaces = std::max<int>(0, EscapedNewlineColumn - 1);
17300b57cec5SDimitry Andric     }
17310b57cec5SDimitry Andric   }
17320b57cec5SDimitry Andric }
17330b57cec5SDimitry Andric 
17340b57cec5SDimitry Andric void WhitespaceManager::appendIndentText(std::string &Text,
17350b57cec5SDimitry Andric                                          unsigned IndentLevel, unsigned Spaces,
17365ffd83dbSDimitry Andric                                          unsigned WhitespaceStartColumn,
17375ffd83dbSDimitry Andric                                          bool IsAligned) {
17380b57cec5SDimitry Andric   switch (Style.UseTab) {
17390b57cec5SDimitry Andric   case FormatStyle::UT_Never:
17400b57cec5SDimitry Andric     Text.append(Spaces, ' ');
17410b57cec5SDimitry Andric     break;
17420b57cec5SDimitry Andric   case FormatStyle::UT_Always: {
1743a7dea167SDimitry Andric     if (Style.TabWidth) {
17440b57cec5SDimitry Andric       unsigned FirstTabWidth =
17450b57cec5SDimitry Andric           Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
1746a7dea167SDimitry Andric 
17470b57cec5SDimitry Andric       // Insert only spaces when we want to end up before the next tab.
17480b57cec5SDimitry Andric       if (Spaces < FirstTabWidth || Spaces == 1) {
17490b57cec5SDimitry Andric         Text.append(Spaces, ' ');
17500b57cec5SDimitry Andric         break;
17510b57cec5SDimitry Andric       }
17520b57cec5SDimitry Andric       // Align to the next tab.
17530b57cec5SDimitry Andric       Spaces -= FirstTabWidth;
17540b57cec5SDimitry Andric       Text.append("\t");
17550b57cec5SDimitry Andric 
17560b57cec5SDimitry Andric       Text.append(Spaces / Style.TabWidth, '\t');
17570b57cec5SDimitry Andric       Text.append(Spaces % Style.TabWidth, ' ');
1758a7dea167SDimitry Andric     } else if (Spaces == 1) {
1759a7dea167SDimitry Andric       Text.append(Spaces, ' ');
1760a7dea167SDimitry Andric     }
17610b57cec5SDimitry Andric     break;
17620b57cec5SDimitry Andric   }
17630b57cec5SDimitry Andric   case FormatStyle::UT_ForIndentation:
17640b57cec5SDimitry Andric     if (WhitespaceStartColumn == 0) {
17650b57cec5SDimitry Andric       unsigned Indentation = IndentLevel * Style.IndentWidth;
17665ffd83dbSDimitry Andric       Spaces = appendTabIndent(Text, Spaces, Indentation);
17675ffd83dbSDimitry Andric     }
17685ffd83dbSDimitry Andric     Text.append(Spaces, ' ');
17695ffd83dbSDimitry Andric     break;
17705ffd83dbSDimitry Andric   case FormatStyle::UT_ForContinuationAndIndentation:
17715ffd83dbSDimitry Andric     if (WhitespaceStartColumn == 0)
17725ffd83dbSDimitry Andric       Spaces = appendTabIndent(Text, Spaces, Spaces);
17735ffd83dbSDimitry Andric     Text.append(Spaces, ' ');
17745ffd83dbSDimitry Andric     break;
17755ffd83dbSDimitry Andric   case FormatStyle::UT_AlignWithSpaces:
17765ffd83dbSDimitry Andric     if (WhitespaceStartColumn == 0) {
17775ffd83dbSDimitry Andric       unsigned Indentation =
17785ffd83dbSDimitry Andric           IsAligned ? IndentLevel * Style.IndentWidth : Spaces;
17795ffd83dbSDimitry Andric       Spaces = appendTabIndent(Text, Spaces, Indentation);
17805ffd83dbSDimitry Andric     }
17815ffd83dbSDimitry Andric     Text.append(Spaces, ' ');
17825ffd83dbSDimitry Andric     break;
17835ffd83dbSDimitry Andric   }
17845ffd83dbSDimitry Andric }
17855ffd83dbSDimitry Andric 
17865ffd83dbSDimitry Andric unsigned WhitespaceManager::appendTabIndent(std::string &Text, unsigned Spaces,
17875ffd83dbSDimitry Andric                                             unsigned Indentation) {
17885ffd83dbSDimitry Andric   // This happens, e.g. when a line in a block comment is indented less than the
17895ffd83dbSDimitry Andric   // first one.
17900b57cec5SDimitry Andric   if (Indentation > Spaces)
17910b57cec5SDimitry Andric     Indentation = Spaces;
1792a7dea167SDimitry Andric   if (Style.TabWidth) {
17930b57cec5SDimitry Andric     unsigned Tabs = Indentation / Style.TabWidth;
17940b57cec5SDimitry Andric     Text.append(Tabs, '\t');
17950b57cec5SDimitry Andric     Spaces -= Tabs * Style.TabWidth;
17960b57cec5SDimitry Andric   }
17975ffd83dbSDimitry Andric   return Spaces;
17980b57cec5SDimitry Andric }
17990b57cec5SDimitry Andric 
18000b57cec5SDimitry Andric } // namespace format
18010b57cec5SDimitry Andric } // namespace clang
1802