[NFC][RemoveDIs] Prefer iterators over inst-pointers in InstCombine
[llvm-project.git] / clang / lib / Format / WhitespaceManager.cpp
blobb7bd8d27dc976b17d04b693c4dbbd5e2f6d4113e
1 //===--- WhitespaceManager.cpp - Format C++ code --------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file implements WhitespaceManager class.
11 ///
12 //===----------------------------------------------------------------------===//
14 #include "WhitespaceManager.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/SmallVector.h"
17 #include <algorithm>
19 namespace clang {
20 namespace format {
22 bool WhitespaceManager::Change::IsBeforeInFile::operator()(
23 const Change &C1, const Change &C2) const {
24 return SourceMgr.isBeforeInTranslationUnit(
25 C1.OriginalWhitespaceRange.getBegin(),
26 C2.OriginalWhitespaceRange.getBegin()) ||
27 (C1.OriginalWhitespaceRange.getBegin() ==
28 C2.OriginalWhitespaceRange.getBegin() &&
29 SourceMgr.isBeforeInTranslationUnit(
30 C1.OriginalWhitespaceRange.getEnd(),
31 C2.OriginalWhitespaceRange.getEnd()));
34 WhitespaceManager::Change::Change(const FormatToken &Tok,
35 bool CreateReplacement,
36 SourceRange OriginalWhitespaceRange,
37 int Spaces, unsigned StartOfTokenColumn,
38 unsigned NewlinesBefore,
39 StringRef PreviousLinePostfix,
40 StringRef CurrentLinePrefix, bool IsAligned,
41 bool ContinuesPPDirective, bool IsInsideToken)
42 : Tok(&Tok), CreateReplacement(CreateReplacement),
43 OriginalWhitespaceRange(OriginalWhitespaceRange),
44 StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
45 PreviousLinePostfix(PreviousLinePostfix),
46 CurrentLinePrefix(CurrentLinePrefix), IsAligned(IsAligned),
47 ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces),
48 IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0),
49 PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
50 StartOfBlockComment(nullptr), IndentationOffset(0), ConditionalsLevel(0) {
53 void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
54 unsigned Spaces,
55 unsigned StartOfTokenColumn,
56 bool IsAligned, bool InPPDirective) {
57 if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg))
58 return;
59 Tok.setDecision((Newlines > 0) ? FD_Break : FD_Continue);
60 Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange,
61 Spaces, StartOfTokenColumn, Newlines, "", "",
62 IsAligned, InPPDirective && !Tok.IsFirst,
63 /*IsInsideToken=*/false));
66 void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
67 bool InPPDirective) {
68 if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg))
69 return;
70 Changes.push_back(Change(Tok, /*CreateReplacement=*/false,
71 Tok.WhitespaceRange, /*Spaces=*/0,
72 Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
73 /*IsAligned=*/false, InPPDirective && !Tok.IsFirst,
74 /*IsInsideToken=*/false));
77 llvm::Error
78 WhitespaceManager::addReplacement(const tooling::Replacement &Replacement) {
79 return Replaces.add(Replacement);
82 bool WhitespaceManager::inputUsesCRLF(StringRef Text, bool DefaultToCRLF) {
83 size_t LF = Text.count('\n');
84 size_t CR = Text.count('\r') * 2;
85 return LF == CR ? DefaultToCRLF : CR > LF;
88 void WhitespaceManager::replaceWhitespaceInToken(
89 const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
90 StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
91 unsigned Newlines, int Spaces) {
92 if (Tok.Finalized || (Tok.MacroCtx && Tok.MacroCtx->Role == MR_ExpandedArg))
93 return;
94 SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
95 Changes.push_back(
96 Change(Tok, /*CreateReplacement=*/true,
97 SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces,
98 std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,
99 /*IsAligned=*/true, InPPDirective && !Tok.IsFirst,
100 /*IsInsideToken=*/true));
103 const tooling::Replacements &WhitespaceManager::generateReplacements() {
104 if (Changes.empty())
105 return Replaces;
107 llvm::sort(Changes, Change::IsBeforeInFile(SourceMgr));
108 calculateLineBreakInformation();
109 alignConsecutiveMacros();
110 alignConsecutiveShortCaseStatements();
111 alignConsecutiveDeclarations();
112 alignConsecutiveBitFields();
113 alignConsecutiveAssignments();
114 alignChainedConditionals();
115 alignTrailingComments();
116 alignEscapedNewlines();
117 alignArrayInitializers();
118 generateChanges();
120 return Replaces;
123 void WhitespaceManager::calculateLineBreakInformation() {
124 Changes[0].PreviousEndOfTokenColumn = 0;
125 Change *LastOutsideTokenChange = &Changes[0];
126 for (unsigned i = 1, e = Changes.size(); i != e; ++i) {
127 SourceLocation OriginalWhitespaceStart =
128 Changes[i].OriginalWhitespaceRange.getBegin();
129 SourceLocation PreviousOriginalWhitespaceEnd =
130 Changes[i - 1].OriginalWhitespaceRange.getEnd();
131 unsigned OriginalWhitespaceStartOffset =
132 SourceMgr.getFileOffset(OriginalWhitespaceStart);
133 unsigned PreviousOriginalWhitespaceEndOffset =
134 SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd);
135 assert(PreviousOriginalWhitespaceEndOffset <=
136 OriginalWhitespaceStartOffset);
137 const char *const PreviousOriginalWhitespaceEndData =
138 SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd);
139 StringRef Text(PreviousOriginalWhitespaceEndData,
140 SourceMgr.getCharacterData(OriginalWhitespaceStart) -
141 PreviousOriginalWhitespaceEndData);
142 // Usually consecutive changes would occur in consecutive tokens. This is
143 // not the case however when analyzing some preprocessor runs of the
144 // annotated lines. For example, in this code:
146 // #if A // line 1
147 // int i = 1;
148 // #else B // line 2
149 // int i = 2;
150 // #endif // line 3
152 // one of the runs will produce the sequence of lines marked with line 1, 2
153 // and 3. So the two consecutive whitespace changes just before '// line 2'
154 // and before '#endif // line 3' span multiple lines and tokens:
156 // #else B{change X}[// line 2
157 // int i = 2;
158 // ]{change Y}#endif // line 3
160 // For this reason, if the text between consecutive changes spans multiple
161 // newlines, the token length must be adjusted to the end of the original
162 // line of the token.
163 auto NewlinePos = Text.find_first_of('\n');
164 if (NewlinePos == StringRef::npos) {
165 Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset -
166 PreviousOriginalWhitespaceEndOffset +
167 Changes[i].PreviousLinePostfix.size() +
168 Changes[i - 1].CurrentLinePrefix.size();
169 } else {
170 Changes[i - 1].TokenLength =
171 NewlinePos + Changes[i - 1].CurrentLinePrefix.size();
174 // If there are multiple changes in this token, sum up all the changes until
175 // the end of the line.
176 if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 0) {
177 LastOutsideTokenChange->TokenLength +=
178 Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
179 } else {
180 LastOutsideTokenChange = &Changes[i - 1];
183 Changes[i].PreviousEndOfTokenColumn =
184 Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
186 Changes[i - 1].IsTrailingComment =
187 (Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof) ||
188 (Changes[i].IsInsideToken && Changes[i].Tok->is(tok::comment))) &&
189 Changes[i - 1].Tok->is(tok::comment) &&
190 // FIXME: This is a dirty hack. The problem is that
191 // BreakableLineCommentSection does comment reflow changes and here is
192 // the aligning of trailing comments. Consider the case where we reflow
193 // the second line up in this example:
195 // // line 1
196 // // line 2
198 // That amounts to 2 changes by BreakableLineCommentSection:
199 // - the first, delimited by (), for the whitespace between the tokens,
200 // - and second, delimited by [], for the whitespace at the beginning
201 // of the second token:
203 // // line 1(
204 // )[// ]line 2
206 // So in the end we have two changes like this:
208 // // line1()[ ]line 2
210 // Note that the OriginalWhitespaceStart of the second change is the
211 // same as the PreviousOriginalWhitespaceEnd of the first change.
212 // In this case, the below check ensures that the second change doesn't
213 // get treated as a trailing comment change here, since this might
214 // trigger additional whitespace to be wrongly inserted before "line 2"
215 // by the comment aligner here.
217 // For a proper solution we need a mechanism to say to WhitespaceManager
218 // that a particular change breaks the current sequence of trailing
219 // comments.
220 OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd;
222 // FIXME: The last token is currently not always an eof token; in those
223 // cases, setting TokenLength of the last token to 0 is wrong.
224 Changes.back().TokenLength = 0;
225 Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);
227 const WhitespaceManager::Change *LastBlockComment = nullptr;
228 for (auto &Change : Changes) {
229 // Reset the IsTrailingComment flag for changes inside of trailing comments
230 // so they don't get realigned later. Comment line breaks however still need
231 // to be aligned.
232 if (Change.IsInsideToken && Change.NewlinesBefore == 0)
233 Change.IsTrailingComment = false;
234 Change.StartOfBlockComment = nullptr;
235 Change.IndentationOffset = 0;
236 if (Change.Tok->is(tok::comment)) {
237 if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken) {
238 LastBlockComment = &Change;
239 } else if ((Change.StartOfBlockComment = LastBlockComment)) {
240 Change.IndentationOffset =
241 Change.StartOfTokenColumn -
242 Change.StartOfBlockComment->StartOfTokenColumn;
244 } else {
245 LastBlockComment = nullptr;
249 // Compute conditional nesting level
250 // Level is increased for each conditional, unless this conditional continues
251 // a chain of conditional, i.e. starts immediately after the colon of another
252 // conditional.
253 SmallVector<bool, 16> ScopeStack;
254 int ConditionalsLevel = 0;
255 for (auto &Change : Changes) {
256 for (unsigned i = 0, e = Change.Tok->FakeLParens.size(); i != e; ++i) {
257 bool isNestedConditional =
258 Change.Tok->FakeLParens[e - 1 - i] == prec::Conditional &&
259 !(i == 0 && Change.Tok->Previous &&
260 Change.Tok->Previous->is(TT_ConditionalExpr) &&
261 Change.Tok->Previous->is(tok::colon));
262 if (isNestedConditional)
263 ++ConditionalsLevel;
264 ScopeStack.push_back(isNestedConditional);
267 Change.ConditionalsLevel = ConditionalsLevel;
269 for (unsigned i = Change.Tok->FakeRParens; i > 0 && ScopeStack.size(); --i)
270 if (ScopeStack.pop_back_val())
271 --ConditionalsLevel;
275 // Align a single sequence of tokens, see AlignTokens below.
276 // Column - The token for which Matches returns true is moved to this column.
277 // RightJustify - Whether it is the token's right end or left end that gets
278 // moved to that column.
279 template <typename F>
280 static void
281 AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
282 unsigned Column, bool RightJustify, F &&Matches,
283 SmallVector<WhitespaceManager::Change, 16> &Changes) {
284 bool FoundMatchOnLine = false;
285 int Shift = 0;
287 // ScopeStack keeps track of the current scope depth. It contains indices of
288 // the first token on each scope.
289 // We only run the "Matches" function on tokens from the outer-most scope.
290 // However, we do need to pay special attention to one class of tokens
291 // that are not in the outer-most scope, and that is function parameters
292 // which are split across multiple lines, as illustrated by this example:
293 // double a(int x);
294 // int b(int y,
295 // double z);
296 // In the above example, we need to take special care to ensure that
297 // 'double z' is indented along with it's owning function 'b'.
298 // The same holds for calling a function:
299 // double a = foo(x);
300 // int b = bar(foo(y),
301 // foor(z));
302 // Similar for broken string literals:
303 // double x = 3.14;
304 // auto s = "Hello"
305 // "World";
306 // Special handling is required for 'nested' ternary operators.
307 SmallVector<unsigned, 16> ScopeStack;
309 for (unsigned i = Start; i != End; ++i) {
310 if (ScopeStack.size() != 0 &&
311 Changes[i].indentAndNestingLevel() <
312 Changes[ScopeStack.back()].indentAndNestingLevel()) {
313 ScopeStack.pop_back();
316 // Compare current token to previous non-comment token to ensure whether
317 // it is in a deeper scope or not.
318 unsigned PreviousNonComment = i - 1;
319 while (PreviousNonComment > Start &&
320 Changes[PreviousNonComment].Tok->is(tok::comment)) {
321 --PreviousNonComment;
323 if (i != Start && Changes[i].indentAndNestingLevel() >
324 Changes[PreviousNonComment].indentAndNestingLevel()) {
325 ScopeStack.push_back(i);
328 bool InsideNestedScope = ScopeStack.size() != 0;
329 bool ContinuedStringLiteral = i > Start &&
330 Changes[i].Tok->is(tok::string_literal) &&
331 Changes[i - 1].Tok->is(tok::string_literal);
332 bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral;
334 if (Changes[i].NewlinesBefore > 0 && !SkipMatchCheck) {
335 Shift = 0;
336 FoundMatchOnLine = false;
339 // If this is the first matching token to be aligned, remember by how many
340 // spaces it has to be shifted, so the rest of the changes on the line are
341 // shifted by the same amount
342 if (!FoundMatchOnLine && !SkipMatchCheck && Matches(Changes[i])) {
343 FoundMatchOnLine = true;
344 Shift = Column - (RightJustify ? Changes[i].TokenLength : 0) -
345 Changes[i].StartOfTokenColumn;
346 Changes[i].Spaces += Shift;
347 // FIXME: This is a workaround that should be removed when we fix
348 // http://llvm.org/PR53699. An assertion later below verifies this.
349 if (Changes[i].NewlinesBefore == 0) {
350 Changes[i].Spaces =
351 std::max(Changes[i].Spaces,
352 static_cast<int>(Changes[i].Tok->SpacesRequiredBefore));
356 // This is for function parameters that are split across multiple lines,
357 // as mentioned in the ScopeStack comment.
358 if (InsideNestedScope && Changes[i].NewlinesBefore > 0) {
359 unsigned ScopeStart = ScopeStack.back();
360 auto ShouldShiftBeAdded = [&] {
361 // Function declaration
362 if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName))
363 return true;
365 // Lambda.
366 if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace))
367 return false;
369 // Continued function declaration
370 if (ScopeStart > Start + 1 &&
371 Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) {
372 return true;
375 // Continued function call
376 if (ScopeStart > Start + 1 &&
377 Changes[ScopeStart - 2].Tok->is(tok::identifier) &&
378 Changes[ScopeStart - 1].Tok->is(tok::l_paren) &&
379 Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) {
380 if (Changes[i].Tok->MatchingParen &&
381 Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)) {
382 return false;
384 if (Changes[ScopeStart].NewlinesBefore > 0)
385 return false;
386 if (Changes[i].Tok->is(tok::l_brace) &&
387 Changes[i].Tok->is(BK_BracedInit)) {
388 return true;
390 return Style.BinPackArguments;
393 // Ternary operator
394 if (Changes[i].Tok->is(TT_ConditionalExpr))
395 return true;
397 // Period Initializer .XXX = 1.
398 if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod))
399 return true;
401 // Continued ternary operator
402 if (Changes[i].Tok->Previous &&
403 Changes[i].Tok->Previous->is(TT_ConditionalExpr)) {
404 return true;
407 // Continued direct-list-initialization using braced list.
408 if (ScopeStart > Start + 1 &&
409 Changes[ScopeStart - 2].Tok->is(tok::identifier) &&
410 Changes[ScopeStart - 1].Tok->is(tok::l_brace) &&
411 Changes[i].Tok->is(tok::l_brace) &&
412 Changes[i].Tok->is(BK_BracedInit)) {
413 return true;
416 // Continued braced list.
417 if (ScopeStart > Start + 1 &&
418 Changes[ScopeStart - 2].Tok->isNot(tok::identifier) &&
419 Changes[ScopeStart - 1].Tok->is(tok::l_brace) &&
420 Changes[i].Tok->isNot(tok::r_brace)) {
421 for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) {
422 // Lambda.
423 if (OuterScopeStart > Start &&
424 Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) {
425 return false;
428 if (Changes[ScopeStart].NewlinesBefore > 0)
429 return false;
430 return true;
433 // Continued template parameter.
434 if (Changes[ScopeStart - 1].Tok->is(TT_TemplateOpener))
435 return true;
437 return false;
440 if (ShouldShiftBeAdded())
441 Changes[i].Spaces += Shift;
444 if (ContinuedStringLiteral)
445 Changes[i].Spaces += Shift;
447 // We should not remove required spaces unless we break the line before.
448 assert(Shift >= 0 || Changes[i].NewlinesBefore > 0 ||
449 Changes[i].Spaces >=
450 static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) ||
451 Changes[i].Tok->is(tok::eof));
453 Changes[i].StartOfTokenColumn += Shift;
454 if (i + 1 != Changes.size())
455 Changes[i + 1].PreviousEndOfTokenColumn += Shift;
457 // If PointerAlignment is PAS_Right, keep *s or &s next to the token
458 if ((Style.PointerAlignment == FormatStyle::PAS_Right ||
459 Style.ReferenceAlignment == FormatStyle::RAS_Right) &&
460 Changes[i].Spaces != 0) {
461 const bool ReferenceNotRightAligned =
462 Style.ReferenceAlignment != FormatStyle::RAS_Right &&
463 Style.ReferenceAlignment != FormatStyle::RAS_Pointer;
464 for (int Previous = i - 1;
465 Previous >= 0 &&
466 Changes[Previous].Tok->getType() == TT_PointerOrReference;
467 --Previous) {
468 assert(
469 Changes[Previous].Tok->isOneOf(tok::star, tok::amp, tok::ampamp));
470 if (Changes[Previous].Tok->isNot(tok::star)) {
471 if (ReferenceNotRightAligned)
472 continue;
473 } else if (Style.PointerAlignment != FormatStyle::PAS_Right) {
474 continue;
476 Changes[Previous + 1].Spaces -= Shift;
477 Changes[Previous].Spaces += Shift;
478 Changes[Previous].StartOfTokenColumn += Shift;
484 // Walk through a subset of the changes, starting at StartAt, and find
485 // sequences of matching tokens to align. To do so, keep track of the lines and
486 // whether or not a matching token was found on a line. If a matching token is
487 // found, extend the current sequence. If the current line cannot be part of a
488 // sequence, e.g. because there is an empty line before it or it contains only
489 // non-matching tokens, finalize the previous sequence.
490 // The value returned is the token on which we stopped, either because we
491 // exhausted all items inside Changes, or because we hit a scope level higher
492 // than our initial scope.
493 // This function is recursive. Each invocation processes only the scope level
494 // equal to the initial level, which is the level of Changes[StartAt].
495 // If we encounter a scope level greater than the initial level, then we call
496 // ourselves recursively, thereby avoiding the pollution of the current state
497 // with the alignment requirements of the nested sub-level. This recursive
498 // behavior is necessary for aligning function prototypes that have one or more
499 // arguments.
500 // If this function encounters a scope level less than the initial level,
501 // it returns the current position.
502 // There is a non-obvious subtlety in the recursive behavior: Even though we
503 // defer processing of nested levels to recursive invocations of this
504 // function, when it comes time to align a sequence of tokens, we run the
505 // alignment on the entire sequence, including the nested levels.
506 // When doing so, most of the nested tokens are skipped, because their
507 // alignment was already handled by the recursive invocations of this function.
508 // However, the special exception is that we do NOT skip function parameters
509 // that are split across multiple lines. See the test case in FormatTest.cpp
510 // that mentions "split function parameter alignment" for an example of this.
511 // When the parameter RightJustify is true, the operator will be
512 // right-justified. It is used to align compound assignments like `+=` and `=`.
513 // When RightJustify and ACS.PadOperators are true, operators in each block to
514 // be aligned will be padded on the left to the same length before aligning.
515 template <typename F>
516 static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
517 SmallVector<WhitespaceManager::Change, 16> &Changes,
518 unsigned StartAt,
519 const FormatStyle::AlignConsecutiveStyle &ACS = {},
520 bool RightJustify = false) {
521 // We arrange each line in 3 parts. The operator to be aligned (the anchor),
522 // and text to its left and right. In the aligned text the width of each part
523 // will be the maximum of that over the block that has been aligned. Maximum
524 // widths of each part so far. When RightJustify is true and ACS.PadOperators
525 // is false, the part from start of line to the right end of the anchor.
526 // Otherwise, only the part to the left of the anchor. Including the space
527 // that exists on its left from the start. Not including the padding added on
528 // the left to right-justify the anchor.
529 unsigned WidthLeft = 0;
530 // The operator to be aligned when RightJustify is true and ACS.PadOperators
531 // is false. 0 otherwise.
532 unsigned WidthAnchor = 0;
533 // Width to the right of the anchor. Plus width of the anchor when
534 // RightJustify is false.
535 unsigned WidthRight = 0;
537 // Line number of the start and the end of the current token sequence.
538 unsigned StartOfSequence = 0;
539 unsigned EndOfSequence = 0;
541 // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
542 // abort when we hit any token in a higher scope than the starting one.
543 auto IndentAndNestingLevel = StartAt < Changes.size()
544 ? Changes[StartAt].indentAndNestingLevel()
545 : std::tuple<unsigned, unsigned, unsigned>();
547 // Keep track of the number of commas before the matching tokens, we will only
548 // align a sequence of matching tokens if they are preceded by the same number
549 // of commas.
550 unsigned CommasBeforeLastMatch = 0;
551 unsigned CommasBeforeMatch = 0;
553 // Whether a matching token has been found on the current line.
554 bool FoundMatchOnLine = false;
556 // Whether the current line consists purely of comments.
557 bool LineIsComment = true;
559 // Aligns a sequence of matching tokens, on the MinColumn column.
561 // Sequences start from the first matching token to align, and end at the
562 // first token of the first line that doesn't need to be aligned.
564 // We need to adjust the StartOfTokenColumn of each Change that is on a line
565 // containing any matching token to be aligned and located after such token.
566 auto AlignCurrentSequence = [&] {
567 if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {
568 AlignTokenSequence(Style, StartOfSequence, EndOfSequence,
569 WidthLeft + WidthAnchor, RightJustify, Matches,
570 Changes);
572 WidthLeft = 0;
573 WidthAnchor = 0;
574 WidthRight = 0;
575 StartOfSequence = 0;
576 EndOfSequence = 0;
579 unsigned i = StartAt;
580 for (unsigned e = Changes.size(); i != e; ++i) {
581 if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
582 break;
584 if (Changes[i].NewlinesBefore != 0) {
585 CommasBeforeMatch = 0;
586 EndOfSequence = i;
588 // Whether to break the alignment sequence because of an empty line.
589 bool EmptyLineBreak =
590 (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines;
592 // Whether to break the alignment sequence because of a line without a
593 // match.
594 bool NoMatchBreak =
595 !FoundMatchOnLine && !(LineIsComment && ACS.AcrossComments);
597 if (EmptyLineBreak || NoMatchBreak)
598 AlignCurrentSequence();
600 // A new line starts, re-initialize line status tracking bools.
601 // Keep the match state if a string literal is continued on this line.
602 if (i == 0 || Changes[i].Tok->isNot(tok::string_literal) ||
603 Changes[i - 1].Tok->isNot(tok::string_literal)) {
604 FoundMatchOnLine = false;
606 LineIsComment = true;
609 if (Changes[i].Tok->isNot(tok::comment))
610 LineIsComment = false;
612 if (Changes[i].Tok->is(tok::comma)) {
613 ++CommasBeforeMatch;
614 } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
615 // Call AlignTokens recursively, skipping over this scope block.
616 unsigned StoppedAt =
617 AlignTokens(Style, Matches, Changes, i, ACS, RightJustify);
618 i = StoppedAt - 1;
619 continue;
622 if (!Matches(Changes[i]))
623 continue;
625 // If there is more than one matching token per line, or if the number of
626 // preceding commas, do not match anymore, end the sequence.
627 if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)
628 AlignCurrentSequence();
630 CommasBeforeLastMatch = CommasBeforeMatch;
631 FoundMatchOnLine = true;
633 if (StartOfSequence == 0)
634 StartOfSequence = i;
636 unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn;
637 unsigned ChangeWidthAnchor = 0;
638 unsigned ChangeWidthRight = 0;
639 if (RightJustify)
640 if (ACS.PadOperators)
641 ChangeWidthAnchor = Changes[i].TokenLength;
642 else
643 ChangeWidthLeft += Changes[i].TokenLength;
644 else
645 ChangeWidthRight = Changes[i].TokenLength;
646 for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 0; ++j) {
647 ChangeWidthRight += Changes[j].Spaces;
648 // Changes are generally 1:1 with the tokens, but a change could also be
649 // inside of a token, in which case it's counted more than once: once for
650 // the whitespace surrounding the token (!IsInsideToken) and once for
651 // each whitespace change within it (IsInsideToken).
652 // Therefore, changes inside of a token should only count the space.
653 if (!Changes[j].IsInsideToken)
654 ChangeWidthRight += Changes[j].TokenLength;
657 // If we are restricted by the maximum column width, end the sequence.
658 unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft);
659 unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor);
660 unsigned NewRight = std::max(ChangeWidthRight, WidthRight);
661 // `ColumnLimit == 0` means there is no column limit.
662 if (Style.ColumnLimit != 0 &&
663 Style.ColumnLimit < NewLeft + NewAnchor + NewRight) {
664 AlignCurrentSequence();
665 StartOfSequence = i;
666 WidthLeft = ChangeWidthLeft;
667 WidthAnchor = ChangeWidthAnchor;
668 WidthRight = ChangeWidthRight;
669 } else {
670 WidthLeft = NewLeft;
671 WidthAnchor = NewAnchor;
672 WidthRight = NewRight;
676 EndOfSequence = i;
677 AlignCurrentSequence();
678 return i;
681 // Aligns a sequence of matching tokens, on the MinColumn column.
683 // Sequences start from the first matching token to align, and end at the
684 // first token of the first line that doesn't need to be aligned.
686 // We need to adjust the StartOfTokenColumn of each Change that is on a line
687 // containing any matching token to be aligned and located after such token.
688 static void AlignMatchingTokenSequence(
689 unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn,
690 std::function<bool(const WhitespaceManager::Change &C)> Matches,
691 SmallVector<WhitespaceManager::Change, 16> &Changes) {
692 if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {
693 bool FoundMatchOnLine = false;
694 int Shift = 0;
696 for (unsigned I = StartOfSequence; I != EndOfSequence; ++I) {
697 if (Changes[I].NewlinesBefore > 0) {
698 Shift = 0;
699 FoundMatchOnLine = false;
702 // If this is the first matching token to be aligned, remember by how many
703 // spaces it has to be shifted, so the rest of the changes on the line are
704 // shifted by the same amount.
705 if (!FoundMatchOnLine && Matches(Changes[I])) {
706 FoundMatchOnLine = true;
707 Shift = MinColumn - Changes[I].StartOfTokenColumn;
708 Changes[I].Spaces += Shift;
711 assert(Shift >= 0);
712 Changes[I].StartOfTokenColumn += Shift;
713 if (I + 1 != Changes.size())
714 Changes[I + 1].PreviousEndOfTokenColumn += Shift;
718 MinColumn = 0;
719 StartOfSequence = 0;
720 EndOfSequence = 0;
723 void WhitespaceManager::alignConsecutiveMacros() {
724 if (!Style.AlignConsecutiveMacros.Enabled)
725 return;
727 auto AlignMacrosMatches = [](const Change &C) {
728 const FormatToken *Current = C.Tok;
729 unsigned SpacesRequiredBefore = 1;
731 if (Current->SpacesRequiredBefore == 0 || !Current->Previous)
732 return false;
734 Current = Current->Previous;
736 // If token is a ")", skip over the parameter list, to the
737 // token that precedes the "("
738 if (Current->is(tok::r_paren) && Current->MatchingParen) {
739 Current = Current->MatchingParen->Previous;
740 SpacesRequiredBefore = 0;
743 if (!Current || Current->isNot(tok::identifier))
744 return false;
746 if (!Current->Previous || Current->Previous->isNot(tok::pp_define))
747 return false;
749 // For a macro function, 0 spaces are required between the
750 // identifier and the lparen that opens the parameter list.
751 // For a simple macro, 1 space is required between the
752 // identifier and the first token of the defined value.
753 return Current->Next->SpacesRequiredBefore == SpacesRequiredBefore;
756 unsigned MinColumn = 0;
758 // Start and end of the token sequence we're processing.
759 unsigned StartOfSequence = 0;
760 unsigned EndOfSequence = 0;
762 // Whether a matching token has been found on the current line.
763 bool FoundMatchOnLine = false;
765 // Whether the current line consists only of comments
766 bool LineIsComment = true;
768 unsigned I = 0;
769 for (unsigned E = Changes.size(); I != E; ++I) {
770 if (Changes[I].NewlinesBefore != 0) {
771 EndOfSequence = I;
773 // Whether to break the alignment sequence because of an empty line.
774 bool EmptyLineBreak = (Changes[I].NewlinesBefore > 1) &&
775 !Style.AlignConsecutiveMacros.AcrossEmptyLines;
777 // Whether to break the alignment sequence because of a line without a
778 // match.
779 bool NoMatchBreak =
780 !FoundMatchOnLine &&
781 !(LineIsComment && Style.AlignConsecutiveMacros.AcrossComments);
783 if (EmptyLineBreak || NoMatchBreak) {
784 AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
785 AlignMacrosMatches, Changes);
788 // A new line starts, re-initialize line status tracking bools.
789 FoundMatchOnLine = false;
790 LineIsComment = true;
793 if (Changes[I].Tok->isNot(tok::comment))
794 LineIsComment = false;
796 if (!AlignMacrosMatches(Changes[I]))
797 continue;
799 FoundMatchOnLine = true;
801 if (StartOfSequence == 0)
802 StartOfSequence = I;
804 unsigned ChangeMinColumn = Changes[I].StartOfTokenColumn;
805 MinColumn = std::max(MinColumn, ChangeMinColumn);
808 EndOfSequence = I;
809 AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
810 AlignMacrosMatches, Changes);
813 void WhitespaceManager::alignConsecutiveAssignments() {
814 if (!Style.AlignConsecutiveAssignments.Enabled)
815 return;
817 AlignTokens(
818 Style,
819 [&](const Change &C) {
820 // Do not align on equal signs that are first on a line.
821 if (C.NewlinesBefore > 0)
822 return false;
824 // Do not align on equal signs that are last on a line.
825 if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
826 return false;
828 // Do not align operator= overloads.
829 FormatToken *Previous = C.Tok->getPreviousNonComment();
830 if (Previous && Previous->is(tok::kw_operator))
831 return false;
833 return Style.AlignConsecutiveAssignments.AlignCompound
834 ? C.Tok->getPrecedence() == prec::Assignment
835 : (C.Tok->is(tok::equal) ||
836 // In Verilog the '<=' is not a compound assignment, thus
837 // it is aligned even when the AlignCompound option is not
838 // set.
839 (Style.isVerilog() && C.Tok->is(tok::lessequal) &&
840 C.Tok->getPrecedence() == prec::Assignment));
842 Changes, /*StartAt=*/0, Style.AlignConsecutiveAssignments,
843 /*RightJustify=*/true);
846 void WhitespaceManager::alignConsecutiveBitFields() {
847 if (!Style.AlignConsecutiveBitFields.Enabled)
848 return;
850 AlignTokens(
851 Style,
852 [&](Change const &C) {
853 // Do not align on ':' that is first on a line.
854 if (C.NewlinesBefore > 0)
855 return false;
857 // Do not align on ':' that is last on a line.
858 if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
859 return false;
861 return C.Tok->is(TT_BitFieldColon);
863 Changes, /*StartAt=*/0, Style.AlignConsecutiveBitFields);
866 void WhitespaceManager::alignConsecutiveShortCaseStatements() {
867 if (!Style.AlignConsecutiveShortCaseStatements.Enabled ||
868 !Style.AllowShortCaseLabelsOnASingleLine) {
869 return;
872 auto Matches = [&](const Change &C) {
873 if (Style.AlignConsecutiveShortCaseStatements.AlignCaseColons)
874 return C.Tok->is(TT_CaseLabelColon);
876 // Ignore 'IsInsideToken' to allow matching trailing comments which
877 // need to be reflowed as that causes the token to appear in two
878 // different changes, which will cause incorrect alignment as we'll
879 // reflow early due to detecting multiple aligning tokens per line.
880 return !C.IsInsideToken && C.Tok->Previous &&
881 C.Tok->Previous->is(TT_CaseLabelColon);
884 unsigned MinColumn = 0;
886 // Empty case statements don't break the alignment, but don't necessarily
887 // match our predicate, so we need to track their column so they can push out
888 // our alignment.
889 unsigned MinEmptyCaseColumn = 0;
891 // Start and end of the token sequence we're processing.
892 unsigned StartOfSequence = 0;
893 unsigned EndOfSequence = 0;
895 // Whether a matching token has been found on the current line.
896 bool FoundMatchOnLine = false;
898 bool LineIsComment = true;
899 bool LineIsEmptyCase = false;
901 unsigned I = 0;
902 for (unsigned E = Changes.size(); I != E; ++I) {
903 if (Changes[I].NewlinesBefore != 0) {
904 // Whether to break the alignment sequence because of an empty line.
905 bool EmptyLineBreak =
906 (Changes[I].NewlinesBefore > 1) &&
907 !Style.AlignConsecutiveShortCaseStatements.AcrossEmptyLines;
909 // Whether to break the alignment sequence because of a line without a
910 // match.
911 bool NoMatchBreak =
912 !FoundMatchOnLine &&
913 !(LineIsComment &&
914 Style.AlignConsecutiveShortCaseStatements.AcrossComments) &&
915 !LineIsEmptyCase;
917 if (EmptyLineBreak || NoMatchBreak) {
918 AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
919 Matches, Changes);
920 MinEmptyCaseColumn = 0;
923 // A new line starts, re-initialize line status tracking bools.
924 FoundMatchOnLine = false;
925 LineIsComment = true;
926 LineIsEmptyCase = false;
929 if (Changes[I].Tok->isNot(tok::comment))
930 LineIsComment = false;
932 if (Changes[I].Tok->is(TT_CaseLabelColon)) {
933 LineIsEmptyCase =
934 !Changes[I].Tok->Next || Changes[I].Tok->Next->isTrailingComment();
936 if (LineIsEmptyCase) {
937 if (Style.AlignConsecutiveShortCaseStatements.AlignCaseColons) {
938 MinEmptyCaseColumn =
939 std::max(MinEmptyCaseColumn, Changes[I].StartOfTokenColumn);
940 } else {
941 MinEmptyCaseColumn =
942 std::max(MinEmptyCaseColumn, Changes[I].StartOfTokenColumn + 2);
947 if (!Matches(Changes[I]))
948 continue;
950 if (LineIsEmptyCase)
951 continue;
953 FoundMatchOnLine = true;
955 if (StartOfSequence == 0)
956 StartOfSequence = I;
958 EndOfSequence = I + 1;
960 MinColumn = std::max(MinColumn, Changes[I].StartOfTokenColumn);
962 // Allow empty case statements to push out our alignment.
963 MinColumn = std::max(MinColumn, MinEmptyCaseColumn);
966 AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
967 Changes);
970 void WhitespaceManager::alignConsecutiveDeclarations() {
971 if (!Style.AlignConsecutiveDeclarations.Enabled)
972 return;
974 AlignTokens(
975 Style,
976 [](Change const &C) {
977 if (C.Tok->isOneOf(TT_FunctionDeclarationName, TT_FunctionTypeLParen))
978 return true;
979 if (C.Tok->isNot(TT_StartOfName))
980 return false;
981 if (C.Tok->Previous &&
982 C.Tok->Previous->is(TT_StatementAttributeLikeMacro))
983 return false;
984 // Check if there is a subsequent name that starts the same declaration.
985 for (FormatToken *Next = C.Tok->Next; Next; Next = Next->Next) {
986 if (Next->is(tok::comment))
987 continue;
988 if (Next->is(TT_PointerOrReference))
989 return false;
990 if (!Next->Tok.getIdentifierInfo())
991 break;
992 if (Next->isOneOf(TT_StartOfName, TT_FunctionDeclarationName,
993 tok::kw_operator)) {
994 return false;
997 return true;
999 Changes, /*StartAt=*/0, Style.AlignConsecutiveDeclarations);
1002 void WhitespaceManager::alignChainedConditionals() {
1003 if (Style.BreakBeforeTernaryOperators) {
1004 AlignTokens(
1005 Style,
1006 [](Change const &C) {
1007 // Align question operators and last colon
1008 return C.Tok->is(TT_ConditionalExpr) &&
1009 ((C.Tok->is(tok::question) && !C.NewlinesBefore) ||
1010 (C.Tok->is(tok::colon) && C.Tok->Next &&
1011 (C.Tok->Next->FakeLParens.size() == 0 ||
1012 C.Tok->Next->FakeLParens.back() != prec::Conditional)));
1014 Changes, /*StartAt=*/0);
1015 } else {
1016 static auto AlignWrappedOperand = [](Change const &C) {
1017 FormatToken *Previous = C.Tok->getPreviousNonComment();
1018 return C.NewlinesBefore && Previous && Previous->is(TT_ConditionalExpr) &&
1019 (Previous->is(tok::colon) &&
1020 (C.Tok->FakeLParens.size() == 0 ||
1021 C.Tok->FakeLParens.back() != prec::Conditional));
1023 // Ensure we keep alignment of wrapped operands with non-wrapped operands
1024 // Since we actually align the operators, the wrapped operands need the
1025 // extra offset to be properly aligned.
1026 for (Change &C : Changes)
1027 if (AlignWrappedOperand(C))
1028 C.StartOfTokenColumn -= 2;
1029 AlignTokens(
1030 Style,
1031 [this](Change const &C) {
1032 // Align question operators if next operand is not wrapped, as
1033 // well as wrapped operands after question operator or last
1034 // colon in conditional sequence
1035 return (C.Tok->is(TT_ConditionalExpr) && C.Tok->is(tok::question) &&
1036 &C != &Changes.back() && (&C + 1)->NewlinesBefore == 0 &&
1037 !(&C + 1)->IsTrailingComment) ||
1038 AlignWrappedOperand(C);
1040 Changes, /*StartAt=*/0);
1044 void WhitespaceManager::alignTrailingComments() {
1045 unsigned MinColumn = 0;
1046 unsigned MaxColumn = UINT_MAX;
1047 unsigned StartOfSequence = 0;
1048 bool BreakBeforeNext = false;
1049 unsigned Newlines = 0;
1050 unsigned int NewLineThreshold = 1;
1051 if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Always)
1052 NewLineThreshold = Style.AlignTrailingComments.OverEmptyLines + 1;
1054 for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
1055 if (Changes[i].StartOfBlockComment)
1056 continue;
1057 Newlines += Changes[i].NewlinesBefore;
1058 if (!Changes[i].IsTrailingComment)
1059 continue;
1061 if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Leave) {
1062 auto OriginalSpaces =
1063 Changes[i].OriginalWhitespaceRange.getEnd().getRawEncoding() -
1064 Changes[i].OriginalWhitespaceRange.getBegin().getRawEncoding() -
1065 Changes[i].Tok->NewlinesBefore;
1066 unsigned RestoredLineLength = Changes[i].StartOfTokenColumn +
1067 Changes[i].TokenLength + OriginalSpaces;
1068 // If leaving comments makes the line exceed the column limit, give up to
1069 // leave the comments.
1070 if (RestoredLineLength >= Style.ColumnLimit && Style.ColumnLimit != 0)
1071 break;
1072 Changes[i].Spaces = OriginalSpaces;
1073 continue;
1076 unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
1077 unsigned ChangeMaxColumn;
1079 if (Style.ColumnLimit == 0)
1080 ChangeMaxColumn = UINT_MAX;
1081 else if (Style.ColumnLimit >= Changes[i].TokenLength)
1082 ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
1083 else
1084 ChangeMaxColumn = ChangeMinColumn;
1086 // If we don't create a replacement for this change, we have to consider
1087 // it to be immovable.
1088 if (!Changes[i].CreateReplacement)
1089 ChangeMaxColumn = ChangeMinColumn;
1091 if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
1092 ChangeMaxColumn -= 2;
1094 // We don't want to align namespace end comments.
1095 bool DontAlignThisComment = i > 0 && Changes[i].NewlinesBefore == 0 &&
1096 Changes[i - 1].Tok->is(TT_NamespaceRBrace);
1097 bool WasAlignedWithStartOfNextLine = false;
1098 if (Changes[i].NewlinesBefore >= 1) { // A comment on its own line.
1099 unsigned CommentColumn = SourceMgr.getSpellingColumnNumber(
1100 Changes[i].OriginalWhitespaceRange.getEnd());
1101 for (unsigned j = i + 1; j != e; ++j) {
1102 if (Changes[j].Tok->is(tok::comment))
1103 continue;
1105 unsigned NextColumn = SourceMgr.getSpellingColumnNumber(
1106 Changes[j].OriginalWhitespaceRange.getEnd());
1107 // The start of the next token was previously aligned with the
1108 // start of this comment.
1109 WasAlignedWithStartOfNextLine =
1110 CommentColumn == NextColumn ||
1111 CommentColumn == NextColumn + Style.IndentWidth;
1112 break;
1115 if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Never ||
1116 DontAlignThisComment) {
1117 alignTrailingComments(StartOfSequence, i, MinColumn);
1118 MinColumn = ChangeMinColumn;
1119 MaxColumn = ChangeMinColumn;
1120 StartOfSequence = i;
1121 } else if (BreakBeforeNext || Newlines > NewLineThreshold ||
1122 (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
1123 // Break the comment sequence if the previous line did not end
1124 // in a trailing comment.
1125 (Changes[i].NewlinesBefore == 1 && i > 0 &&
1126 !Changes[i - 1].IsTrailingComment) ||
1127 WasAlignedWithStartOfNextLine) {
1128 alignTrailingComments(StartOfSequence, i, MinColumn);
1129 MinColumn = ChangeMinColumn;
1130 MaxColumn = ChangeMaxColumn;
1131 StartOfSequence = i;
1132 } else {
1133 MinColumn = std::max(MinColumn, ChangeMinColumn);
1134 MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
1136 BreakBeforeNext = (i == 0) || (Changes[i].NewlinesBefore > 1) ||
1137 // Never start a sequence with a comment at the beginning
1138 // of the line.
1139 (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
1140 Newlines = 0;
1142 alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
1145 void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
1146 unsigned Column) {
1147 for (unsigned i = Start; i != End; ++i) {
1148 int Shift = 0;
1149 if (Changes[i].IsTrailingComment)
1150 Shift = Column - Changes[i].StartOfTokenColumn;
1151 if (Changes[i].StartOfBlockComment) {
1152 Shift = Changes[i].IndentationOffset +
1153 Changes[i].StartOfBlockComment->StartOfTokenColumn -
1154 Changes[i].StartOfTokenColumn;
1156 if (Shift <= 0)
1157 continue;
1158 Changes[i].Spaces += Shift;
1159 if (i + 1 != Changes.size())
1160 Changes[i + 1].PreviousEndOfTokenColumn += Shift;
1161 Changes[i].StartOfTokenColumn += Shift;
1165 void WhitespaceManager::alignEscapedNewlines() {
1166 if (Style.AlignEscapedNewlines == FormatStyle::ENAS_DontAlign)
1167 return;
1169 bool AlignLeft = Style.AlignEscapedNewlines == FormatStyle::ENAS_Left;
1170 unsigned MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit;
1171 unsigned StartOfMacro = 0;
1172 for (unsigned i = 1, e = Changes.size(); i < e; ++i) {
1173 Change &C = Changes[i];
1174 if (C.NewlinesBefore > 0) {
1175 if (C.ContinuesPPDirective) {
1176 MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine);
1177 } else {
1178 alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
1179 MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit;
1180 StartOfMacro = i;
1184 alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
1187 void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End,
1188 unsigned Column) {
1189 for (unsigned i = Start; i < End; ++i) {
1190 Change &C = Changes[i];
1191 if (C.NewlinesBefore > 0) {
1192 assert(C.ContinuesPPDirective);
1193 if (C.PreviousEndOfTokenColumn + 1 > Column)
1194 C.EscapedNewlineColumn = 0;
1195 else
1196 C.EscapedNewlineColumn = Column;
1201 void WhitespaceManager::alignArrayInitializers() {
1202 if (Style.AlignArrayOfStructures == FormatStyle::AIAS_None)
1203 return;
1205 for (unsigned ChangeIndex = 1U, ChangeEnd = Changes.size();
1206 ChangeIndex < ChangeEnd; ++ChangeIndex) {
1207 auto &C = Changes[ChangeIndex];
1208 if (C.Tok->IsArrayInitializer) {
1209 bool FoundComplete = false;
1210 for (unsigned InsideIndex = ChangeIndex + 1; InsideIndex < ChangeEnd;
1211 ++InsideIndex) {
1212 if (Changes[InsideIndex].Tok == C.Tok->MatchingParen) {
1213 alignArrayInitializers(ChangeIndex, InsideIndex + 1);
1214 ChangeIndex = InsideIndex + 1;
1215 FoundComplete = true;
1216 break;
1219 if (!FoundComplete)
1220 ChangeIndex = ChangeEnd;
1225 void WhitespaceManager::alignArrayInitializers(unsigned Start, unsigned End) {
1227 if (Style.AlignArrayOfStructures == FormatStyle::AIAS_Right)
1228 alignArrayInitializersRightJustified(getCells(Start, End));
1229 else if (Style.AlignArrayOfStructures == FormatStyle::AIAS_Left)
1230 alignArrayInitializersLeftJustified(getCells(Start, End));
1233 void WhitespaceManager::alignArrayInitializersRightJustified(
1234 CellDescriptions &&CellDescs) {
1235 if (!CellDescs.isRectangular())
1236 return;
1238 const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1;
1239 auto &Cells = CellDescs.Cells;
1240 // Now go through and fixup the spaces.
1241 auto *CellIter = Cells.begin();
1242 for (auto i = 0U; i < CellDescs.CellCounts[0]; ++i, ++CellIter) {
1243 unsigned NetWidth = 0U;
1244 if (isSplitCell(*CellIter))
1245 NetWidth = getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
1246 auto CellWidth = getMaximumCellWidth(CellIter, NetWidth);
1248 if (Changes[CellIter->Index].Tok->is(tok::r_brace)) {
1249 // So in here we want to see if there is a brace that falls
1250 // on a line that was split. If so on that line we make sure that
1251 // the spaces in front of the brace are enough.
1252 const auto *Next = CellIter;
1253 do {
1254 const FormatToken *Previous = Changes[Next->Index].Tok->Previous;
1255 if (Previous && Previous->isNot(TT_LineComment)) {
1256 Changes[Next->Index].Spaces = BracePadding;
1257 Changes[Next->Index].NewlinesBefore = 0;
1259 Next = Next->NextColumnElement;
1260 } while (Next);
1261 // Unless the array is empty, we need the position of all the
1262 // immediately adjacent cells
1263 if (CellIter != Cells.begin()) {
1264 auto ThisNetWidth =
1265 getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
1266 auto MaxNetWidth = getMaximumNetWidth(
1267 Cells.begin(), CellIter, CellDescs.InitialSpaces,
1268 CellDescs.CellCounts[0], CellDescs.CellCounts.size());
1269 if (ThisNetWidth < MaxNetWidth)
1270 Changes[CellIter->Index].Spaces = (MaxNetWidth - ThisNetWidth);
1271 auto RowCount = 1U;
1272 auto Offset = std::distance(Cells.begin(), CellIter);
1273 for (const auto *Next = CellIter->NextColumnElement; Next;
1274 Next = Next->NextColumnElement) {
1275 auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]);
1276 auto *End = Start + Offset;
1277 ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces);
1278 if (ThisNetWidth < MaxNetWidth)
1279 Changes[Next->Index].Spaces = (MaxNetWidth - ThisNetWidth);
1280 ++RowCount;
1283 } else {
1284 auto ThisWidth =
1285 calculateCellWidth(CellIter->Index, CellIter->EndIndex, true) +
1286 NetWidth;
1287 if (Changes[CellIter->Index].NewlinesBefore == 0) {
1288 Changes[CellIter->Index].Spaces = (CellWidth - (ThisWidth + NetWidth));
1289 Changes[CellIter->Index].Spaces += (i > 0) ? 1 : BracePadding;
1291 alignToStartOfCell(CellIter->Index, CellIter->EndIndex);
1292 for (const auto *Next = CellIter->NextColumnElement; Next;
1293 Next = Next->NextColumnElement) {
1294 ThisWidth =
1295 calculateCellWidth(Next->Index, Next->EndIndex, true) + NetWidth;
1296 if (Changes[Next->Index].NewlinesBefore == 0) {
1297 Changes[Next->Index].Spaces = (CellWidth - ThisWidth);
1298 Changes[Next->Index].Spaces += (i > 0) ? 1 : BracePadding;
1300 alignToStartOfCell(Next->Index, Next->EndIndex);
1306 void WhitespaceManager::alignArrayInitializersLeftJustified(
1307 CellDescriptions &&CellDescs) {
1309 if (!CellDescs.isRectangular())
1310 return;
1312 const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1;
1313 auto &Cells = CellDescs.Cells;
1314 // Now go through and fixup the spaces.
1315 auto *CellIter = Cells.begin();
1316 // The first cell needs to be against the left brace.
1317 if (Changes[CellIter->Index].NewlinesBefore == 0)
1318 Changes[CellIter->Index].Spaces = BracePadding;
1319 else
1320 Changes[CellIter->Index].Spaces = CellDescs.InitialSpaces;
1321 ++CellIter;
1322 for (auto i = 1U; i < CellDescs.CellCounts[0]; i++, ++CellIter) {
1323 auto MaxNetWidth = getMaximumNetWidth(
1324 Cells.begin(), CellIter, CellDescs.InitialSpaces,
1325 CellDescs.CellCounts[0], CellDescs.CellCounts.size());
1326 auto ThisNetWidth =
1327 getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
1328 if (Changes[CellIter->Index].NewlinesBefore == 0) {
1329 Changes[CellIter->Index].Spaces =
1330 MaxNetWidth - ThisNetWidth +
1331 (Changes[CellIter->Index].Tok->isNot(tok::r_brace) ? 1
1332 : BracePadding);
1334 auto RowCount = 1U;
1335 auto Offset = std::distance(Cells.begin(), CellIter);
1336 for (const auto *Next = CellIter->NextColumnElement; Next;
1337 Next = Next->NextColumnElement) {
1338 if (RowCount > CellDescs.CellCounts.size())
1339 break;
1340 auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]);
1341 auto *End = Start + Offset;
1342 auto ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces);
1343 if (Changes[Next->Index].NewlinesBefore == 0) {
1344 Changes[Next->Index].Spaces =
1345 MaxNetWidth - ThisNetWidth +
1346 (Changes[Next->Index].Tok->isNot(tok::r_brace) ? 1 : BracePadding);
1348 ++RowCount;
1353 bool WhitespaceManager::isSplitCell(const CellDescription &Cell) {
1354 if (Cell.HasSplit)
1355 return true;
1356 for (const auto *Next = Cell.NextColumnElement; Next;
1357 Next = Next->NextColumnElement) {
1358 if (Next->HasSplit)
1359 return true;
1361 return false;
1364 WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start,
1365 unsigned End) {
1367 unsigned Depth = 0;
1368 unsigned Cell = 0;
1369 SmallVector<unsigned> CellCounts;
1370 unsigned InitialSpaces = 0;
1371 unsigned InitialTokenLength = 0;
1372 unsigned EndSpaces = 0;
1373 SmallVector<CellDescription> Cells;
1374 const FormatToken *MatchingParen = nullptr;
1375 for (unsigned i = Start; i < End; ++i) {
1376 auto &C = Changes[i];
1377 if (C.Tok->is(tok::l_brace))
1378 ++Depth;
1379 else if (C.Tok->is(tok::r_brace))
1380 --Depth;
1381 if (Depth == 2) {
1382 if (C.Tok->is(tok::l_brace)) {
1383 Cell = 0;
1384 MatchingParen = C.Tok->MatchingParen;
1385 if (InitialSpaces == 0) {
1386 InitialSpaces = C.Spaces + C.TokenLength;
1387 InitialTokenLength = C.TokenLength;
1388 auto j = i - 1;
1389 for (; Changes[j].NewlinesBefore == 0 && j > Start; --j) {
1390 InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength;
1391 InitialTokenLength += Changes[j].TokenLength;
1393 if (C.NewlinesBefore == 0) {
1394 InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength;
1395 InitialTokenLength += Changes[j].TokenLength;
1398 } else if (C.Tok->is(tok::comma)) {
1399 if (!Cells.empty())
1400 Cells.back().EndIndex = i;
1401 if (C.Tok->getNextNonComment()->isNot(tok::r_brace)) // dangling comma
1402 ++Cell;
1404 } else if (Depth == 1) {
1405 if (C.Tok == MatchingParen) {
1406 if (!Cells.empty())
1407 Cells.back().EndIndex = i;
1408 Cells.push_back(CellDescription{i, ++Cell, i + 1, false, nullptr});
1409 CellCounts.push_back(C.Tok->Previous->isNot(tok::comma) ? Cell + 1
1410 : Cell);
1411 // Go to the next non-comment and ensure there is a break in front
1412 const auto *NextNonComment = C.Tok->getNextNonComment();
1413 while (NextNonComment->is(tok::comma))
1414 NextNonComment = NextNonComment->getNextNonComment();
1415 auto j = i;
1416 while (Changes[j].Tok != NextNonComment && j < End)
1417 ++j;
1418 if (j < End && Changes[j].NewlinesBefore == 0 &&
1419 Changes[j].Tok->isNot(tok::r_brace)) {
1420 Changes[j].NewlinesBefore = 1;
1421 // Account for the added token lengths
1422 Changes[j].Spaces = InitialSpaces - InitialTokenLength;
1424 } else if (C.Tok->is(tok::comment)) {
1425 // Trailing comments stay at a space past the last token
1426 C.Spaces = Changes[i - 1].Tok->is(tok::comma) ? 1 : 2;
1427 } else if (C.Tok->is(tok::l_brace)) {
1428 // We need to make sure that the ending braces is aligned to the
1429 // start of our initializer
1430 auto j = i - 1;
1431 for (; j > 0 && !Changes[j].Tok->ArrayInitializerLineStart; --j)
1432 ; // Nothing the loop does the work
1433 EndSpaces = Changes[j].Spaces;
1435 } else if (Depth == 0 && C.Tok->is(tok::r_brace)) {
1436 C.NewlinesBefore = 1;
1437 C.Spaces = EndSpaces;
1439 if (C.Tok->StartsColumn) {
1440 // This gets us past tokens that have been split over multiple
1441 // lines
1442 bool HasSplit = false;
1443 if (Changes[i].NewlinesBefore > 0) {
1444 // So if we split a line previously and the tail line + this token is
1445 // less then the column limit we remove the split here and just put
1446 // the column start at a space past the comma
1448 // FIXME This if branch covers the cases where the column is not
1449 // the first column. This leads to weird pathologies like the formatting
1450 // auto foo = Items{
1451 // Section{
1452 // 0, bar(),
1453 // }
1454 // };
1455 // Well if it doesn't lead to that it's indicative that the line
1456 // breaking should be revisited. Unfortunately alot of other options
1457 // interact with this
1458 auto j = i - 1;
1459 if ((j - 1) > Start && Changes[j].Tok->is(tok::comma) &&
1460 Changes[j - 1].NewlinesBefore > 0) {
1461 --j;
1462 auto LineLimit = Changes[j].Spaces + Changes[j].TokenLength;
1463 if (LineLimit < Style.ColumnLimit) {
1464 Changes[i].NewlinesBefore = 0;
1465 Changes[i].Spaces = 1;
1469 while (Changes[i].NewlinesBefore > 0 && Changes[i].Tok == C.Tok) {
1470 Changes[i].Spaces = InitialSpaces;
1471 ++i;
1472 HasSplit = true;
1474 if (Changes[i].Tok != C.Tok)
1475 --i;
1476 Cells.push_back(CellDescription{i, Cell, i, HasSplit, nullptr});
1480 return linkCells({Cells, CellCounts, InitialSpaces});
1483 unsigned WhitespaceManager::calculateCellWidth(unsigned Start, unsigned End,
1484 bool WithSpaces) const {
1485 unsigned CellWidth = 0;
1486 for (auto i = Start; i < End; i++) {
1487 if (Changes[i].NewlinesBefore > 0)
1488 CellWidth = 0;
1489 CellWidth += Changes[i].TokenLength;
1490 CellWidth += (WithSpaces ? Changes[i].Spaces : 0);
1492 return CellWidth;
1495 void WhitespaceManager::alignToStartOfCell(unsigned Start, unsigned End) {
1496 if ((End - Start) <= 1)
1497 return;
1498 // If the line is broken anywhere in there make sure everything
1499 // is aligned to the parent
1500 for (auto i = Start + 1; i < End; i++)
1501 if (Changes[i].NewlinesBefore > 0)
1502 Changes[i].Spaces = Changes[Start].Spaces;
1505 WhitespaceManager::CellDescriptions
1506 WhitespaceManager::linkCells(CellDescriptions &&CellDesc) {
1507 auto &Cells = CellDesc.Cells;
1508 for (auto *CellIter = Cells.begin(); CellIter != Cells.end(); ++CellIter) {
1509 if (!CellIter->NextColumnElement && (CellIter + 1) != Cells.end()) {
1510 for (auto *NextIter = CellIter + 1; NextIter != Cells.end(); ++NextIter) {
1511 if (NextIter->Cell == CellIter->Cell) {
1512 CellIter->NextColumnElement = &(*NextIter);
1513 break;
1518 return std::move(CellDesc);
1521 void WhitespaceManager::generateChanges() {
1522 for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
1523 const Change &C = Changes[i];
1524 if (i > 0) {
1525 auto Last = Changes[i - 1].OriginalWhitespaceRange;
1526 auto New = Changes[i].OriginalWhitespaceRange;
1527 // Do not generate two replacements for the same location. As a special
1528 // case, it is allowed if there is a replacement for the empty range
1529 // between 2 tokens and another non-empty range at the start of the second
1530 // token. We didn't implement logic to combine replacements for 2
1531 // consecutive source ranges into a single replacement, because the
1532 // program works fine without it.
1534 // We can't eliminate empty original whitespace ranges. They appear when
1535 // 2 tokens have no whitespace in between in the input. It does not
1536 // matter whether whitespace is to be added. If no whitespace is to be
1537 // added, the replacement will be empty, and it gets eliminated after this
1538 // step in storeReplacement. For example, if the input is `foo();`,
1539 // there will be a replacement for the range between every consecutive
1540 // pair of tokens.
1542 // A replacement at the start of a token can be added by
1543 // BreakableStringLiteralUsingOperators::insertBreak when it adds braces
1544 // around the string literal. Say Verilog code is being formatted and the
1545 // first line is to become the next 2 lines.
1546 // x("long string");
1547 // x({"long ",
1548 // "string"});
1549 // There will be a replacement for the empty range between the parenthesis
1550 // and the string and another replacement for the quote character. The
1551 // replacement for the empty range between the parenthesis and the quote
1552 // comes from ContinuationIndenter::addTokenOnCurrentLine when it changes
1553 // the original empty range between the parenthesis and the string to
1554 // another empty one. The replacement for the quote character comes from
1555 // BreakableStringLiteralUsingOperators::insertBreak when it adds the
1556 // brace. In the example, the replacement for the empty range is the same
1557 // as the original text. However, eliminating replacements that are same
1558 // as the original does not help in general. For example, a newline can
1559 // be inserted, causing the first line to become the next 3 lines.
1560 // xxxxxxxxxxx("long string");
1561 // xxxxxxxxxxx(
1562 // {"long ",
1563 // "string"});
1564 // In that case, the empty range between the parenthesis and the string
1565 // will be replaced by a newline and 4 spaces. So we will still have to
1566 // deal with a replacement for an empty source range followed by a
1567 // replacement for a non-empty source range.
1568 if (Last.getBegin() == New.getBegin() &&
1569 (Last.getEnd() != Last.getBegin() ||
1570 New.getEnd() == New.getBegin())) {
1571 continue;
1574 if (C.CreateReplacement) {
1575 std::string ReplacementText = C.PreviousLinePostfix;
1576 if (C.ContinuesPPDirective) {
1577 appendEscapedNewlineText(ReplacementText, C.NewlinesBefore,
1578 C.PreviousEndOfTokenColumn,
1579 C.EscapedNewlineColumn);
1580 } else {
1581 appendNewlineText(ReplacementText, C.NewlinesBefore);
1583 // FIXME: This assert should hold if we computed the column correctly.
1584 // assert((int)C.StartOfTokenColumn >= C.Spaces);
1585 appendIndentText(
1586 ReplacementText, C.Tok->IndentLevel, std::max(0, C.Spaces),
1587 std::max((int)C.StartOfTokenColumn, C.Spaces) - std::max(0, C.Spaces),
1588 C.IsAligned);
1589 ReplacementText.append(C.CurrentLinePrefix);
1590 storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
1595 void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) {
1596 unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) -
1597 SourceMgr.getFileOffset(Range.getBegin());
1598 // Don't create a replacement, if it does not change anything.
1599 if (StringRef(SourceMgr.getCharacterData(Range.getBegin()),
1600 WhitespaceLength) == Text) {
1601 return;
1603 auto Err = Replaces.add(tooling::Replacement(
1604 SourceMgr, CharSourceRange::getCharRange(Range), Text));
1605 // FIXME: better error handling. For now, just print an error message in the
1606 // release version.
1607 if (Err) {
1608 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
1609 assert(false);
1613 void WhitespaceManager::appendNewlineText(std::string &Text,
1614 unsigned Newlines) {
1615 if (UseCRLF) {
1616 Text.reserve(Text.size() + 2 * Newlines);
1617 for (unsigned i = 0; i < Newlines; ++i)
1618 Text.append("\r\n");
1619 } else {
1620 Text.append(Newlines, '\n');
1624 void WhitespaceManager::appendEscapedNewlineText(
1625 std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn,
1626 unsigned EscapedNewlineColumn) {
1627 if (Newlines > 0) {
1628 unsigned Spaces =
1629 std::max<int>(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1);
1630 for (unsigned i = 0; i < Newlines; ++i) {
1631 Text.append(Spaces, ' ');
1632 Text.append(UseCRLF ? "\\\r\n" : "\\\n");
1633 Spaces = std::max<int>(0, EscapedNewlineColumn - 1);
1638 void WhitespaceManager::appendIndentText(std::string &Text,
1639 unsigned IndentLevel, unsigned Spaces,
1640 unsigned WhitespaceStartColumn,
1641 bool IsAligned) {
1642 switch (Style.UseTab) {
1643 case FormatStyle::UT_Never:
1644 Text.append(Spaces, ' ');
1645 break;
1646 case FormatStyle::UT_Always: {
1647 if (Style.TabWidth) {
1648 unsigned FirstTabWidth =
1649 Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
1651 // Insert only spaces when we want to end up before the next tab.
1652 if (Spaces < FirstTabWidth || Spaces == 1) {
1653 Text.append(Spaces, ' ');
1654 break;
1656 // Align to the next tab.
1657 Spaces -= FirstTabWidth;
1658 Text.append("\t");
1660 Text.append(Spaces / Style.TabWidth, '\t');
1661 Text.append(Spaces % Style.TabWidth, ' ');
1662 } else if (Spaces == 1) {
1663 Text.append(Spaces, ' ');
1665 break;
1667 case FormatStyle::UT_ForIndentation:
1668 if (WhitespaceStartColumn == 0) {
1669 unsigned Indentation = IndentLevel * Style.IndentWidth;
1670 Spaces = appendTabIndent(Text, Spaces, Indentation);
1672 Text.append(Spaces, ' ');
1673 break;
1674 case FormatStyle::UT_ForContinuationAndIndentation:
1675 if (WhitespaceStartColumn == 0)
1676 Spaces = appendTabIndent(Text, Spaces, Spaces);
1677 Text.append(Spaces, ' ');
1678 break;
1679 case FormatStyle::UT_AlignWithSpaces:
1680 if (WhitespaceStartColumn == 0) {
1681 unsigned Indentation =
1682 IsAligned ? IndentLevel * Style.IndentWidth : Spaces;
1683 Spaces = appendTabIndent(Text, Spaces, Indentation);
1685 Text.append(Spaces, ' ');
1686 break;
1690 unsigned WhitespaceManager::appendTabIndent(std::string &Text, unsigned Spaces,
1691 unsigned Indentation) {
1692 // This happens, e.g. when a line in a block comment is indented less than the
1693 // first one.
1694 if (Indentation > Spaces)
1695 Indentation = Spaces;
1696 if (Style.TabWidth) {
1697 unsigned Tabs = Indentation / Style.TabWidth;
1698 Text.append(Tabs, '\t');
1699 Spaces -= Tabs * Style.TabWidth;
1701 return Spaces;
1704 } // namespace format
1705 } // namespace clang