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