clang 22.0.0git
WhitespaceManager.cpp
Go to the documentation of this file.
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//===----------------------------------------------------------------------===//
13
14#include "WhitespaceManager.h"
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/SmallVector.h"
17#include <algorithm>
18
19namespace clang {
20namespace format {
21
23 const Change &C1, const Change &C2) const {
24 return SourceMgr.isBeforeInTranslationUnit(
29 SourceMgr.isBeforeInTranslationUnit(
32}
33
52
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));
64}
65
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));
75}
76
77llvm::Error
79 return Replaces.add(Replacement);
80}
81
82bool 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;
86}
87
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));
101}
102
104 if (Changes.empty())
105 return Replaces;
106
107 llvm::sort(Changes, Change::IsBeforeInFile(SourceMgr));
108 calculateLineBreakInformation();
109 alignConsecutiveMacros();
110 alignConsecutiveShortCaseStatements(/*IsExpr=*/true);
111 alignConsecutiveShortCaseStatements(/*IsExpr=*/false);
112 alignConsecutiveDeclarations();
113 alignConsecutiveBitFields();
114 alignConsecutiveAssignments();
115 if (Style.isTableGen()) {
116 alignConsecutiveTableGenBreakingDAGArgColons();
117 alignConsecutiveTableGenCondOperatorColons();
118 alignConsecutiveTableGenDefinitions();
119 }
120 alignChainedConditionals();
121 alignTrailingComments();
122 alignEscapedNewlines();
123 alignArrayInitializers();
124 generateChanges();
125
126 return Replaces;
127}
128
129void WhitespaceManager::calculateLineBreakInformation() {
130 Changes[0].PreviousEndOfTokenColumn = 0;
131 Change *LastOutsideTokenChange = &Changes[0];
132 for (unsigned I = 1, e = Changes.size(); I != e; ++I) {
133 auto &C = Changes[I];
134 auto &P = Changes[I - 1];
135 auto &PrevTokLength = P.TokenLength;
136 SourceLocation OriginalWhitespaceStart =
137 C.OriginalWhitespaceRange.getBegin();
138 SourceLocation PreviousOriginalWhitespaceEnd =
139 P.OriginalWhitespaceRange.getEnd();
140 unsigned OriginalWhitespaceStartOffset =
141 SourceMgr.getFileOffset(OriginalWhitespaceStart);
142 unsigned PreviousOriginalWhitespaceEndOffset =
143 SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd);
144 assert(PreviousOriginalWhitespaceEndOffset <=
145 OriginalWhitespaceStartOffset);
146 const char *const PreviousOriginalWhitespaceEndData =
147 SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd);
148 StringRef Text(PreviousOriginalWhitespaceEndData,
149 SourceMgr.getCharacterData(OriginalWhitespaceStart) -
150 PreviousOriginalWhitespaceEndData);
151 // Usually consecutive changes would occur in consecutive tokens. This is
152 // not the case however when analyzing some preprocessor runs of the
153 // annotated lines. For example, in this code:
154 //
155 // #if A // line 1
156 // int i = 1;
157 // #else B // line 2
158 // int i = 2;
159 // #endif // line 3
160 //
161 // one of the runs will produce the sequence of lines marked with line 1, 2
162 // and 3. So the two consecutive whitespace changes just before '// line 2'
163 // and before '#endif // line 3' span multiple lines and tokens:
164 //
165 // #else B{change X}[// line 2
166 // int i = 2;
167 // ]{change Y}#endif // line 3
168 //
169 // For this reason, if the text between consecutive changes spans multiple
170 // newlines, the token length must be adjusted to the end of the original
171 // line of the token.
172 auto NewlinePos = Text.find_first_of('\n');
173 if (NewlinePos == StringRef::npos) {
174 PrevTokLength = OriginalWhitespaceStartOffset -
175 PreviousOriginalWhitespaceEndOffset +
176 C.PreviousLinePostfix.size() + P.CurrentLinePrefix.size();
177 if (!P.IsInsideToken)
178 PrevTokLength = std::min(PrevTokLength, P.Tok->ColumnWidth);
179 } else {
180 PrevTokLength = NewlinePos + P.CurrentLinePrefix.size();
181 }
182
183 // If there are multiple changes in this token, sum up all the changes until
184 // the end of the line.
185 if (P.IsInsideToken && P.NewlinesBefore == 0)
186 LastOutsideTokenChange->TokenLength += PrevTokLength + P.Spaces;
187 else
188 LastOutsideTokenChange = &P;
189
190 C.PreviousEndOfTokenColumn = P.StartOfTokenColumn + PrevTokLength;
191
192 P.IsTrailingComment =
193 (C.NewlinesBefore > 0 || C.Tok->is(tok::eof) ||
194 (C.IsInsideToken && C.Tok->is(tok::comment))) &&
195 P.Tok->is(tok::comment) &&
196 // FIXME: This is a dirty hack. The problem is that
197 // BreakableLineCommentSection does comment reflow changes and here is
198 // the aligning of trailing comments. Consider the case where we reflow
199 // the second line up in this example:
200 //
201 // // line 1
202 // // line 2
203 //
204 // That amounts to 2 changes by BreakableLineCommentSection:
205 // - the first, delimited by (), for the whitespace between the tokens,
206 // - and second, delimited by [], for the whitespace at the beginning
207 // of the second token:
208 //
209 // // line 1(
210 // )[// ]line 2
211 //
212 // So in the end we have two changes like this:
213 //
214 // // line1()[ ]line 2
215 //
216 // Note that the OriginalWhitespaceStart of the second change is the
217 // same as the PreviousOriginalWhitespaceEnd of the first change.
218 // In this case, the below check ensures that the second change doesn't
219 // get treated as a trailing comment change here, since this might
220 // trigger additional whitespace to be wrongly inserted before "line 2"
221 // by the comment aligner here.
222 //
223 // For a proper solution we need a mechanism to say to WhitespaceManager
224 // that a particular change breaks the current sequence of trailing
225 // comments.
226 OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd;
227 }
228 // FIXME: The last token is currently not always an eof token; in those
229 // cases, setting TokenLength of the last token to 0 is wrong.
230 Changes.back().TokenLength = 0;
231 Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);
232
233 const WhitespaceManager::Change *LastBlockComment = nullptr;
234 for (auto &Change : Changes) {
235 // Reset the IsTrailingComment flag for changes inside of trailing comments
236 // so they don't get realigned later. Comment line breaks however still need
237 // to be aligned.
240 Change.StartOfBlockComment = nullptr;
242 if (Change.Tok->is(tok::comment)) {
243 if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken) {
244 LastBlockComment = &Change;
245 } else if ((Change.StartOfBlockComment = LastBlockComment)) {
249 }
250 } else {
251 LastBlockComment = nullptr;
252 }
253 }
254
255 // Compute conditional nesting level
256 // Level is increased for each conditional, unless this conditional continues
257 // a chain of conditional, i.e. starts immediately after the colon of another
258 // conditional.
259 SmallVector<bool, 16> ScopeStack;
260 int ConditionalsLevel = 0;
261 for (auto &Change : Changes) {
262 for (unsigned i = 0, e = Change.Tok->FakeLParens.size(); i != e; ++i) {
263 bool isNestedConditional =
264 Change.Tok->FakeLParens[e - 1 - i] == prec::Conditional &&
265 !(i == 0 && Change.Tok->Previous &&
266 Change.Tok->Previous->is(TT_ConditionalExpr) &&
267 Change.Tok->Previous->is(tok::colon));
268 if (isNestedConditional)
269 ++ConditionalsLevel;
270 ScopeStack.push_back(isNestedConditional);
271 }
272
273 Change.ConditionalsLevel = ConditionalsLevel;
274
275 for (unsigned i = Change.Tok->FakeRParens; i > 0 && ScopeStack.size(); --i)
276 if (ScopeStack.pop_back_val())
277 --ConditionalsLevel;
278 }
279}
280
281// Align a single sequence of tokens, see AlignTokens below.
282// Column - The token for which Matches returns true is moved to this column.
283// RightJustify - Whether it is the token's right end or left end that gets
284// moved to that column.
285template <typename F>
286static void
287AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End,
288 unsigned Column, bool RightJustify, F &&Matches,
290 bool FoundMatchOnLine = false;
291 int Shift = 0;
292
293 // ScopeStack keeps track of the current scope depth. It contains indices of
294 // the first token on each scope.
295 // We only run the "Matches" function on tokens from the outer-most scope.
296 // However, we do need to pay special attention to one class of tokens
297 // that are not in the outer-most scope, and that is function parameters
298 // which are split across multiple lines, as illustrated by this example:
299 // double a(int x);
300 // int b(int y,
301 // double z);
302 // In the above example, we need to take special care to ensure that
303 // 'double z' is indented along with it's owning function 'b'.
304 // The same holds for calling a function:
305 // double a = foo(x);
306 // int b = bar(foo(y),
307 // foor(z));
308 // Similar for broken string literals:
309 // double x = 3.14;
310 // auto s = "Hello"
311 // "World";
312 // Special handling is required for 'nested' ternary operators.
313 SmallVector<unsigned, 16> ScopeStack;
314
315 for (unsigned i = Start; i != End; ++i) {
316 auto &CurrentChange = Changes[i];
317 if (!ScopeStack.empty() &&
318 CurrentChange.indentAndNestingLevel() <
319 Changes[ScopeStack.back()].indentAndNestingLevel()) {
320 ScopeStack.pop_back();
321 }
322
323 // Compare current token to previous non-comment token to ensure whether
324 // it is in a deeper scope or not.
325 unsigned PreviousNonComment = i - 1;
326 while (PreviousNonComment > Start &&
327 Changes[PreviousNonComment].Tok->is(tok::comment)) {
328 --PreviousNonComment;
329 }
330 if (i != Start && CurrentChange.indentAndNestingLevel() >
331 Changes[PreviousNonComment].indentAndNestingLevel()) {
332 ScopeStack.push_back(i);
333 }
334
335 bool InsideNestedScope = !ScopeStack.empty();
336 bool ContinuedStringLiteral = i > Start &&
337 CurrentChange.Tok->is(tok::string_literal) &&
338 Changes[i - 1].Tok->is(tok::string_literal);
339 bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral;
340
341 if (CurrentChange.NewlinesBefore > 0 && !SkipMatchCheck) {
342 Shift = 0;
343 FoundMatchOnLine = false;
344 }
345
346 // If this is the first matching token to be aligned, remember by how many
347 // spaces it has to be shifted, so the rest of the changes on the line are
348 // shifted by the same amount
349 if (!FoundMatchOnLine && !SkipMatchCheck && Matches(CurrentChange)) {
350 FoundMatchOnLine = true;
351 Shift = Column - (RightJustify ? CurrentChange.TokenLength : 0) -
352 CurrentChange.StartOfTokenColumn;
353 CurrentChange.Spaces += Shift;
354 // FIXME: This is a workaround that should be removed when we fix
355 // http://llvm.org/PR53699. An assertion later below verifies this.
356 if (CurrentChange.NewlinesBefore == 0) {
357 CurrentChange.Spaces =
358 std::max(CurrentChange.Spaces,
359 static_cast<int>(CurrentChange.Tok->SpacesRequiredBefore));
360 }
361 }
362
363 if (Shift == 0)
364 continue;
365
366 // This is for function parameters that are split across multiple lines,
367 // as mentioned in the ScopeStack comment.
368 if (InsideNestedScope && CurrentChange.NewlinesBefore > 0) {
369 unsigned ScopeStart = ScopeStack.back();
370 auto ShouldShiftBeAdded = [&] {
371 // Function declaration
372 if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName))
373 return true;
374
375 // Lambda.
376 if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace))
377 return false;
378
379 // Continued function declaration
380 if (ScopeStart > Start + 1 &&
381 Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) {
382 return true;
383 }
384
385 // Continued (template) function call.
386 if (ScopeStart > Start + 1 &&
387 Changes[ScopeStart - 2].Tok->isOneOf(tok::identifier,
388 TT_TemplateCloser) &&
389 Changes[ScopeStart - 1].Tok->is(tok::l_paren) &&
390 Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) {
391 if (CurrentChange.Tok->MatchingParen &&
392 CurrentChange.Tok->MatchingParen->is(TT_LambdaLBrace)) {
393 return false;
394 }
395 if (Changes[ScopeStart].NewlinesBefore > 0)
396 return false;
397 if (CurrentChange.Tok->is(tok::l_brace) &&
398 CurrentChange.Tok->is(BK_BracedInit)) {
399 return true;
400 }
401 return Style.BinPackArguments;
402 }
403
404 // Ternary operator
405 if (CurrentChange.Tok->is(TT_ConditionalExpr))
406 return true;
407
408 // Period Initializer .XXX = 1.
409 if (CurrentChange.Tok->is(TT_DesignatedInitializerPeriod))
410 return true;
411
412 // Continued ternary operator
413 if (CurrentChange.Tok->Previous &&
414 CurrentChange.Tok->Previous->is(TT_ConditionalExpr)) {
415 return true;
416 }
417
418 // Continued direct-list-initialization using braced list.
419 if (ScopeStart > Start + 1 &&
420 Changes[ScopeStart - 2].Tok->is(tok::identifier) &&
421 Changes[ScopeStart - 1].Tok->is(tok::l_brace) &&
422 CurrentChange.Tok->is(tok::l_brace) &&
423 CurrentChange.Tok->is(BK_BracedInit)) {
424 return true;
425 }
426
427 // Continued braced list.
428 if (ScopeStart > Start + 1 &&
429 Changes[ScopeStart - 2].Tok->isNot(tok::identifier) &&
430 Changes[ScopeStart - 1].Tok->is(tok::l_brace) &&
431 CurrentChange.Tok->isNot(tok::r_brace)) {
432 for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) {
433 // Lambda.
434 if (OuterScopeStart > Start &&
435 Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) {
436 return false;
437 }
438 }
439 if (Changes[ScopeStart].NewlinesBefore > 0)
440 return false;
441 return true;
442 }
443
444 // Continued template parameter.
445 if (Changes[ScopeStart - 1].Tok->is(TT_TemplateOpener))
446 return true;
447
448 return false;
449 };
450
451 if (ShouldShiftBeAdded())
452 CurrentChange.Spaces += Shift;
453 }
454
455 if (ContinuedStringLiteral)
456 CurrentChange.Spaces += Shift;
457
458 // We should not remove required spaces unless we break the line before.
459 assert(Shift > 0 || Changes[i].NewlinesBefore > 0 ||
460 CurrentChange.Spaces >=
461 static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) ||
462 CurrentChange.Tok->is(tok::eof));
463
464 CurrentChange.StartOfTokenColumn += Shift;
465 if (i + 1 != Changes.size())
466 Changes[i + 1].PreviousEndOfTokenColumn += Shift;
467
468 // If PointerAlignment is PAS_Right, keep *s or &s next to the token,
469 // except if the token is equal, then a space is needed.
470 if ((Style.PointerAlignment == FormatStyle::PAS_Right ||
471 Style.ReferenceAlignment == FormatStyle::RAS_Right) &&
472 CurrentChange.Spaces != 0 &&
473 !CurrentChange.Tok->isOneOf(tok::equal, tok::r_paren,
474 TT_TemplateCloser)) {
475 const bool ReferenceNotRightAligned =
476 Style.ReferenceAlignment != FormatStyle::RAS_Right &&
477 Style.ReferenceAlignment != FormatStyle::RAS_Pointer;
478 for (int Previous = i - 1;
479 Previous >= 0 && Changes[Previous].Tok->is(TT_PointerOrReference);
480 --Previous) {
481 assert(Changes[Previous].Tok->isPointerOrReference());
482 if (Changes[Previous].Tok->isNot(tok::star)) {
483 if (ReferenceNotRightAligned)
484 continue;
485 } else if (Style.PointerAlignment != FormatStyle::PAS_Right) {
486 continue;
487 }
488 Changes[Previous + 1].Spaces -= Shift;
489 Changes[Previous].Spaces += Shift;
490 Changes[Previous].StartOfTokenColumn += Shift;
491 }
492 }
493 }
494}
495
496// Walk through a subset of the changes, starting at StartAt, and find
497// sequences of matching tokens to align. To do so, keep track of the lines and
498// whether or not a matching token was found on a line. If a matching token is
499// found, extend the current sequence. If the current line cannot be part of a
500// sequence, e.g. because there is an empty line before it or it contains only
501// non-matching tokens, finalize the previous sequence.
502// The value returned is the token on which we stopped, either because we
503// exhausted all items inside Changes, or because we hit a scope level higher
504// than our initial scope.
505// This function is recursive. Each invocation processes only the scope level
506// equal to the initial level, which is the level of Changes[StartAt].
507// If we encounter a scope level greater than the initial level, then we call
508// ourselves recursively, thereby avoiding the pollution of the current state
509// with the alignment requirements of the nested sub-level. This recursive
510// behavior is necessary for aligning function prototypes that have one or more
511// arguments.
512// If this function encounters a scope level less than the initial level,
513// it returns the current position.
514// There is a non-obvious subtlety in the recursive behavior: Even though we
515// defer processing of nested levels to recursive invocations of this
516// function, when it comes time to align a sequence of tokens, we run the
517// alignment on the entire sequence, including the nested levels.
518// When doing so, most of the nested tokens are skipped, because their
519// alignment was already handled by the recursive invocations of this function.
520// However, the special exception is that we do NOT skip function parameters
521// that are split across multiple lines. See the test case in FormatTest.cpp
522// that mentions "split function parameter alignment" for an example of this.
523// When the parameter RightJustify is true, the operator will be
524// right-justified. It is used to align compound assignments like `+=` and `=`.
525// When RightJustify and ACS.PadOperators are true, operators in each block to
526// be aligned will be padded on the left to the same length before aligning.
527template <typename F>
528static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
530 unsigned StartAt,
531 const FormatStyle::AlignConsecutiveStyle &ACS = {},
532 bool RightJustify = false) {
533 // We arrange each line in 3 parts. The operator to be aligned (the anchor),
534 // and text to its left and right. In the aligned text the width of each part
535 // will be the maximum of that over the block that has been aligned. Maximum
536 // widths of each part so far. When RightJustify is true and ACS.PadOperators
537 // is false, the part from start of line to the right end of the anchor.
538 // Otherwise, only the part to the left of the anchor. Including the space
539 // that exists on its left from the start. Not including the padding added on
540 // the left to right-justify the anchor.
541 unsigned WidthLeft = 0;
542 // The operator to be aligned when RightJustify is true and ACS.PadOperators
543 // is false. 0 otherwise.
544 unsigned WidthAnchor = 0;
545 // Width to the right of the anchor. Plus width of the anchor when
546 // RightJustify is false.
547 unsigned WidthRight = 0;
548
549 // Line number of the start and the end of the current token sequence.
550 unsigned StartOfSequence = 0;
551 unsigned EndOfSequence = 0;
552
553 // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
554 // abort when we hit any token in a higher scope than the starting one.
555 auto IndentAndNestingLevel = StartAt < Changes.size()
556 ? Changes[StartAt].indentAndNestingLevel()
557 : std::tuple<unsigned, unsigned, unsigned>();
558
559 // Keep track of the number of commas before the matching tokens, we will only
560 // align a sequence of matching tokens if they are preceded by the same number
561 // of commas.
562 unsigned CommasBeforeLastMatch = 0;
563 unsigned CommasBeforeMatch = 0;
564
565 // Whether a matching token has been found on the current line.
566 bool FoundMatchOnLine = false;
567
568 // Whether the current line consists purely of comments.
569 bool LineIsComment = true;
570
571 // Aligns a sequence of matching tokens, on the MinColumn column.
572 //
573 // Sequences start from the first matching token to align, and end at the
574 // first token of the first line that doesn't need to be aligned.
575 //
576 // We need to adjust the StartOfTokenColumn of each Change that is on a line
577 // containing any matching token to be aligned and located after such token.
578 auto AlignCurrentSequence = [&] {
579 if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {
580 AlignTokenSequence(Style, StartOfSequence, EndOfSequence,
581 WidthLeft + WidthAnchor, RightJustify, Matches,
582 Changes);
583 }
584 WidthLeft = 0;
585 WidthAnchor = 0;
586 WidthRight = 0;
587 StartOfSequence = 0;
588 EndOfSequence = 0;
589 };
590
591 unsigned i = StartAt;
592 for (unsigned e = Changes.size(); i != e; ++i) {
593 auto &CurrentChange = Changes[i];
594 if (CurrentChange.indentAndNestingLevel() < IndentAndNestingLevel)
595 break;
596
597 if (CurrentChange.NewlinesBefore != 0) {
598 CommasBeforeMatch = 0;
599 EndOfSequence = i;
600
601 // Whether to break the alignment sequence because of an empty line.
602 bool EmptyLineBreak =
603 (CurrentChange.NewlinesBefore > 1) && !ACS.AcrossEmptyLines;
604
605 // Whether to break the alignment sequence because of a line without a
606 // match.
607 bool NoMatchBreak =
608 !FoundMatchOnLine && !(LineIsComment && ACS.AcrossComments);
609
610 if (EmptyLineBreak || NoMatchBreak)
611 AlignCurrentSequence();
612
613 // A new line starts, re-initialize line status tracking bools.
614 // Keep the match state if a string literal is continued on this line.
615 if (i == 0 || CurrentChange.Tok->isNot(tok::string_literal) ||
616 Changes[i - 1].Tok->isNot(tok::string_literal)) {
617 FoundMatchOnLine = false;
618 }
619 LineIsComment = true;
620 }
621
622 if (CurrentChange.Tok->isNot(tok::comment))
623 LineIsComment = false;
624
625 if (CurrentChange.Tok->is(tok::comma)) {
626 ++CommasBeforeMatch;
627 } else if (CurrentChange.indentAndNestingLevel() > IndentAndNestingLevel) {
628 // Call AlignTokens recursively, skipping over this scope block.
629 unsigned StoppedAt =
630 AlignTokens(Style, Matches, Changes, i, ACS, RightJustify);
631 i = StoppedAt - 1;
632 continue;
633 }
634
635 if (!Matches(CurrentChange))
636 continue;
637
638 // If there is more than one matching token per line, or if the number of
639 // preceding commas, do not match anymore, end the sequence.
640 if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)
641 AlignCurrentSequence();
642
643 CommasBeforeLastMatch = CommasBeforeMatch;
644 FoundMatchOnLine = true;
645
646 if (StartOfSequence == 0)
647 StartOfSequence = i;
648
649 unsigned ChangeWidthLeft = CurrentChange.StartOfTokenColumn;
650 unsigned ChangeWidthAnchor = 0;
651 unsigned ChangeWidthRight = 0;
652 if (RightJustify)
653 if (ACS.PadOperators)
654 ChangeWidthAnchor = CurrentChange.TokenLength;
655 else
656 ChangeWidthLeft += CurrentChange.TokenLength;
657 else
658 ChangeWidthRight = CurrentChange.TokenLength;
659 for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 0; ++j) {
660 ChangeWidthRight += Changes[j].Spaces;
661 // Changes are generally 1:1 with the tokens, but a change could also be
662 // inside of a token, in which case it's counted more than once: once for
663 // the whitespace surrounding the token (!IsInsideToken) and once for
664 // each whitespace change within it (IsInsideToken).
665 // Therefore, changes inside of a token should only count the space.
666 if (!Changes[j].IsInsideToken)
667 ChangeWidthRight += Changes[j].TokenLength;
668 }
669
670 // If we are restricted by the maximum column width, end the sequence.
671 unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft);
672 unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor);
673 unsigned NewRight = std::max(ChangeWidthRight, WidthRight);
674 // `ColumnLimit == 0` means there is no column limit.
675 if (Style.ColumnLimit != 0 &&
676 Style.ColumnLimit < NewLeft + NewAnchor + NewRight) {
677 AlignCurrentSequence();
678 StartOfSequence = i;
679 WidthLeft = ChangeWidthLeft;
680 WidthAnchor = ChangeWidthAnchor;
681 WidthRight = ChangeWidthRight;
682 } else {
683 WidthLeft = NewLeft;
684 WidthAnchor = NewAnchor;
685 WidthRight = NewRight;
686 }
687 }
688
689 EndOfSequence = i;
690 AlignCurrentSequence();
691 return i;
692}
693
694// Aligns a sequence of matching tokens, on the MinColumn column.
695//
696// Sequences start from the first matching token to align, and end at the
697// first token of the first line that doesn't need to be aligned.
698//
699// We need to adjust the StartOfTokenColumn of each Change that is on a line
700// containing any matching token to be aligned and located after such token.
702 unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn,
703 std::function<bool(const WhitespaceManager::Change &C)> Matches,
705 if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {
706 bool FoundMatchOnLine = false;
707 int Shift = 0;
708
709 for (unsigned I = StartOfSequence; I != EndOfSequence; ++I) {
710 if (Changes[I].NewlinesBefore > 0) {
711 Shift = 0;
712 FoundMatchOnLine = false;
713 }
714
715 // If this is the first matching token to be aligned, remember by how many
716 // spaces it has to be shifted, so the rest of the changes on the line are
717 // shifted by the same amount.
718 if (!FoundMatchOnLine && Matches(Changes[I])) {
719 FoundMatchOnLine = true;
720 Shift = MinColumn - Changes[I].StartOfTokenColumn;
721 Changes[I].Spaces += Shift;
722 }
723
724 assert(Shift >= 0);
725 Changes[I].StartOfTokenColumn += Shift;
726 if (I + 1 != Changes.size())
727 Changes[I + 1].PreviousEndOfTokenColumn += Shift;
728 }
729 }
730
731 MinColumn = 0;
732 StartOfSequence = 0;
733 EndOfSequence = 0;
734}
735
736void WhitespaceManager::alignConsecutiveMacros() {
737 if (!Style.AlignConsecutiveMacros.Enabled)
738 return;
739
740 auto AlignMacrosMatches = [](const Change &C) {
741 const FormatToken *Current = C.Tok;
742 unsigned SpacesRequiredBefore = 1;
743
744 if (Current->SpacesRequiredBefore == 0 || !Current->Previous)
745 return false;
746
747 Current = Current->Previous;
748
749 // If token is a ")", skip over the parameter list, to the
750 // token that precedes the "("
751 if (Current->is(tok::r_paren) && Current->MatchingParen) {
752 Current = Current->MatchingParen->Previous;
754 }
755
756 if (!Current || Current->isNot(tok::identifier))
757 return false;
758
759 if (!Current->Previous || Current->Previous->isNot(tok::pp_define))
760 return false;
761
762 // For a macro function, 0 spaces are required between the
763 // identifier and the lparen that opens the parameter list.
764 // For a simple macro, 1 space is required between the
765 // identifier and the first token of the defined value.
766 return Current->Next->SpacesRequiredBefore == SpacesRequiredBefore;
767 };
768
769 unsigned MinColumn = 0;
770
771 // Start and end of the token sequence we're processing.
772 unsigned StartOfSequence = 0;
773 unsigned EndOfSequence = 0;
774
775 // Whether a matching token has been found on the current line.
776 bool FoundMatchOnLine = false;
777
778 // Whether the current line consists only of comments
779 bool LineIsComment = true;
780
781 unsigned I = 0;
782 for (unsigned E = Changes.size(); I != E; ++I) {
783 if (Changes[I].NewlinesBefore != 0) {
784 EndOfSequence = I;
785
786 // Whether to break the alignment sequence because of an empty line.
787 bool EmptyLineBreak = (Changes[I].NewlinesBefore > 1) &&
788 !Style.AlignConsecutiveMacros.AcrossEmptyLines;
789
790 // Whether to break the alignment sequence because of a line without a
791 // match.
792 bool NoMatchBreak =
793 !FoundMatchOnLine &&
794 !(LineIsComment && Style.AlignConsecutiveMacros.AcrossComments);
795
796 if (EmptyLineBreak || NoMatchBreak) {
797 AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
798 AlignMacrosMatches, Changes);
799 }
800
801 // A new line starts, re-initialize line status tracking bools.
802 FoundMatchOnLine = false;
803 LineIsComment = true;
804 }
805
806 if (Changes[I].Tok->isNot(tok::comment))
807 LineIsComment = false;
808
809 if (!AlignMacrosMatches(Changes[I]))
810 continue;
811
812 FoundMatchOnLine = true;
813
814 if (StartOfSequence == 0)
815 StartOfSequence = I;
816
817 unsigned ChangeMinColumn = Changes[I].StartOfTokenColumn;
818 MinColumn = std::max(MinColumn, ChangeMinColumn);
819 }
820
821 EndOfSequence = I;
822 AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
823 AlignMacrosMatches, Changes);
824}
825
826void WhitespaceManager::alignConsecutiveAssignments() {
827 if (!Style.AlignConsecutiveAssignments.Enabled)
828 return;
829
831 Style,
832 [&](const Change &C) {
833 // Do not align on equal signs that are first on a line.
834 if (C.NewlinesBefore > 0)
835 return false;
836
837 // Do not align on equal signs that are last on a line.
838 if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
839 return false;
840
841 // Do not align operator= overloads.
842 FormatToken *Previous = C.Tok->getPreviousNonComment();
843 if (Previous && Previous->is(tok::kw_operator))
844 return false;
845
846 return Style.AlignConsecutiveAssignments.AlignCompound
847 ? C.Tok->getPrecedence() == prec::Assignment
848 : (C.Tok->is(tok::equal) ||
849 // In Verilog the '<=' is not a compound assignment, thus
850 // it is aligned even when the AlignCompound option is not
851 // set.
852 (Style.isVerilog() && C.Tok->is(tok::lessequal) &&
853 C.Tok->getPrecedence() == prec::Assignment));
854 },
855 Changes, /*StartAt=*/0, Style.AlignConsecutiveAssignments,
856 /*RightJustify=*/true);
857}
858
859void WhitespaceManager::alignConsecutiveBitFields() {
860 alignConsecutiveColons(Style.AlignConsecutiveBitFields, TT_BitFieldColon);
861}
862
863void WhitespaceManager::alignConsecutiveColons(
864 const FormatStyle::AlignConsecutiveStyle &AlignStyle, TokenType Type) {
865 if (!AlignStyle.Enabled)
866 return;
867
869 Style,
870 [&](Change const &C) {
871 // Do not align on ':' that is first on a line.
872 if (C.NewlinesBefore > 0)
873 return false;
874
875 // Do not align on ':' that is last on a line.
876 if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
877 return false;
878
879 return C.Tok->is(Type);
880 },
881 Changes, /*StartAt=*/0, AlignStyle);
882}
883
884void WhitespaceManager::alignConsecutiveShortCaseStatements(bool IsExpr) {
885 if (!Style.AlignConsecutiveShortCaseStatements.Enabled ||
886 !(IsExpr ? Style.AllowShortCaseExpressionOnASingleLine
887 : Style.AllowShortCaseLabelsOnASingleLine)) {
888 return;
889 }
890
891 const auto Type = IsExpr ? TT_CaseLabelArrow : TT_CaseLabelColon;
892 const auto &Option = Style.AlignConsecutiveShortCaseStatements;
893 const bool AlignArrowOrColon =
894 IsExpr ? Option.AlignCaseArrows : Option.AlignCaseColons;
895
896 auto Matches = [&](const Change &C) {
897 if (AlignArrowOrColon)
898 return C.Tok->is(Type);
899
900 // Ignore 'IsInsideToken' to allow matching trailing comments which
901 // need to be reflowed as that causes the token to appear in two
902 // different changes, which will cause incorrect alignment as we'll
903 // reflow early due to detecting multiple aligning tokens per line.
904 return !C.IsInsideToken && C.Tok->Previous && C.Tok->Previous->is(Type);
905 };
906
907 unsigned MinColumn = 0;
908
909 // Empty case statements don't break the alignment, but don't necessarily
910 // match our predicate, so we need to track their column so they can push out
911 // our alignment.
912 unsigned MinEmptyCaseColumn = 0;
913
914 // Start and end of the token sequence we're processing.
915 unsigned StartOfSequence = 0;
916 unsigned EndOfSequence = 0;
917
918 // Whether a matching token has been found on the current line.
919 bool FoundMatchOnLine = false;
920
921 bool LineIsComment = true;
922 bool LineIsEmptyCase = false;
923
924 unsigned I = 0;
925 for (unsigned E = Changes.size(); I != E; ++I) {
926 if (Changes[I].NewlinesBefore != 0) {
927 // Whether to break the alignment sequence because of an empty line.
928 bool EmptyLineBreak =
929 (Changes[I].NewlinesBefore > 1) &&
930 !Style.AlignConsecutiveShortCaseStatements.AcrossEmptyLines;
931
932 // Whether to break the alignment sequence because of a line without a
933 // match.
934 bool NoMatchBreak =
935 !FoundMatchOnLine &&
936 !(LineIsComment &&
937 Style.AlignConsecutiveShortCaseStatements.AcrossComments) &&
938 !LineIsEmptyCase;
939
940 if (EmptyLineBreak || NoMatchBreak) {
941 AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn,
942 Matches, Changes);
943 MinEmptyCaseColumn = 0;
944 }
945
946 // A new line starts, re-initialize line status tracking bools.
947 FoundMatchOnLine = false;
948 LineIsComment = true;
949 LineIsEmptyCase = false;
950 }
951
952 if (Changes[I].Tok->isNot(tok::comment))
953 LineIsComment = false;
954
955 if (Changes[I].Tok->is(Type)) {
956 LineIsEmptyCase =
957 !Changes[I].Tok->Next || Changes[I].Tok->Next->isTrailingComment();
958
959 if (LineIsEmptyCase) {
960 if (Style.AlignConsecutiveShortCaseStatements.AlignCaseColons) {
961 MinEmptyCaseColumn =
962 std::max(MinEmptyCaseColumn, Changes[I].StartOfTokenColumn);
963 } else {
964 MinEmptyCaseColumn =
965 std::max(MinEmptyCaseColumn, Changes[I].StartOfTokenColumn + 2);
966 }
967 }
968 }
969
970 if (!Matches(Changes[I]))
971 continue;
972
973 if (LineIsEmptyCase)
974 continue;
975
976 FoundMatchOnLine = true;
977
978 if (StartOfSequence == 0)
979 StartOfSequence = I;
980
981 EndOfSequence = I + 1;
982
983 MinColumn = std::max(MinColumn, Changes[I].StartOfTokenColumn);
984
985 // Allow empty case statements to push out our alignment.
986 MinColumn = std::max(MinColumn, MinEmptyCaseColumn);
987 }
988
989 AlignMatchingTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
990 Changes);
991}
992
993void WhitespaceManager::alignConsecutiveTableGenBreakingDAGArgColons() {
994 alignConsecutiveColons(Style.AlignConsecutiveTableGenBreakingDAGArgColons,
995 TT_TableGenDAGArgListColonToAlign);
996}
997
998void WhitespaceManager::alignConsecutiveTableGenCondOperatorColons() {
999 alignConsecutiveColons(Style.AlignConsecutiveTableGenCondOperatorColons,
1000 TT_TableGenCondOperatorColon);
1001}
1002
1003void WhitespaceManager::alignConsecutiveTableGenDefinitions() {
1004 alignConsecutiveColons(Style.AlignConsecutiveTableGenDefinitionColons,
1005 TT_InheritanceColon);
1006}
1007
1008void WhitespaceManager::alignConsecutiveDeclarations() {
1009 if (!Style.AlignConsecutiveDeclarations.Enabled)
1010 return;
1011
1013 Style,
1014 [&](Change const &C) {
1015 if (C.Tok->is(TT_FunctionTypeLParen))
1016 return Style.AlignConsecutiveDeclarations.AlignFunctionPointers;
1017 if (C.Tok->is(TT_FunctionDeclarationName))
1018 return Style.AlignConsecutiveDeclarations.AlignFunctionDeclarations;
1019 if (C.Tok->isNot(TT_StartOfName))
1020 return false;
1021 if (C.Tok->Previous &&
1022 C.Tok->Previous->is(TT_StatementAttributeLikeMacro))
1023 return false;
1024 // Check if there is a subsequent name that starts the same declaration.
1025 for (FormatToken *Next = C.Tok->Next; Next; Next = Next->Next) {
1026 if (Next->is(tok::comment))
1027 continue;
1028 if (Next->is(TT_PointerOrReference))
1029 return false;
1030 if (!Next->Tok.getIdentifierInfo())
1031 break;
1032 if (Next->isOneOf(TT_StartOfName, TT_FunctionDeclarationName,
1033 tok::kw_operator)) {
1034 return false;
1035 }
1036 }
1037 return true;
1038 },
1039 Changes, /*StartAt=*/0, Style.AlignConsecutiveDeclarations);
1040}
1041
1042void WhitespaceManager::alignChainedConditionals() {
1043 if (Style.BreakBeforeTernaryOperators) {
1045 Style,
1046 [](Change const &C) {
1047 // Align question operators and last colon
1048 return C.Tok->is(TT_ConditionalExpr) &&
1049 ((C.Tok->is(tok::question) && !C.NewlinesBefore) ||
1050 (C.Tok->is(tok::colon) && C.Tok->Next &&
1051 (C.Tok->Next->FakeLParens.empty() ||
1052 C.Tok->Next->FakeLParens.back() != prec::Conditional)));
1053 },
1054 Changes, /*StartAt=*/0);
1055 } else {
1056 static auto AlignWrappedOperand = [](Change const &C) {
1057 FormatToken *Previous = C.Tok->getPreviousNonComment();
1058 return C.NewlinesBefore && Previous && Previous->is(TT_ConditionalExpr) &&
1059 (Previous->is(tok::colon) &&
1060 (C.Tok->FakeLParens.empty() ||
1061 C.Tok->FakeLParens.back() != prec::Conditional));
1062 };
1063 // Ensure we keep alignment of wrapped operands with non-wrapped operands
1064 // Since we actually align the operators, the wrapped operands need the
1065 // extra offset to be properly aligned.
1066 for (Change &C : Changes)
1067 if (AlignWrappedOperand(C))
1068 C.StartOfTokenColumn -= 2;
1070 Style,
1071 [this](Change const &C) {
1072 // Align question operators if next operand is not wrapped, as
1073 // well as wrapped operands after question operator or last
1074 // colon in conditional sequence
1075 return (C.Tok->is(TT_ConditionalExpr) && C.Tok->is(tok::question) &&
1076 &C != &Changes.back() && (&C + 1)->NewlinesBefore == 0 &&
1077 !(&C + 1)->IsTrailingComment) ||
1078 AlignWrappedOperand(C);
1079 },
1080 Changes, /*StartAt=*/0);
1081 }
1082}
1083
1084void WhitespaceManager::alignTrailingComments() {
1085 if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Never)
1086 return;
1087
1088 const int Size = Changes.size();
1089 int MinColumn = 0;
1090 int StartOfSequence = 0;
1091 bool BreakBeforeNext = false;
1092 int NewLineThreshold = 1;
1093 if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Always)
1094 NewLineThreshold = Style.AlignTrailingComments.OverEmptyLines + 1;
1095
1096 for (int I = 0, MaxColumn = INT_MAX, Newlines = 0; I < Size; ++I) {
1097 auto &C = Changes[I];
1098 if (C.StartOfBlockComment)
1099 continue;
1100 Newlines += C.NewlinesBefore;
1101 if (!C.IsTrailingComment)
1102 continue;
1103
1104 if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Leave) {
1105 const int OriginalSpaces =
1106 C.OriginalWhitespaceRange.getEnd().getRawEncoding() -
1107 C.OriginalWhitespaceRange.getBegin().getRawEncoding() -
1108 C.Tok->LastNewlineOffset;
1109 assert(OriginalSpaces >= 0);
1110 const auto RestoredLineLength =
1111 C.StartOfTokenColumn + C.TokenLength + OriginalSpaces;
1112 // If leaving comments makes the line exceed the column limit, give up to
1113 // leave the comments.
1114 if (RestoredLineLength >= Style.ColumnLimit && Style.ColumnLimit > 0)
1115 break;
1116 C.Spaces = C.NewlinesBefore > 0 ? C.Tok->OriginalColumn : OriginalSpaces;
1117 continue;
1118 }
1119
1120 const int ChangeMinColumn = C.StartOfTokenColumn;
1121 int ChangeMaxColumn;
1122
1123 // If we don't create a replacement for this change, we have to consider
1124 // it to be immovable.
1125 if (!C.CreateReplacement)
1126 ChangeMaxColumn = ChangeMinColumn;
1127 else if (Style.ColumnLimit == 0)
1128 ChangeMaxColumn = INT_MAX;
1129 else if (Style.ColumnLimit >= C.TokenLength)
1130 ChangeMaxColumn = Style.ColumnLimit - C.TokenLength;
1131 else
1132 ChangeMaxColumn = ChangeMinColumn;
1133
1134 if (I + 1 < Size && Changes[I + 1].ContinuesPPDirective &&
1135 ChangeMaxColumn >= 2) {
1136 ChangeMaxColumn -= 2;
1137 }
1138
1139 bool WasAlignedWithStartOfNextLine = false;
1140 if (C.NewlinesBefore >= 1) { // A comment on its own line.
1141 const auto CommentColumn =
1142 SourceMgr.getSpellingColumnNumber(C.OriginalWhitespaceRange.getEnd());
1143 for (int J = I + 1; J < Size; ++J) {
1144 if (Changes[J].Tok->is(tok::comment))
1145 continue;
1146
1147 const auto NextColumn = SourceMgr.getSpellingColumnNumber(
1148 Changes[J].OriginalWhitespaceRange.getEnd());
1149 // The start of the next token was previously aligned with the
1150 // start of this comment.
1151 WasAlignedWithStartOfNextLine =
1152 CommentColumn == NextColumn ||
1153 CommentColumn == NextColumn + Style.IndentWidth;
1154 break;
1155 }
1156 }
1157
1158 // We don't want to align comments which end a scope, which are here
1159 // identified by most closing braces.
1160 auto DontAlignThisComment = [](const auto *Tok) {
1161 if (Tok->is(tok::semi)) {
1162 Tok = Tok->getPreviousNonComment();
1163 if (!Tok)
1164 return false;
1165 }
1166 if (Tok->is(tok::r_paren)) {
1167 // Back up past the parentheses and a `TT_DoWhile` that may precede.
1168 Tok = Tok->MatchingParen;
1169 if (!Tok)
1170 return false;
1171 Tok = Tok->getPreviousNonComment();
1172 if (!Tok)
1173 return false;
1174 if (Tok->is(TT_DoWhile)) {
1175 const auto *Prev = Tok->getPreviousNonComment();
1176 if (!Prev) {
1177 // A do-while-loop without braces.
1178 return true;
1179 }
1180 Tok = Prev;
1181 }
1182 }
1183
1184 if (Tok->isNot(tok::r_brace))
1185 return false;
1186
1187 while (Tok->Previous && Tok->Previous->is(tok::r_brace))
1188 Tok = Tok->Previous;
1189 return Tok->NewlinesBefore > 0;
1190 };
1191
1192 if (I > 0 && C.NewlinesBefore == 0 &&
1193 DontAlignThisComment(Changes[I - 1].Tok)) {
1194 alignTrailingComments(StartOfSequence, I, MinColumn);
1195 // Reset to initial values, but skip this change for the next alignment
1196 // pass.
1197 MinColumn = 0;
1198 MaxColumn = INT_MAX;
1199 StartOfSequence = I + 1;
1200 } else if (BreakBeforeNext || Newlines > NewLineThreshold ||
1201 (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
1202 // Break the comment sequence if the previous line did not end
1203 // in a trailing comment.
1204 (C.NewlinesBefore == 1 && I > 0 &&
1205 !Changes[I - 1].IsTrailingComment) ||
1206 WasAlignedWithStartOfNextLine) {
1207 alignTrailingComments(StartOfSequence, I, MinColumn);
1208 MinColumn = ChangeMinColumn;
1209 MaxColumn = ChangeMaxColumn;
1210 StartOfSequence = I;
1211 } else {
1212 MinColumn = std::max(MinColumn, ChangeMinColumn);
1213 MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
1214 }
1215 BreakBeforeNext = (I == 0) || (C.NewlinesBefore > 1) ||
1216 // Never start a sequence with a comment at the beginning
1217 // of the line.
1218 (C.NewlinesBefore == 1 && StartOfSequence == I);
1219 Newlines = 0;
1220 }
1221 alignTrailingComments(StartOfSequence, Size, MinColumn);
1222}
1223
1224void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
1225 unsigned Column) {
1226 for (unsigned i = Start; i != End; ++i) {
1227 int Shift = 0;
1228 if (Changes[i].IsTrailingComment)
1229 Shift = Column - Changes[i].StartOfTokenColumn;
1230 if (Changes[i].StartOfBlockComment) {
1231 Shift = Changes[i].IndentationOffset +
1232 Changes[i].StartOfBlockComment->StartOfTokenColumn -
1233 Changes[i].StartOfTokenColumn;
1234 }
1235 if (Shift <= 0)
1236 continue;
1237 Changes[i].Spaces += Shift;
1238 if (i + 1 != Changes.size())
1239 Changes[i + 1].PreviousEndOfTokenColumn += Shift;
1240 Changes[i].StartOfTokenColumn += Shift;
1241 }
1242}
1243
1244void WhitespaceManager::alignEscapedNewlines() {
1245 const auto Align = Style.AlignEscapedNewlines;
1246 if (Align == FormatStyle::ENAS_DontAlign)
1247 return;
1248
1249 const bool WithLastLine = Align == FormatStyle::ENAS_LeftWithLastLine;
1250 const bool AlignLeft = Align == FormatStyle::ENAS_Left || WithLastLine;
1251 const auto MaxColumn = Style.ColumnLimit;
1252 unsigned MaxEndOfLine = AlignLeft ? 0 : MaxColumn;
1253 unsigned StartOfMacro = 0;
1254 for (unsigned i = 1, e = Changes.size(); i < e; ++i) {
1255 Change &C = Changes[i];
1256 if (C.NewlinesBefore == 0 && (!WithLastLine || C.Tok->isNot(tok::eof)))
1257 continue;
1258 const bool InPPDirective = C.ContinuesPPDirective;
1259 const auto BackslashColumn = C.PreviousEndOfTokenColumn + 2;
1260 if (InPPDirective ||
1261 (WithLastLine && (MaxColumn == 0 || BackslashColumn <= MaxColumn))) {
1262 MaxEndOfLine = std::max(BackslashColumn, MaxEndOfLine);
1263 }
1264 if (!InPPDirective) {
1265 alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
1266 MaxEndOfLine = AlignLeft ? 0 : MaxColumn;
1267 StartOfMacro = i;
1268 }
1269 }
1270 alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
1271}
1272
1273void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End,
1274 unsigned Column) {
1275 for (unsigned i = Start; i < End; ++i) {
1276 Change &C = Changes[i];
1277 if (C.NewlinesBefore > 0) {
1278 assert(C.ContinuesPPDirective);
1279 if (C.PreviousEndOfTokenColumn + 1 > Column)
1280 C.EscapedNewlineColumn = 0;
1281 else
1282 C.EscapedNewlineColumn = Column;
1283 }
1284 }
1285}
1286
1287void WhitespaceManager::alignArrayInitializers() {
1288 if (Style.AlignArrayOfStructures == FormatStyle::AIAS_None)
1289 return;
1290
1291 for (unsigned ChangeIndex = 1U, ChangeEnd = Changes.size();
1292 ChangeIndex < ChangeEnd; ++ChangeIndex) {
1293 auto &C = Changes[ChangeIndex];
1294 if (C.Tok->IsArrayInitializer) {
1295 bool FoundComplete = false;
1296 for (unsigned InsideIndex = ChangeIndex + 1; InsideIndex < ChangeEnd;
1297 ++InsideIndex) {
1298 if (Changes[InsideIndex].Tok == C.Tok->MatchingParen) {
1299 alignArrayInitializers(ChangeIndex, InsideIndex + 1);
1300 ChangeIndex = InsideIndex + 1;
1301 FoundComplete = true;
1302 break;
1303 }
1304 }
1305 if (!FoundComplete)
1306 ChangeIndex = ChangeEnd;
1307 }
1308 }
1309}
1310
1311void WhitespaceManager::alignArrayInitializers(unsigned Start, unsigned End) {
1312
1313 if (Style.AlignArrayOfStructures == FormatStyle::AIAS_Right)
1314 alignArrayInitializersRightJustified(getCells(Start, End));
1315 else if (Style.AlignArrayOfStructures == FormatStyle::AIAS_Left)
1316 alignArrayInitializersLeftJustified(getCells(Start, End));
1317}
1318
1319void WhitespaceManager::alignArrayInitializersRightJustified(
1320 CellDescriptions &&CellDescs) {
1321 if (!CellDescs.isRectangular())
1322 return;
1323
1324 const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1;
1325 auto &Cells = CellDescs.Cells;
1326 // Now go through and fixup the spaces.
1327 auto *CellIter = Cells.begin();
1328 for (auto i = 0U; i < CellDescs.CellCounts[0]; ++i, ++CellIter) {
1329 unsigned NetWidth = 0U;
1330 if (isSplitCell(*CellIter))
1331 NetWidth = getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
1332 auto CellWidth = getMaximumCellWidth(CellIter, NetWidth);
1333
1334 if (Changes[CellIter->Index].Tok->is(tok::r_brace)) {
1335 // So in here we want to see if there is a brace that falls
1336 // on a line that was split. If so on that line we make sure that
1337 // the spaces in front of the brace are enough.
1338 const auto *Next = CellIter;
1339 do {
1340 const FormatToken *Previous = Changes[Next->Index].Tok->Previous;
1341 if (Previous && Previous->isNot(TT_LineComment)) {
1342 Changes[Next->Index].Spaces = BracePadding;
1343 Changes[Next->Index].NewlinesBefore = 0;
1344 }
1345 Next = Next->NextColumnElement;
1346 } while (Next);
1347 // Unless the array is empty, we need the position of all the
1348 // immediately adjacent cells
1349 if (CellIter != Cells.begin()) {
1350 auto ThisNetWidth =
1351 getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
1352 auto MaxNetWidth = getMaximumNetWidth(
1353 Cells.begin(), CellIter, CellDescs.InitialSpaces,
1354 CellDescs.CellCounts[0], CellDescs.CellCounts.size());
1355 if (ThisNetWidth < MaxNetWidth)
1356 Changes[CellIter->Index].Spaces = (MaxNetWidth - ThisNetWidth);
1357 auto RowCount = 1U;
1358 auto Offset = std::distance(Cells.begin(), CellIter);
1359 for (const auto *Next = CellIter->NextColumnElement; Next;
1360 Next = Next->NextColumnElement) {
1361 if (RowCount >= CellDescs.CellCounts.size())
1362 break;
1363 auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]);
1364 auto *End = Start + Offset;
1365 ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces);
1366 if (ThisNetWidth < MaxNetWidth)
1367 Changes[Next->Index].Spaces = (MaxNetWidth - ThisNetWidth);
1368 ++RowCount;
1369 }
1370 }
1371 } else {
1372 auto ThisWidth =
1373 calculateCellWidth(CellIter->Index, CellIter->EndIndex, true) +
1374 NetWidth;
1375 if (Changes[CellIter->Index].NewlinesBefore == 0) {
1376 Changes[CellIter->Index].Spaces = (CellWidth - (ThisWidth + NetWidth));
1377 Changes[CellIter->Index].Spaces += (i > 0) ? 1 : BracePadding;
1378 }
1379 alignToStartOfCell(CellIter->Index, CellIter->EndIndex);
1380 for (const auto *Next = CellIter->NextColumnElement; Next;
1381 Next = Next->NextColumnElement) {
1382 ThisWidth =
1383 calculateCellWidth(Next->Index, Next->EndIndex, true) + NetWidth;
1384 if (Changes[Next->Index].NewlinesBefore == 0) {
1385 Changes[Next->Index].Spaces = (CellWidth - ThisWidth);
1386 Changes[Next->Index].Spaces += (i > 0) ? 1 : BracePadding;
1387 }
1388 alignToStartOfCell(Next->Index, Next->EndIndex);
1389 }
1390 }
1391 }
1392}
1393
1394void WhitespaceManager::alignArrayInitializersLeftJustified(
1395 CellDescriptions &&CellDescs) {
1396
1397 if (!CellDescs.isRectangular())
1398 return;
1399
1400 const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1;
1401 auto &Cells = CellDescs.Cells;
1402 // Now go through and fixup the spaces.
1403 auto *CellIter = Cells.begin();
1404 // The first cell of every row needs to be against the left brace.
1405 for (const auto *Next = CellIter; Next; Next = Next->NextColumnElement) {
1406 auto &Change = Changes[Next->Index];
1407 Change.Spaces =
1408 Change.NewlinesBefore == 0 ? BracePadding : CellDescs.InitialSpaces;
1409 }
1410 ++CellIter;
1411 for (auto i = 1U; i < CellDescs.CellCounts[0]; i++, ++CellIter) {
1412 auto MaxNetWidth = getMaximumNetWidth(
1413 Cells.begin(), CellIter, CellDescs.InitialSpaces,
1414 CellDescs.CellCounts[0], CellDescs.CellCounts.size());
1415 auto ThisNetWidth =
1416 getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces);
1417 if (Changes[CellIter->Index].NewlinesBefore == 0) {
1418 Changes[CellIter->Index].Spaces =
1419 MaxNetWidth - ThisNetWidth +
1420 (Changes[CellIter->Index].Tok->isNot(tok::r_brace) ? 1
1421 : BracePadding);
1422 }
1423 auto RowCount = 1U;
1424 auto Offset = std::distance(Cells.begin(), CellIter);
1425 for (const auto *Next = CellIter->NextColumnElement; Next;
1426 Next = Next->NextColumnElement) {
1427 if (RowCount >= CellDescs.CellCounts.size())
1428 break;
1429 auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]);
1430 auto *End = Start + Offset;
1431 auto ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces);
1432 if (Changes[Next->Index].NewlinesBefore == 0) {
1433 Changes[Next->Index].Spaces =
1434 MaxNetWidth - ThisNetWidth +
1435 (Changes[Next->Index].Tok->isNot(tok::r_brace) ? 1 : BracePadding);
1436 }
1437 ++RowCount;
1438 }
1439 }
1440}
1441
1442bool WhitespaceManager::isSplitCell(const CellDescription &Cell) {
1443 if (Cell.HasSplit)
1444 return true;
1445 for (const auto *Next = Cell.NextColumnElement; Next;
1446 Next = Next->NextColumnElement) {
1447 if (Next->HasSplit)
1448 return true;
1449 }
1450 return false;
1451}
1452
1453WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start,
1454 unsigned End) {
1455
1456 unsigned Depth = 0;
1457 unsigned Cell = 0;
1458 SmallVector<unsigned> CellCounts;
1459 unsigned InitialSpaces = 0;
1460 unsigned InitialTokenLength = 0;
1461 unsigned EndSpaces = 0;
1462 SmallVector<CellDescription> Cells;
1463 const FormatToken *MatchingParen = nullptr;
1464 for (unsigned i = Start; i < End; ++i) {
1465 auto &C = Changes[i];
1466 if (C.Tok->is(tok::l_brace))
1467 ++Depth;
1468 else if (C.Tok->is(tok::r_brace))
1469 --Depth;
1470 if (Depth == 2) {
1471 if (C.Tok->is(tok::l_brace)) {
1472 Cell = 0;
1473 MatchingParen = C.Tok->MatchingParen;
1474 if (InitialSpaces == 0) {
1475 InitialSpaces = C.Spaces + C.TokenLength;
1476 InitialTokenLength = C.TokenLength;
1477 auto j = i - 1;
1478 for (; Changes[j].NewlinesBefore == 0 && j > Start; --j) {
1479 InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength;
1480 InitialTokenLength += Changes[j].TokenLength;
1481 }
1482 if (C.NewlinesBefore == 0) {
1483 InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength;
1484 InitialTokenLength += Changes[j].TokenLength;
1485 }
1486 }
1487 } else if (C.Tok->is(tok::comma)) {
1488 if (!Cells.empty())
1489 Cells.back().EndIndex = i;
1490 if (const auto *Next = C.Tok->getNextNonComment();
1491 Next && Next->isNot(tok::r_brace)) { // dangling comma
1492 ++Cell;
1493 }
1494 }
1495 } else if (Depth == 1) {
1496 if (C.Tok == MatchingParen) {
1497 if (!Cells.empty())
1498 Cells.back().EndIndex = i;
1499 Cells.push_back(CellDescription{i, ++Cell, i + 1, false, nullptr});
1500 CellCounts.push_back(C.Tok->Previous->isNot(tok::comma) ? Cell + 1
1501 : Cell);
1502 // Go to the next non-comment and ensure there is a break in front
1503 const auto *NextNonComment = C.Tok->getNextNonComment();
1504 while (NextNonComment && NextNonComment->is(tok::comma))
1505 NextNonComment = NextNonComment->getNextNonComment();
1506 auto j = i;
1507 while (j < End && Changes[j].Tok != NextNonComment)
1508 ++j;
1509 if (j < End && Changes[j].NewlinesBefore == 0 &&
1510 Changes[j].Tok->isNot(tok::r_brace)) {
1511 Changes[j].NewlinesBefore = 1;
1512 // Account for the added token lengths
1513 Changes[j].Spaces = InitialSpaces - InitialTokenLength;
1514 }
1515 } else if (C.Tok->is(tok::comment) && C.Tok->NewlinesBefore == 0) {
1516 // Trailing comments stay at a space past the last token
1517 C.Spaces = Changes[i - 1].Tok->is(tok::comma) ? 1 : 2;
1518 } else if (C.Tok->is(tok::l_brace)) {
1519 // We need to make sure that the ending braces is aligned to the
1520 // start of our initializer
1521 auto j = i - 1;
1522 for (; j > 0 && !Changes[j].Tok->ArrayInitializerLineStart; --j)
1523 ; // Nothing the loop does the work
1524 EndSpaces = Changes[j].Spaces;
1525 }
1526 } else if (Depth == 0 && C.Tok->is(tok::r_brace)) {
1527 C.NewlinesBefore = 1;
1528 C.Spaces = EndSpaces;
1529 }
1530 if (C.Tok->StartsColumn) {
1531 // This gets us past tokens that have been split over multiple
1532 // lines
1533 bool HasSplit = false;
1534 if (Changes[i].NewlinesBefore > 0) {
1535 // So if we split a line previously and the tail line + this token is
1536 // less then the column limit we remove the split here and just put
1537 // the column start at a space past the comma
1538 //
1539 // FIXME This if branch covers the cases where the column is not
1540 // the first column. This leads to weird pathologies like the formatting
1541 // auto foo = Items{
1542 // Section{
1543 // 0, bar(),
1544 // }
1545 // };
1546 // Well if it doesn't lead to that it's indicative that the line
1547 // breaking should be revisited. Unfortunately alot of other options
1548 // interact with this
1549 auto j = i - 1;
1550 if ((j - 1) > Start && Changes[j].Tok->is(tok::comma) &&
1551 Changes[j - 1].NewlinesBefore > 0) {
1552 --j;
1553 auto LineLimit = Changes[j].Spaces + Changes[j].TokenLength;
1554 if (LineLimit < Style.ColumnLimit) {
1555 Changes[i].NewlinesBefore = 0;
1556 Changes[i].Spaces = 1;
1557 }
1558 }
1559 }
1560 while (Changes[i].NewlinesBefore > 0 && Changes[i].Tok == C.Tok) {
1561 Changes[i].Spaces = InitialSpaces;
1562 ++i;
1563 HasSplit = true;
1564 }
1565 if (Changes[i].Tok != C.Tok)
1566 --i;
1567 Cells.push_back(CellDescription{i, Cell, i, HasSplit, nullptr});
1568 }
1569 }
1570
1571 return linkCells({Cells, CellCounts, InitialSpaces});
1572}
1573
1574unsigned WhitespaceManager::calculateCellWidth(unsigned Start, unsigned End,
1575 bool WithSpaces) const {
1576 unsigned CellWidth = 0;
1577 for (auto i = Start; i < End; i++) {
1578 if (Changes[i].NewlinesBefore > 0)
1579 CellWidth = 0;
1580 CellWidth += Changes[i].TokenLength;
1581 CellWidth += (WithSpaces ? Changes[i].Spaces : 0);
1582 }
1583 return CellWidth;
1584}
1585
1586void WhitespaceManager::alignToStartOfCell(unsigned Start, unsigned End) {
1587 if ((End - Start) <= 1)
1588 return;
1589 // If the line is broken anywhere in there make sure everything
1590 // is aligned to the parent
1591 for (auto i = Start + 1; i < End; i++)
1592 if (Changes[i].NewlinesBefore > 0)
1593 Changes[i].Spaces = Changes[Start].Spaces;
1594}
1595
1596WhitespaceManager::CellDescriptions
1597WhitespaceManager::linkCells(CellDescriptions &&CellDesc) {
1598 auto &Cells = CellDesc.Cells;
1599 for (auto *CellIter = Cells.begin(); CellIter != Cells.end(); ++CellIter) {
1600 if (!CellIter->NextColumnElement && (CellIter + 1) != Cells.end()) {
1601 for (auto *NextIter = CellIter + 1; NextIter != Cells.end(); ++NextIter) {
1602 if (NextIter->Cell == CellIter->Cell) {
1603 CellIter->NextColumnElement = &(*NextIter);
1604 break;
1605 }
1606 }
1607 }
1608 }
1609 return std::move(CellDesc);
1610}
1611
1612void WhitespaceManager::generateChanges() {
1613 for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
1614 const Change &C = Changes[i];
1615 if (i > 0) {
1616 auto Last = Changes[i - 1].OriginalWhitespaceRange;
1617 auto New = Changes[i].OriginalWhitespaceRange;
1618 // Do not generate two replacements for the same location. As a special
1619 // case, it is allowed if there is a replacement for the empty range
1620 // between 2 tokens and another non-empty range at the start of the second
1621 // token. We didn't implement logic to combine replacements for 2
1622 // consecutive source ranges into a single replacement, because the
1623 // program works fine without it.
1624 //
1625 // We can't eliminate empty original whitespace ranges. They appear when
1626 // 2 tokens have no whitespace in between in the input. It does not
1627 // matter whether whitespace is to be added. If no whitespace is to be
1628 // added, the replacement will be empty, and it gets eliminated after this
1629 // step in storeReplacement. For example, if the input is `foo();`,
1630 // there will be a replacement for the range between every consecutive
1631 // pair of tokens.
1632 //
1633 // A replacement at the start of a token can be added by
1634 // BreakableStringLiteralUsingOperators::insertBreak when it adds braces
1635 // around the string literal. Say Verilog code is being formatted and the
1636 // first line is to become the next 2 lines.
1637 // x("long string");
1638 // x({"long ",
1639 // "string"});
1640 // There will be a replacement for the empty range between the parenthesis
1641 // and the string and another replacement for the quote character. The
1642 // replacement for the empty range between the parenthesis and the quote
1643 // comes from ContinuationIndenter::addTokenOnCurrentLine when it changes
1644 // the original empty range between the parenthesis and the string to
1645 // another empty one. The replacement for the quote character comes from
1646 // BreakableStringLiteralUsingOperators::insertBreak when it adds the
1647 // brace. In the example, the replacement for the empty range is the same
1648 // as the original text. However, eliminating replacements that are same
1649 // as the original does not help in general. For example, a newline can
1650 // be inserted, causing the first line to become the next 3 lines.
1651 // xxxxxxxxxxx("long string");
1652 // xxxxxxxxxxx(
1653 // {"long ",
1654 // "string"});
1655 // In that case, the empty range between the parenthesis and the string
1656 // will be replaced by a newline and 4 spaces. So we will still have to
1657 // deal with a replacement for an empty source range followed by a
1658 // replacement for a non-empty source range.
1659 if (Last.getBegin() == New.getBegin() &&
1660 (Last.getEnd() != Last.getBegin() ||
1661 New.getEnd() == New.getBegin())) {
1662 continue;
1663 }
1664 }
1665 if (C.CreateReplacement) {
1666 std::string ReplacementText = C.PreviousLinePostfix;
1667 if (C.ContinuesPPDirective) {
1668 appendEscapedNewlineText(ReplacementText, C.NewlinesBefore,
1669 C.PreviousEndOfTokenColumn,
1670 C.EscapedNewlineColumn);
1671 } else {
1672 appendNewlineText(ReplacementText, C);
1673 }
1674 // FIXME: This assert should hold if we computed the column correctly.
1675 // assert((int)C.StartOfTokenColumn >= C.Spaces);
1676 appendIndentText(
1677 ReplacementText, C.Tok->IndentLevel, std::max(0, C.Spaces),
1678 std::max((int)C.StartOfTokenColumn, C.Spaces) - std::max(0, C.Spaces),
1679 C.IsAligned);
1680 ReplacementText.append(C.CurrentLinePrefix);
1681 storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
1682 }
1683 }
1684}
1685
1686void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) {
1687 unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) -
1688 SourceMgr.getFileOffset(Range.getBegin());
1689 // Don't create a replacement, if it does not change anything.
1690 if (StringRef(SourceMgr.getCharacterData(Range.getBegin()),
1691 WhitespaceLength) == Text) {
1692 return;
1693 }
1694 auto Err = Replaces.add(tooling::Replacement(
1695 SourceMgr, CharSourceRange::getCharRange(Range), Text));
1696 // FIXME: better error handling. For now, just print an error message in the
1697 // release version.
1698 if (Err) {
1699 llvm::errs() << llvm::toString(std::move(Err)) << "\n";
1700 assert(false);
1701 }
1702}
1703
1704void WhitespaceManager::appendNewlineText(std::string &Text, const Change &C) {
1705 if (C.NewlinesBefore <= 0)
1706 return;
1707
1708 StringRef Newline = UseCRLF ? "\r\n" : "\n";
1709 Text.append(Newline);
1710
1711 if (C.Tok->HasFormFeedBefore)
1712 Text.append("\f");
1713
1714 for (unsigned I = 1; I < C.NewlinesBefore; ++I)
1715 Text.append(Newline);
1716}
1717
1718void WhitespaceManager::appendEscapedNewlineText(
1719 std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn,
1720 unsigned EscapedNewlineColumn) {
1721 if (Newlines > 0) {
1722 unsigned Spaces =
1723 std::max<int>(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1);
1724 for (unsigned i = 0; i < Newlines; ++i) {
1725 Text.append(Spaces, ' ');
1726 Text.append(UseCRLF ? "\\\r\n" : "\\\n");
1727 Spaces = std::max<int>(0, EscapedNewlineColumn - 1);
1728 }
1729 }
1730}
1731
1732void WhitespaceManager::appendIndentText(std::string &Text,
1733 unsigned IndentLevel, unsigned Spaces,
1734 unsigned WhitespaceStartColumn,
1735 bool IsAligned) {
1736 switch (Style.UseTab) {
1737 case FormatStyle::UT_Never:
1738 Text.append(Spaces, ' ');
1739 break;
1740 case FormatStyle::UT_Always: {
1741 if (Style.TabWidth) {
1742 unsigned FirstTabWidth =
1743 Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
1744
1745 // Insert only spaces when we want to end up before the next tab.
1746 if (Spaces < FirstTabWidth || Spaces == 1) {
1747 Text.append(Spaces, ' ');
1748 break;
1749 }
1750 // Align to the next tab.
1751 Spaces -= FirstTabWidth;
1752 Text.append("\t");
1753
1754 Text.append(Spaces / Style.TabWidth, '\t');
1755 Text.append(Spaces % Style.TabWidth, ' ');
1756 } else if (Spaces == 1) {
1757 Text.append(Spaces, ' ');
1758 }
1759 break;
1760 }
1761 case FormatStyle::UT_ForIndentation:
1762 if (WhitespaceStartColumn == 0) {
1763 unsigned Indentation = IndentLevel * Style.IndentWidth;
1764 Spaces = appendTabIndent(Text, Spaces, Indentation);
1765 }
1766 Text.append(Spaces, ' ');
1767 break;
1768 case FormatStyle::UT_ForContinuationAndIndentation:
1769 if (WhitespaceStartColumn == 0)
1770 Spaces = appendTabIndent(Text, Spaces, Spaces);
1771 Text.append(Spaces, ' ');
1772 break;
1773 case FormatStyle::UT_AlignWithSpaces:
1774 if (WhitespaceStartColumn == 0) {
1775 unsigned Indentation =
1776 IsAligned ? IndentLevel * Style.IndentWidth : Spaces;
1777 Spaces = appendTabIndent(Text, Spaces, Indentation);
1778 }
1779 Text.append(Spaces, ' ');
1780 break;
1781 }
1782}
1783
1784unsigned WhitespaceManager::appendTabIndent(std::string &Text, unsigned Spaces,
1785 unsigned Indentation) {
1786 // This happens, e.g. when a line in a block comment is indented less than the
1787 // first one.
1788 if (Indentation > Spaces)
1789 Indentation = Spaces;
1790 if (Style.TabWidth) {
1791 unsigned Tabs = Indentation / Style.TabWidth;
1792 Text.append(Tabs, '\t');
1793 Spaces -= Tabs * Style.TabWidth;
1794 }
1795 return Spaces;
1796}
1797
1798} // namespace format
1799} // namespace clang
unsigned SpacesRequiredBefore
The number of spaces that should be inserted before this token.
int Newlines
The number of newlines immediately before the Token after formatting.
FormatToken()
Token Tok
The Token.
unsigned NewlinesBefore
The number of newlines immediately before the Token.
FormatToken * MatchingParen
If this is a bracket, this points to the matching one.
unsigned IndentLevel
The indent level of this token. Copied from the surrounding line.
FormatToken * Previous
The previous token in the unwrapped line.
FormatToken * Next
The next token in the unwrapped line.
WhitespaceManager class manages whitespace around tokens and their replacements.
static CharSourceRange getCharRange(SourceRange R)
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
A trivial tuple used to represent a source range.
SourceLocation getEnd() const
SourceLocation getBegin() const
Functor to sort changes in original source order.
bool operator()(const Change &C1, const Change &C2) const
void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, unsigned Newlines, int Spaces)
Inserts or replaces whitespace in the middle of a token.
void addUntouchableToken(const FormatToken &Tok, bool InPPDirective)
Adds information about an unchangeable token's whitespace.
static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF)
Infers whether the input is using CRLF.
llvm::Error addReplacement(const tooling::Replacement &Replacement)
const tooling::Replacements & generateReplacements()
Returns all the Replacements created during formatting.
void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, unsigned StartOfTokenColumn, bool IsAligned=false, bool InPPDirective=false)
Replaces the whitespace in front of Tok.
A text replacement.
Definition Replacement.h:83
Maintains a set of replacements that are conflict-free.
#define INT_MAX
Definition limits.h:50
@ MR_ExpandedArg
The token was expanded from a macro argument when formatting the expanded token sequence.
static void AlignMatchingTokenSequence(unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn, std::function< bool(const WhitespaceManager::Change &C)> Matches, SmallVector< WhitespaceManager::Change, 16 > &Changes)
static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, SmallVector< WhitespaceManager::Change, 16 > &Changes, unsigned StartAt, const FormatStyle::AlignConsecutiveStyle &ACS={}, bool RightJustify=false)
static void AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, unsigned Column, bool RightJustify, F &&Matches, SmallVector< WhitespaceManager::Change, 16 > &Changes)
TokenType
Determines the semantic type of a syntactic token, e.g.
The JSON file list parser is used to communicate input to InstallAPI.
nullptr
This class represents a compute construct, representing a 'Kind' of β€˜parallel’, 'serial',...
@ Type
The name was classified as a type.
Definition Sema.h:562
int const char * function
Definition c++config.h:31
#define false
Definition stdbool.h:26
A wrapper around a Token storing information about the whitespace characters preceding it.
unsigned FakeRParens
Insert this many fake ) after this token for correct indentation.
SmallVector< prec::Level, 4 > FakeLParens
Stores the number of required fake parentheses and the corresponding operator precedence.
bool is(tok::TokenKind Kind) const
FormatToken * Previous
The previous token in the unwrapped line.
Represents a change before a token, a break inside a token, or the layout of an unchanged token (or w...
Change(const FormatToken &Tok, bool CreateReplacement, SourceRange OriginalWhitespaceRange, int Spaces, unsigned StartOfTokenColumn, unsigned NewlinesBefore, StringRef PreviousLinePostfix, StringRef CurrentLinePrefix, bool IsAligned, bool ContinuesPPDirective, bool IsInsideToken)
Creates a Change.