1 //===--- WhitespaceManager.cpp - Format C++ code --------------------------===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file implements WhitespaceManager class.
12 //===----------------------------------------------------------------------===//
14 #include "WhitespaceManager.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/SmallVector.h"
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
,
55 unsigned StartOfTokenColumn
,
56 bool IsAligned
, bool InPPDirective
) {
57 if (Tok
.Finalized
|| (Tok
.MacroCtx
&& Tok
.MacroCtx
->Role
== MR_ExpandedArg
))
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
,
68 if (Tok
.Finalized
|| (Tok
.MacroCtx
&& Tok
.MacroCtx
->Role
== MR_ExpandedArg
))
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));
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
))
94 SourceLocation Start
= Tok
.getStartOfNonWhitespace().getLocWithOffset(Offset
);
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() {
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();
120 alignChainedConditionals();
121 alignTrailingComments();
122 alignEscapedNewlines();
123 alignArrayInitializers();
129 void 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:
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:
165 // #else B{change X}[// line 2
167 // ]{change Y}#endif // line 3
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
);
180 PrevTokLength
= NewlinePos
+ P
.CurrentLinePrefix
.size();
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
;
188 LastOutsideTokenChange
= &P
;
190 C
.PreviousEndOfTokenColumn
= P
.StartOfTokenColumn
+ PrevTokLength
;
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:
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:
212 // So in the end we have two changes like this:
214 // // line1()[ ]line 2
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.
223 // For a proper solution we need a mechanism to say to WhitespaceManager
224 // that a particular change breaks the current sequence of trailing
226 OriginalWhitespaceStart
!= PreviousOriginalWhitespaceEnd
;
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
);
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
238 if (Change
.IsInsideToken
&& Change
.NewlinesBefore
== 0)
239 Change
.IsTrailingComment
= false;
240 Change
.StartOfBlockComment
= nullptr;
241 Change
.IndentationOffset
= 0;
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
)) {
246 Change
.IndentationOffset
=
247 Change
.StartOfTokenColumn
-
248 Change
.StartOfBlockComment
->StartOfTokenColumn
;
251 LastBlockComment
= nullptr;
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
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
)
270 ScopeStack
.push_back(isNestedConditional
);
273 Change
.ConditionalsLevel
= ConditionalsLevel
;
275 for (unsigned i
= Change
.Tok
->FakeRParens
; i
> 0 && ScopeStack
.size(); --i
)
276 if (ScopeStack
.pop_back_val())
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.
285 template <typename F
>
287 AlignTokenSequence(const FormatStyle
&Style
, unsigned Start
, unsigned End
,
288 unsigned Column
, bool RightJustify
, F
&&Matches
,
289 SmallVector
<WhitespaceManager::Change
, 16> &Changes
) {
290 bool FoundMatchOnLine
= false;
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:
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),
308 // Similar for broken string literals:
312 // Special handling is required for 'nested' ternary operators.
313 SmallVector
<unsigned, 16> ScopeStack
;
315 for (unsigned i
= Start
; i
!= End
; ++i
) {
316 auto &CurrentChange
= Changes
[i
];
317 if (ScopeStack
.size() != 0 &&
318 CurrentChange
.indentAndNestingLevel() <
319 Changes
[ScopeStack
.back()].indentAndNestingLevel()) {
320 ScopeStack
.pop_back();
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
;
330 if (i
!= Start
&& CurrentChange
.indentAndNestingLevel() >
331 Changes
[PreviousNonComment
].indentAndNestingLevel()) {
332 ScopeStack
.push_back(i
);
335 bool InsideNestedScope
= ScopeStack
.size() != 0;
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
;
341 if (CurrentChange
.NewlinesBefore
> 0 && !SkipMatchCheck
) {
343 FoundMatchOnLine
= false;
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
));
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
))
376 if (Changes
[ScopeStart
- 1].Tok
->is(TT_LambdaLBrace
))
379 // Continued function declaration
380 if (ScopeStart
> Start
+ 1 &&
381 Changes
[ScopeStart
- 2].Tok
->is(TT_FunctionDeclarationName
)) {
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
)) {
395 if (Changes
[ScopeStart
].NewlinesBefore
> 0)
397 if (CurrentChange
.Tok
->is(tok::l_brace
) &&
398 CurrentChange
.Tok
->is(BK_BracedInit
)) {
401 return Style
.BinPackArguments
;
405 if (CurrentChange
.Tok
->is(TT_ConditionalExpr
))
408 // Period Initializer .XXX = 1.
409 if (CurrentChange
.Tok
->is(TT_DesignatedInitializerPeriod
))
412 // Continued ternary operator
413 if (CurrentChange
.Tok
->Previous
&&
414 CurrentChange
.Tok
->Previous
->is(TT_ConditionalExpr
)) {
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
)) {
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
)) {
434 if (OuterScopeStart
> Start
&&
435 Changes
[OuterScopeStart
- 1].Tok
->is(TT_LambdaLBrace
)) {
439 if (Changes
[ScopeStart
].NewlinesBefore
> 0)
444 // Continued template parameter.
445 if (Changes
[ScopeStart
- 1].Tok
->is(TT_TemplateOpener
))
451 if (ShouldShiftBeAdded())
452 CurrentChange
.Spaces
+= Shift
;
455 if (ContinuedStringLiteral
)
456 CurrentChange
.Spaces
+= Shift
;
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
));
464 CurrentChange
.StartOfTokenColumn
+= Shift
;
465 if (i
+ 1 != Changes
.size())
466 Changes
[i
+ 1].PreviousEndOfTokenColumn
+= Shift
;
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
);
481 assert(Changes
[Previous
].Tok
->isPointerOrReference());
482 if (Changes
[Previous
].Tok
->isNot(tok::star
)) {
483 if (ReferenceNotRightAligned
)
485 } else if (Style
.PointerAlignment
!= FormatStyle::PAS_Right
) {
488 Changes
[Previous
+ 1].Spaces
-= Shift
;
489 Changes
[Previous
].Spaces
+= Shift
;
490 Changes
[Previous
].StartOfTokenColumn
+= Shift
;
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
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.
527 template <typename F
>
528 static unsigned AlignTokens(const FormatStyle
&Style
, F
&&Matches
,
529 SmallVector
<WhitespaceManager::Change
, 16> &Changes
,
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;
549 // Line number of the start and the end of the current token sequence.
550 unsigned StartOfSequence
= 0;
551 unsigned EndOfSequence
= 0;
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>();
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
562 unsigned CommasBeforeLastMatch
= 0;
563 unsigned CommasBeforeMatch
= 0;
565 // Whether a matching token has been found on the current line.
566 bool FoundMatchOnLine
= false;
568 // Whether the current line consists purely of comments.
569 bool LineIsComment
= true;
571 // Aligns a sequence of matching tokens, on the MinColumn column.
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.
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
,
591 unsigned i
= StartAt
;
592 for (unsigned e
= Changes
.size(); i
!= e
; ++i
) {
593 auto &CurrentChange
= Changes
[i
];
594 if (CurrentChange
.indentAndNestingLevel() < IndentAndNestingLevel
)
597 if (CurrentChange
.NewlinesBefore
!= 0) {
598 CommasBeforeMatch
= 0;
601 // Whether to break the alignment sequence because of an empty line.
602 bool EmptyLineBreak
=
603 (CurrentChange
.NewlinesBefore
> 1) && !ACS
.AcrossEmptyLines
;
605 // Whether to break the alignment sequence because of a line without a
608 !FoundMatchOnLine
&& !(LineIsComment
&& ACS
.AcrossComments
);
610 if (EmptyLineBreak
|| NoMatchBreak
)
611 AlignCurrentSequence();
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;
619 LineIsComment
= true;
622 if (CurrentChange
.Tok
->isNot(tok::comment
))
623 LineIsComment
= false;
625 if (CurrentChange
.Tok
->is(tok::comma
)) {
627 } else if (CurrentChange
.indentAndNestingLevel() > IndentAndNestingLevel
) {
628 // Call AlignTokens recursively, skipping over this scope block.
630 AlignTokens(Style
, Matches
, Changes
, i
, ACS
, RightJustify
);
635 if (!Matches(CurrentChange
))
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();
643 CommasBeforeLastMatch
= CommasBeforeMatch
;
644 FoundMatchOnLine
= true;
646 if (StartOfSequence
== 0)
649 unsigned ChangeWidthLeft
= CurrentChange
.StartOfTokenColumn
;
650 unsigned ChangeWidthAnchor
= 0;
651 unsigned ChangeWidthRight
= 0;
653 if (ACS
.PadOperators
)
654 ChangeWidthAnchor
= CurrentChange
.TokenLength
;
656 ChangeWidthLeft
+= CurrentChange
.TokenLength
;
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
;
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();
679 WidthLeft
= ChangeWidthLeft
;
680 WidthAnchor
= ChangeWidthAnchor
;
681 WidthRight
= ChangeWidthRight
;
684 WidthAnchor
= NewAnchor
;
685 WidthRight
= NewRight
;
690 AlignCurrentSequence();
694 // Aligns a sequence of matching tokens, on the MinColumn column.
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.
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.
701 static void AlignMatchingTokenSequence(
702 unsigned &StartOfSequence
, unsigned &EndOfSequence
, unsigned &MinColumn
,
703 std::function
<bool(const WhitespaceManager::Change
&C
)> Matches
,
704 SmallVector
<WhitespaceManager::Change
, 16> &Changes
) {
705 if (StartOfSequence
> 0 && StartOfSequence
< EndOfSequence
) {
706 bool FoundMatchOnLine
= false;
709 for (unsigned I
= StartOfSequence
; I
!= EndOfSequence
; ++I
) {
710 if (Changes
[I
].NewlinesBefore
> 0) {
712 FoundMatchOnLine
= false;
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
;
725 Changes
[I
].StartOfTokenColumn
+= Shift
;
726 if (I
+ 1 != Changes
.size())
727 Changes
[I
+ 1].PreviousEndOfTokenColumn
+= Shift
;
736 void WhitespaceManager::alignConsecutiveMacros() {
737 if (!Style
.AlignConsecutiveMacros
.Enabled
)
740 auto AlignMacrosMatches
= [](const Change
&C
) {
741 const FormatToken
*Current
= C
.Tok
;
742 unsigned SpacesRequiredBefore
= 1;
744 if (Current
->SpacesRequiredBefore
== 0 || !Current
->Previous
)
747 Current
= Current
->Previous
;
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
;
753 SpacesRequiredBefore
= 0;
756 if (!Current
|| Current
->isNot(tok::identifier
))
759 if (!Current
->Previous
|| Current
->Previous
->isNot(tok::pp_define
))
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
;
769 unsigned MinColumn
= 0;
771 // Start and end of the token sequence we're processing.
772 unsigned StartOfSequence
= 0;
773 unsigned EndOfSequence
= 0;
775 // Whether a matching token has been found on the current line.
776 bool FoundMatchOnLine
= false;
778 // Whether the current line consists only of comments
779 bool LineIsComment
= true;
782 for (unsigned E
= Changes
.size(); I
!= E
; ++I
) {
783 if (Changes
[I
].NewlinesBefore
!= 0) {
786 // Whether to break the alignment sequence because of an empty line.
787 bool EmptyLineBreak
= (Changes
[I
].NewlinesBefore
> 1) &&
788 !Style
.AlignConsecutiveMacros
.AcrossEmptyLines
;
790 // Whether to break the alignment sequence because of a line without a
794 !(LineIsComment
&& Style
.AlignConsecutiveMacros
.AcrossComments
);
796 if (EmptyLineBreak
|| NoMatchBreak
) {
797 AlignMatchingTokenSequence(StartOfSequence
, EndOfSequence
, MinColumn
,
798 AlignMacrosMatches
, Changes
);
801 // A new line starts, re-initialize line status tracking bools.
802 FoundMatchOnLine
= false;
803 LineIsComment
= true;
806 if (Changes
[I
].Tok
->isNot(tok::comment
))
807 LineIsComment
= false;
809 if (!AlignMacrosMatches(Changes
[I
]))
812 FoundMatchOnLine
= true;
814 if (StartOfSequence
== 0)
817 unsigned ChangeMinColumn
= Changes
[I
].StartOfTokenColumn
;
818 MinColumn
= std::max(MinColumn
, ChangeMinColumn
);
822 AlignMatchingTokenSequence(StartOfSequence
, EndOfSequence
, MinColumn
,
823 AlignMacrosMatches
, Changes
);
826 void WhitespaceManager::alignConsecutiveAssignments() {
827 if (!Style
.AlignConsecutiveAssignments
.Enabled
)
832 [&](const Change
&C
) {
833 // Do not align on equal signs that are first on a line.
834 if (C
.NewlinesBefore
> 0)
837 // Do not align on equal signs that are last on a line.
838 if (&C
!= &Changes
.back() && (&C
+ 1)->NewlinesBefore
> 0)
841 // Do not align operator= overloads.
842 FormatToken
*Previous
= C
.Tok
->getPreviousNonComment();
843 if (Previous
&& Previous
->is(tok::kw_operator
))
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
852 (Style
.isVerilog() && C
.Tok
->is(tok::lessequal
) &&
853 C
.Tok
->getPrecedence() == prec::Assignment
));
855 Changes
, /*StartAt=*/0, Style
.AlignConsecutiveAssignments
,
856 /*RightJustify=*/true);
859 void WhitespaceManager::alignConsecutiveBitFields() {
860 alignConsecutiveColons(Style
.AlignConsecutiveBitFields
, TT_BitFieldColon
);
863 void WhitespaceManager::alignConsecutiveColons(
864 const FormatStyle::AlignConsecutiveStyle
&AlignStyle
, TokenType Type
) {
865 if (!AlignStyle
.Enabled
)
870 [&](Change
const &C
) {
871 // Do not align on ':' that is first on a line.
872 if (C
.NewlinesBefore
> 0)
875 // Do not align on ':' that is last on a line.
876 if (&C
!= &Changes
.back() && (&C
+ 1)->NewlinesBefore
> 0)
879 return C
.Tok
->is(Type
);
881 Changes
, /*StartAt=*/0, AlignStyle
);
884 void WhitespaceManager::alignConsecutiveShortCaseStatements(bool IsExpr
) {
885 if (!Style
.AlignConsecutiveShortCaseStatements
.Enabled
||
886 !(IsExpr
? Style
.AllowShortCaseExpressionOnASingleLine
887 : Style
.AllowShortCaseLabelsOnASingleLine
)) {
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
;
896 auto Matches
= [&](const Change
&C
) {
897 if (AlignArrowOrColon
)
898 return C
.Tok
->is(Type
);
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
);
907 unsigned MinColumn
= 0;
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
912 unsigned MinEmptyCaseColumn
= 0;
914 // Start and end of the token sequence we're processing.
915 unsigned StartOfSequence
= 0;
916 unsigned EndOfSequence
= 0;
918 // Whether a matching token has been found on the current line.
919 bool FoundMatchOnLine
= false;
921 bool LineIsComment
= true;
922 bool LineIsEmptyCase
= false;
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
;
932 // Whether to break the alignment sequence because of a line without a
937 Style
.AlignConsecutiveShortCaseStatements
.AcrossComments
) &&
940 if (EmptyLineBreak
|| NoMatchBreak
) {
941 AlignMatchingTokenSequence(StartOfSequence
, EndOfSequence
, MinColumn
,
943 MinEmptyCaseColumn
= 0;
946 // A new line starts, re-initialize line status tracking bools.
947 FoundMatchOnLine
= false;
948 LineIsComment
= true;
949 LineIsEmptyCase
= false;
952 if (Changes
[I
].Tok
->isNot(tok::comment
))
953 LineIsComment
= false;
955 if (Changes
[I
].Tok
->is(Type
)) {
957 !Changes
[I
].Tok
->Next
|| Changes
[I
].Tok
->Next
->isTrailingComment();
959 if (LineIsEmptyCase
) {
960 if (Style
.AlignConsecutiveShortCaseStatements
.AlignCaseColons
) {
962 std::max(MinEmptyCaseColumn
, Changes
[I
].StartOfTokenColumn
);
965 std::max(MinEmptyCaseColumn
, Changes
[I
].StartOfTokenColumn
+ 2);
970 if (!Matches(Changes
[I
]))
976 FoundMatchOnLine
= true;
978 if (StartOfSequence
== 0)
981 EndOfSequence
= I
+ 1;
983 MinColumn
= std::max(MinColumn
, Changes
[I
].StartOfTokenColumn
);
985 // Allow empty case statements to push out our alignment.
986 MinColumn
= std::max(MinColumn
, MinEmptyCaseColumn
);
989 AlignMatchingTokenSequence(StartOfSequence
, EndOfSequence
, MinColumn
, Matches
,
993 void WhitespaceManager::alignConsecutiveTableGenBreakingDAGArgColons() {
994 alignConsecutiveColons(Style
.AlignConsecutiveTableGenBreakingDAGArgColons
,
995 TT_TableGenDAGArgListColonToAlign
);
998 void WhitespaceManager::alignConsecutiveTableGenCondOperatorColons() {
999 alignConsecutiveColons(Style
.AlignConsecutiveTableGenCondOperatorColons
,
1000 TT_TableGenCondOperatorColon
);
1003 void WhitespaceManager::alignConsecutiveTableGenDefinitions() {
1004 alignConsecutiveColons(Style
.AlignConsecutiveTableGenDefinitionColons
,
1005 TT_InheritanceColon
);
1008 void WhitespaceManager::alignConsecutiveDeclarations() {
1009 if (!Style
.AlignConsecutiveDeclarations
.Enabled
)
1014 [&](Change
const &C
) {
1015 if (Style
.AlignConsecutiveDeclarations
.AlignFunctionPointers
) {
1016 for (const auto *Prev
= C
.Tok
->Previous
; Prev
; Prev
= Prev
->Previous
)
1017 if (Prev
->is(tok::equal
))
1019 if (C
.Tok
->is(TT_FunctionTypeLParen
))
1022 if (C
.Tok
->is(TT_FunctionDeclarationName
))
1024 if (C
.Tok
->isNot(TT_StartOfName
))
1026 if (C
.Tok
->Previous
&&
1027 C
.Tok
->Previous
->is(TT_StatementAttributeLikeMacro
))
1029 // Check if there is a subsequent name that starts the same declaration.
1030 for (FormatToken
*Next
= C
.Tok
->Next
; Next
; Next
= Next
->Next
) {
1031 if (Next
->is(tok::comment
))
1033 if (Next
->is(TT_PointerOrReference
))
1035 if (!Next
->Tok
.getIdentifierInfo())
1037 if (Next
->isOneOf(TT_StartOfName
, TT_FunctionDeclarationName
,
1038 tok::kw_operator
)) {
1044 Changes
, /*StartAt=*/0, Style
.AlignConsecutiveDeclarations
);
1047 void WhitespaceManager::alignChainedConditionals() {
1048 if (Style
.BreakBeforeTernaryOperators
) {
1051 [](Change
const &C
) {
1052 // Align question operators and last colon
1053 return C
.Tok
->is(TT_ConditionalExpr
) &&
1054 ((C
.Tok
->is(tok::question
) && !C
.NewlinesBefore
) ||
1055 (C
.Tok
->is(tok::colon
) && C
.Tok
->Next
&&
1056 (C
.Tok
->Next
->FakeLParens
.size() == 0 ||
1057 C
.Tok
->Next
->FakeLParens
.back() != prec::Conditional
)));
1059 Changes
, /*StartAt=*/0);
1061 static auto AlignWrappedOperand
= [](Change
const &C
) {
1062 FormatToken
*Previous
= C
.Tok
->getPreviousNonComment();
1063 return C
.NewlinesBefore
&& Previous
&& Previous
->is(TT_ConditionalExpr
) &&
1064 (Previous
->is(tok::colon
) &&
1065 (C
.Tok
->FakeLParens
.size() == 0 ||
1066 C
.Tok
->FakeLParens
.back() != prec::Conditional
));
1068 // Ensure we keep alignment of wrapped operands with non-wrapped operands
1069 // Since we actually align the operators, the wrapped operands need the
1070 // extra offset to be properly aligned.
1071 for (Change
&C
: Changes
)
1072 if (AlignWrappedOperand(C
))
1073 C
.StartOfTokenColumn
-= 2;
1076 [this](Change
const &C
) {
1077 // Align question operators if next operand is not wrapped, as
1078 // well as wrapped operands after question operator or last
1079 // colon in conditional sequence
1080 return (C
.Tok
->is(TT_ConditionalExpr
) && C
.Tok
->is(tok::question
) &&
1081 &C
!= &Changes
.back() && (&C
+ 1)->NewlinesBefore
== 0 &&
1082 !(&C
+ 1)->IsTrailingComment
) ||
1083 AlignWrappedOperand(C
);
1085 Changes
, /*StartAt=*/0);
1089 void WhitespaceManager::alignTrailingComments() {
1090 if (Style
.AlignTrailingComments
.Kind
== FormatStyle::TCAS_Never
)
1093 const int Size
= Changes
.size();
1095 int StartOfSequence
= 0;
1096 bool BreakBeforeNext
= false;
1097 int NewLineThreshold
= 1;
1098 if (Style
.AlignTrailingComments
.Kind
== FormatStyle::TCAS_Always
)
1099 NewLineThreshold
= Style
.AlignTrailingComments
.OverEmptyLines
+ 1;
1101 for (int I
= 0, MaxColumn
= INT_MAX
, Newlines
= 0; I
< Size
; ++I
) {
1102 auto &C
= Changes
[I
];
1103 if (C
.StartOfBlockComment
)
1105 Newlines
+= C
.NewlinesBefore
;
1106 if (!C
.IsTrailingComment
)
1109 if (Style
.AlignTrailingComments
.Kind
== FormatStyle::TCAS_Leave
) {
1110 const int OriginalSpaces
=
1111 C
.OriginalWhitespaceRange
.getEnd().getRawEncoding() -
1112 C
.OriginalWhitespaceRange
.getBegin().getRawEncoding() -
1113 C
.Tok
->LastNewlineOffset
;
1114 assert(OriginalSpaces
>= 0);
1115 const auto RestoredLineLength
=
1116 C
.StartOfTokenColumn
+ C
.TokenLength
+ OriginalSpaces
;
1117 // If leaving comments makes the line exceed the column limit, give up to
1118 // leave the comments.
1119 if (RestoredLineLength
>= Style
.ColumnLimit
&& Style
.ColumnLimit
> 0)
1121 C
.Spaces
= C
.NewlinesBefore
> 0 ? C
.Tok
->OriginalColumn
: OriginalSpaces
;
1125 const int ChangeMinColumn
= C
.StartOfTokenColumn
;
1126 int ChangeMaxColumn
;
1128 // If we don't create a replacement for this change, we have to consider
1129 // it to be immovable.
1130 if (!C
.CreateReplacement
)
1131 ChangeMaxColumn
= ChangeMinColumn
;
1132 else if (Style
.ColumnLimit
== 0)
1133 ChangeMaxColumn
= INT_MAX
;
1134 else if (Style
.ColumnLimit
>= C
.TokenLength
)
1135 ChangeMaxColumn
= Style
.ColumnLimit
- C
.TokenLength
;
1137 ChangeMaxColumn
= ChangeMinColumn
;
1139 if (I
+ 1 < Size
&& Changes
[I
+ 1].ContinuesPPDirective
&&
1140 ChangeMaxColumn
>= 2) {
1141 ChangeMaxColumn
-= 2;
1144 bool WasAlignedWithStartOfNextLine
= false;
1145 if (C
.NewlinesBefore
>= 1) { // A comment on its own line.
1146 const auto CommentColumn
=
1147 SourceMgr
.getSpellingColumnNumber(C
.OriginalWhitespaceRange
.getEnd());
1148 for (int J
= I
+ 1; J
< Size
; ++J
) {
1149 if (Changes
[J
].Tok
->is(tok::comment
))
1152 const auto NextColumn
= SourceMgr
.getSpellingColumnNumber(
1153 Changes
[J
].OriginalWhitespaceRange
.getEnd());
1154 // The start of the next token was previously aligned with the
1155 // start of this comment.
1156 WasAlignedWithStartOfNextLine
=
1157 CommentColumn
== NextColumn
||
1158 CommentColumn
== NextColumn
+ Style
.IndentWidth
;
1163 // We don't want to align comments which end a scope, which are here
1164 // identified by most closing braces.
1165 auto DontAlignThisComment
= [](const auto *Tok
) {
1166 if (Tok
->is(tok::semi
)) {
1167 Tok
= Tok
->getPreviousNonComment();
1171 if (Tok
->is(tok::r_paren
)) {
1172 // Back up past the parentheses and a `TT_DoWhile` that may precede.
1173 Tok
= Tok
->MatchingParen
;
1176 Tok
= Tok
->getPreviousNonComment();
1179 if (Tok
->is(TT_DoWhile
)) {
1180 const auto *Prev
= Tok
->getPreviousNonComment();
1182 // A do-while-loop without braces.
1189 if (Tok
->isNot(tok::r_brace
))
1192 while (Tok
->Previous
&& Tok
->Previous
->is(tok::r_brace
))
1193 Tok
= Tok
->Previous
;
1194 return Tok
->NewlinesBefore
> 0;
1197 if (I
> 0 && C
.NewlinesBefore
== 0 &&
1198 DontAlignThisComment(Changes
[I
- 1].Tok
)) {
1199 alignTrailingComments(StartOfSequence
, I
, MinColumn
);
1200 // Reset to initial values, but skip this change for the next alignment
1203 MaxColumn
= INT_MAX
;
1204 StartOfSequence
= I
+ 1;
1205 } else if (BreakBeforeNext
|| Newlines
> NewLineThreshold
||
1206 (ChangeMinColumn
> MaxColumn
|| ChangeMaxColumn
< MinColumn
) ||
1207 // Break the comment sequence if the previous line did not end
1208 // in a trailing comment.
1209 (C
.NewlinesBefore
== 1 && I
> 0 &&
1210 !Changes
[I
- 1].IsTrailingComment
) ||
1211 WasAlignedWithStartOfNextLine
) {
1212 alignTrailingComments(StartOfSequence
, I
, MinColumn
);
1213 MinColumn
= ChangeMinColumn
;
1214 MaxColumn
= ChangeMaxColumn
;
1215 StartOfSequence
= I
;
1217 MinColumn
= std::max(MinColumn
, ChangeMinColumn
);
1218 MaxColumn
= std::min(MaxColumn
, ChangeMaxColumn
);
1220 BreakBeforeNext
= (I
== 0) || (C
.NewlinesBefore
> 1) ||
1221 // Never start a sequence with a comment at the beginning
1223 (C
.NewlinesBefore
== 1 && StartOfSequence
== I
);
1226 alignTrailingComments(StartOfSequence
, Size
, MinColumn
);
1229 void WhitespaceManager::alignTrailingComments(unsigned Start
, unsigned End
,
1231 for (unsigned i
= Start
; i
!= End
; ++i
) {
1233 if (Changes
[i
].IsTrailingComment
)
1234 Shift
= Column
- Changes
[i
].StartOfTokenColumn
;
1235 if (Changes
[i
].StartOfBlockComment
) {
1236 Shift
= Changes
[i
].IndentationOffset
+
1237 Changes
[i
].StartOfBlockComment
->StartOfTokenColumn
-
1238 Changes
[i
].StartOfTokenColumn
;
1242 Changes
[i
].Spaces
+= Shift
;
1243 if (i
+ 1 != Changes
.size())
1244 Changes
[i
+ 1].PreviousEndOfTokenColumn
+= Shift
;
1245 Changes
[i
].StartOfTokenColumn
+= Shift
;
1249 void WhitespaceManager::alignEscapedNewlines() {
1250 const auto Align
= Style
.AlignEscapedNewlines
;
1251 if (Align
== FormatStyle::ENAS_DontAlign
)
1254 const bool WithLastLine
= Align
== FormatStyle::ENAS_LeftWithLastLine
;
1255 const bool AlignLeft
= Align
== FormatStyle::ENAS_Left
|| WithLastLine
;
1256 const auto MaxColumn
= Style
.ColumnLimit
;
1257 unsigned MaxEndOfLine
= AlignLeft
? 0 : MaxColumn
;
1258 unsigned StartOfMacro
= 0;
1259 for (unsigned i
= 1, e
= Changes
.size(); i
< e
; ++i
) {
1260 Change
&C
= Changes
[i
];
1261 if (C
.NewlinesBefore
== 0 && (!WithLastLine
|| C
.Tok
->isNot(tok::eof
)))
1263 const bool InPPDirective
= C
.ContinuesPPDirective
;
1264 const auto BackslashColumn
= C
.PreviousEndOfTokenColumn
+ 2;
1265 if (InPPDirective
||
1266 (WithLastLine
&& (MaxColumn
== 0 || BackslashColumn
<= MaxColumn
))) {
1267 MaxEndOfLine
= std::max(BackslashColumn
, MaxEndOfLine
);
1269 if (!InPPDirective
) {
1270 alignEscapedNewlines(StartOfMacro
+ 1, i
, MaxEndOfLine
);
1271 MaxEndOfLine
= AlignLeft
? 0 : MaxColumn
;
1275 alignEscapedNewlines(StartOfMacro
+ 1, Changes
.size(), MaxEndOfLine
);
1278 void WhitespaceManager::alignEscapedNewlines(unsigned Start
, unsigned End
,
1280 for (unsigned i
= Start
; i
< End
; ++i
) {
1281 Change
&C
= Changes
[i
];
1282 if (C
.NewlinesBefore
> 0) {
1283 assert(C
.ContinuesPPDirective
);
1284 if (C
.PreviousEndOfTokenColumn
+ 1 > Column
)
1285 C
.EscapedNewlineColumn
= 0;
1287 C
.EscapedNewlineColumn
= Column
;
1292 void WhitespaceManager::alignArrayInitializers() {
1293 if (Style
.AlignArrayOfStructures
== FormatStyle::AIAS_None
)
1296 for (unsigned ChangeIndex
= 1U, ChangeEnd
= Changes
.size();
1297 ChangeIndex
< ChangeEnd
; ++ChangeIndex
) {
1298 auto &C
= Changes
[ChangeIndex
];
1299 if (C
.Tok
->IsArrayInitializer
) {
1300 bool FoundComplete
= false;
1301 for (unsigned InsideIndex
= ChangeIndex
+ 1; InsideIndex
< ChangeEnd
;
1303 if (Changes
[InsideIndex
].Tok
== C
.Tok
->MatchingParen
) {
1304 alignArrayInitializers(ChangeIndex
, InsideIndex
+ 1);
1305 ChangeIndex
= InsideIndex
+ 1;
1306 FoundComplete
= true;
1311 ChangeIndex
= ChangeEnd
;
1316 void WhitespaceManager::alignArrayInitializers(unsigned Start
, unsigned End
) {
1318 if (Style
.AlignArrayOfStructures
== FormatStyle::AIAS_Right
)
1319 alignArrayInitializersRightJustified(getCells(Start
, End
));
1320 else if (Style
.AlignArrayOfStructures
== FormatStyle::AIAS_Left
)
1321 alignArrayInitializersLeftJustified(getCells(Start
, End
));
1324 void WhitespaceManager::alignArrayInitializersRightJustified(
1325 CellDescriptions
&&CellDescs
) {
1326 if (!CellDescs
.isRectangular())
1329 const int BracePadding
= Style
.Cpp11BracedListStyle
? 0 : 1;
1330 auto &Cells
= CellDescs
.Cells
;
1331 // Now go through and fixup the spaces.
1332 auto *CellIter
= Cells
.begin();
1333 for (auto i
= 0U; i
< CellDescs
.CellCounts
[0]; ++i
, ++CellIter
) {
1334 unsigned NetWidth
= 0U;
1335 if (isSplitCell(*CellIter
))
1336 NetWidth
= getNetWidth(Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
);
1337 auto CellWidth
= getMaximumCellWidth(CellIter
, NetWidth
);
1339 if (Changes
[CellIter
->Index
].Tok
->is(tok::r_brace
)) {
1340 // So in here we want to see if there is a brace that falls
1341 // on a line that was split. If so on that line we make sure that
1342 // the spaces in front of the brace are enough.
1343 const auto *Next
= CellIter
;
1345 const FormatToken
*Previous
= Changes
[Next
->Index
].Tok
->Previous
;
1346 if (Previous
&& Previous
->isNot(TT_LineComment
)) {
1347 Changes
[Next
->Index
].Spaces
= BracePadding
;
1348 Changes
[Next
->Index
].NewlinesBefore
= 0;
1350 Next
= Next
->NextColumnElement
;
1352 // Unless the array is empty, we need the position of all the
1353 // immediately adjacent cells
1354 if (CellIter
!= Cells
.begin()) {
1356 getNetWidth(Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
);
1357 auto MaxNetWidth
= getMaximumNetWidth(
1358 Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
,
1359 CellDescs
.CellCounts
[0], CellDescs
.CellCounts
.size());
1360 if (ThisNetWidth
< MaxNetWidth
)
1361 Changes
[CellIter
->Index
].Spaces
= (MaxNetWidth
- ThisNetWidth
);
1363 auto Offset
= std::distance(Cells
.begin(), CellIter
);
1364 for (const auto *Next
= CellIter
->NextColumnElement
; Next
;
1365 Next
= Next
->NextColumnElement
) {
1366 if (RowCount
>= CellDescs
.CellCounts
.size())
1368 auto *Start
= (Cells
.begin() + RowCount
* CellDescs
.CellCounts
[0]);
1369 auto *End
= Start
+ Offset
;
1370 ThisNetWidth
= getNetWidth(Start
, End
, CellDescs
.InitialSpaces
);
1371 if (ThisNetWidth
< MaxNetWidth
)
1372 Changes
[Next
->Index
].Spaces
= (MaxNetWidth
- ThisNetWidth
);
1378 calculateCellWidth(CellIter
->Index
, CellIter
->EndIndex
, true) +
1380 if (Changes
[CellIter
->Index
].NewlinesBefore
== 0) {
1381 Changes
[CellIter
->Index
].Spaces
= (CellWidth
- (ThisWidth
+ NetWidth
));
1382 Changes
[CellIter
->Index
].Spaces
+= (i
> 0) ? 1 : BracePadding
;
1384 alignToStartOfCell(CellIter
->Index
, CellIter
->EndIndex
);
1385 for (const auto *Next
= CellIter
->NextColumnElement
; Next
;
1386 Next
= Next
->NextColumnElement
) {
1388 calculateCellWidth(Next
->Index
, Next
->EndIndex
, true) + NetWidth
;
1389 if (Changes
[Next
->Index
].NewlinesBefore
== 0) {
1390 Changes
[Next
->Index
].Spaces
= (CellWidth
- ThisWidth
);
1391 Changes
[Next
->Index
].Spaces
+= (i
> 0) ? 1 : BracePadding
;
1393 alignToStartOfCell(Next
->Index
, Next
->EndIndex
);
1399 void WhitespaceManager::alignArrayInitializersLeftJustified(
1400 CellDescriptions
&&CellDescs
) {
1402 if (!CellDescs
.isRectangular())
1405 const int BracePadding
= Style
.Cpp11BracedListStyle
? 0 : 1;
1406 auto &Cells
= CellDescs
.Cells
;
1407 // Now go through and fixup the spaces.
1408 auto *CellIter
= Cells
.begin();
1409 // The first cell of every row needs to be against the left brace.
1410 for (const auto *Next
= CellIter
; Next
; Next
= Next
->NextColumnElement
) {
1411 auto &Change
= Changes
[Next
->Index
];
1413 Change
.NewlinesBefore
== 0 ? BracePadding
: CellDescs
.InitialSpaces
;
1416 for (auto i
= 1U; i
< CellDescs
.CellCounts
[0]; i
++, ++CellIter
) {
1417 auto MaxNetWidth
= getMaximumNetWidth(
1418 Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
,
1419 CellDescs
.CellCounts
[0], CellDescs
.CellCounts
.size());
1421 getNetWidth(Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
);
1422 if (Changes
[CellIter
->Index
].NewlinesBefore
== 0) {
1423 Changes
[CellIter
->Index
].Spaces
=
1424 MaxNetWidth
- ThisNetWidth
+
1425 (Changes
[CellIter
->Index
].Tok
->isNot(tok::r_brace
) ? 1
1429 auto Offset
= std::distance(Cells
.begin(), CellIter
);
1430 for (const auto *Next
= CellIter
->NextColumnElement
; Next
;
1431 Next
= Next
->NextColumnElement
) {
1432 if (RowCount
>= CellDescs
.CellCounts
.size())
1434 auto *Start
= (Cells
.begin() + RowCount
* CellDescs
.CellCounts
[0]);
1435 auto *End
= Start
+ Offset
;
1436 auto ThisNetWidth
= getNetWidth(Start
, End
, CellDescs
.InitialSpaces
);
1437 if (Changes
[Next
->Index
].NewlinesBefore
== 0) {
1438 Changes
[Next
->Index
].Spaces
=
1439 MaxNetWidth
- ThisNetWidth
+
1440 (Changes
[Next
->Index
].Tok
->isNot(tok::r_brace
) ? 1 : BracePadding
);
1447 bool WhitespaceManager::isSplitCell(const CellDescription
&Cell
) {
1450 for (const auto *Next
= Cell
.NextColumnElement
; Next
;
1451 Next
= Next
->NextColumnElement
) {
1458 WhitespaceManager::CellDescriptions
WhitespaceManager::getCells(unsigned Start
,
1463 SmallVector
<unsigned> CellCounts
;
1464 unsigned InitialSpaces
= 0;
1465 unsigned InitialTokenLength
= 0;
1466 unsigned EndSpaces
= 0;
1467 SmallVector
<CellDescription
> Cells
;
1468 const FormatToken
*MatchingParen
= nullptr;
1469 for (unsigned i
= Start
; i
< End
; ++i
) {
1470 auto &C
= Changes
[i
];
1471 if (C
.Tok
->is(tok::l_brace
))
1473 else if (C
.Tok
->is(tok::r_brace
))
1476 if (C
.Tok
->is(tok::l_brace
)) {
1478 MatchingParen
= C
.Tok
->MatchingParen
;
1479 if (InitialSpaces
== 0) {
1480 InitialSpaces
= C
.Spaces
+ C
.TokenLength
;
1481 InitialTokenLength
= C
.TokenLength
;
1483 for (; Changes
[j
].NewlinesBefore
== 0 && j
> Start
; --j
) {
1484 InitialSpaces
+= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
1485 InitialTokenLength
+= Changes
[j
].TokenLength
;
1487 if (C
.NewlinesBefore
== 0) {
1488 InitialSpaces
+= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
1489 InitialTokenLength
+= Changes
[j
].TokenLength
;
1492 } else if (C
.Tok
->is(tok::comma
)) {
1494 Cells
.back().EndIndex
= i
;
1495 if (const auto *Next
= C
.Tok
->getNextNonComment();
1496 Next
&& Next
->isNot(tok::r_brace
)) { // dangling comma
1500 } else if (Depth
== 1) {
1501 if (C
.Tok
== MatchingParen
) {
1503 Cells
.back().EndIndex
= i
;
1504 Cells
.push_back(CellDescription
{i
, ++Cell
, i
+ 1, false, nullptr});
1505 CellCounts
.push_back(C
.Tok
->Previous
->isNot(tok::comma
) ? Cell
+ 1
1507 // Go to the next non-comment and ensure there is a break in front
1508 const auto *NextNonComment
= C
.Tok
->getNextNonComment();
1509 while (NextNonComment
&& NextNonComment
->is(tok::comma
))
1510 NextNonComment
= NextNonComment
->getNextNonComment();
1512 while (j
< End
&& Changes
[j
].Tok
!= NextNonComment
)
1514 if (j
< End
&& Changes
[j
].NewlinesBefore
== 0 &&
1515 Changes
[j
].Tok
->isNot(tok::r_brace
)) {
1516 Changes
[j
].NewlinesBefore
= 1;
1517 // Account for the added token lengths
1518 Changes
[j
].Spaces
= InitialSpaces
- InitialTokenLength
;
1520 } else if (C
.Tok
->is(tok::comment
) && C
.Tok
->NewlinesBefore
== 0) {
1521 // Trailing comments stay at a space past the last token
1522 C
.Spaces
= Changes
[i
- 1].Tok
->is(tok::comma
) ? 1 : 2;
1523 } else if (C
.Tok
->is(tok::l_brace
)) {
1524 // We need to make sure that the ending braces is aligned to the
1525 // start of our initializer
1527 for (; j
> 0 && !Changes
[j
].Tok
->ArrayInitializerLineStart
; --j
)
1528 ; // Nothing the loop does the work
1529 EndSpaces
= Changes
[j
].Spaces
;
1531 } else if (Depth
== 0 && C
.Tok
->is(tok::r_brace
)) {
1532 C
.NewlinesBefore
= 1;
1533 C
.Spaces
= EndSpaces
;
1535 if (C
.Tok
->StartsColumn
) {
1536 // This gets us past tokens that have been split over multiple
1538 bool HasSplit
= false;
1539 if (Changes
[i
].NewlinesBefore
> 0) {
1540 // So if we split a line previously and the tail line + this token is
1541 // less then the column limit we remove the split here and just put
1542 // the column start at a space past the comma
1544 // FIXME This if branch covers the cases where the column is not
1545 // the first column. This leads to weird pathologies like the formatting
1546 // auto foo = Items{
1551 // Well if it doesn't lead to that it's indicative that the line
1552 // breaking should be revisited. Unfortunately alot of other options
1553 // interact with this
1555 if ((j
- 1) > Start
&& Changes
[j
].Tok
->is(tok::comma
) &&
1556 Changes
[j
- 1].NewlinesBefore
> 0) {
1558 auto LineLimit
= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
1559 if (LineLimit
< Style
.ColumnLimit
) {
1560 Changes
[i
].NewlinesBefore
= 0;
1561 Changes
[i
].Spaces
= 1;
1565 while (Changes
[i
].NewlinesBefore
> 0 && Changes
[i
].Tok
== C
.Tok
) {
1566 Changes
[i
].Spaces
= InitialSpaces
;
1570 if (Changes
[i
].Tok
!= C
.Tok
)
1572 Cells
.push_back(CellDescription
{i
, Cell
, i
, HasSplit
, nullptr});
1576 return linkCells({Cells
, CellCounts
, InitialSpaces
});
1579 unsigned WhitespaceManager::calculateCellWidth(unsigned Start
, unsigned End
,
1580 bool WithSpaces
) const {
1581 unsigned CellWidth
= 0;
1582 for (auto i
= Start
; i
< End
; i
++) {
1583 if (Changes
[i
].NewlinesBefore
> 0)
1585 CellWidth
+= Changes
[i
].TokenLength
;
1586 CellWidth
+= (WithSpaces
? Changes
[i
].Spaces
: 0);
1591 void WhitespaceManager::alignToStartOfCell(unsigned Start
, unsigned End
) {
1592 if ((End
- Start
) <= 1)
1594 // If the line is broken anywhere in there make sure everything
1595 // is aligned to the parent
1596 for (auto i
= Start
+ 1; i
< End
; i
++)
1597 if (Changes
[i
].NewlinesBefore
> 0)
1598 Changes
[i
].Spaces
= Changes
[Start
].Spaces
;
1601 WhitespaceManager::CellDescriptions
1602 WhitespaceManager::linkCells(CellDescriptions
&&CellDesc
) {
1603 auto &Cells
= CellDesc
.Cells
;
1604 for (auto *CellIter
= Cells
.begin(); CellIter
!= Cells
.end(); ++CellIter
) {
1605 if (!CellIter
->NextColumnElement
&& (CellIter
+ 1) != Cells
.end()) {
1606 for (auto *NextIter
= CellIter
+ 1; NextIter
!= Cells
.end(); ++NextIter
) {
1607 if (NextIter
->Cell
== CellIter
->Cell
) {
1608 CellIter
->NextColumnElement
= &(*NextIter
);
1614 return std::move(CellDesc
);
1617 void WhitespaceManager::generateChanges() {
1618 for (unsigned i
= 0, e
= Changes
.size(); i
!= e
; ++i
) {
1619 const Change
&C
= Changes
[i
];
1621 auto Last
= Changes
[i
- 1].OriginalWhitespaceRange
;
1622 auto New
= Changes
[i
].OriginalWhitespaceRange
;
1623 // Do not generate two replacements for the same location. As a special
1624 // case, it is allowed if there is a replacement for the empty range
1625 // between 2 tokens and another non-empty range at the start of the second
1626 // token. We didn't implement logic to combine replacements for 2
1627 // consecutive source ranges into a single replacement, because the
1628 // program works fine without it.
1630 // We can't eliminate empty original whitespace ranges. They appear when
1631 // 2 tokens have no whitespace in between in the input. It does not
1632 // matter whether whitespace is to be added. If no whitespace is to be
1633 // added, the replacement will be empty, and it gets eliminated after this
1634 // step in storeReplacement. For example, if the input is `foo();`,
1635 // there will be a replacement for the range between every consecutive
1638 // A replacement at the start of a token can be added by
1639 // BreakableStringLiteralUsingOperators::insertBreak when it adds braces
1640 // around the string literal. Say Verilog code is being formatted and the
1641 // first line is to become the next 2 lines.
1642 // x("long string");
1645 // There will be a replacement for the empty range between the parenthesis
1646 // and the string and another replacement for the quote character. The
1647 // replacement for the empty range between the parenthesis and the quote
1648 // comes from ContinuationIndenter::addTokenOnCurrentLine when it changes
1649 // the original empty range between the parenthesis and the string to
1650 // another empty one. The replacement for the quote character comes from
1651 // BreakableStringLiteralUsingOperators::insertBreak when it adds the
1652 // brace. In the example, the replacement for the empty range is the same
1653 // as the original text. However, eliminating replacements that are same
1654 // as the original does not help in general. For example, a newline can
1655 // be inserted, causing the first line to become the next 3 lines.
1656 // xxxxxxxxxxx("long string");
1660 // In that case, the empty range between the parenthesis and the string
1661 // will be replaced by a newline and 4 spaces. So we will still have to
1662 // deal with a replacement for an empty source range followed by a
1663 // replacement for a non-empty source range.
1664 if (Last
.getBegin() == New
.getBegin() &&
1665 (Last
.getEnd() != Last
.getBegin() ||
1666 New
.getEnd() == New
.getBegin())) {
1670 if (C
.CreateReplacement
) {
1671 std::string ReplacementText
= C
.PreviousLinePostfix
;
1672 if (C
.ContinuesPPDirective
) {
1673 appendEscapedNewlineText(ReplacementText
, C
.NewlinesBefore
,
1674 C
.PreviousEndOfTokenColumn
,
1675 C
.EscapedNewlineColumn
);
1677 appendNewlineText(ReplacementText
, C
.NewlinesBefore
);
1679 // FIXME: This assert should hold if we computed the column correctly.
1680 // assert((int)C.StartOfTokenColumn >= C.Spaces);
1682 ReplacementText
, C
.Tok
->IndentLevel
, std::max(0, C
.Spaces
),
1683 std::max((int)C
.StartOfTokenColumn
, C
.Spaces
) - std::max(0, C
.Spaces
),
1685 ReplacementText
.append(C
.CurrentLinePrefix
);
1686 storeReplacement(C
.OriginalWhitespaceRange
, ReplacementText
);
1691 void WhitespaceManager::storeReplacement(SourceRange Range
, StringRef Text
) {
1692 unsigned WhitespaceLength
= SourceMgr
.getFileOffset(Range
.getEnd()) -
1693 SourceMgr
.getFileOffset(Range
.getBegin());
1694 // Don't create a replacement, if it does not change anything.
1695 if (StringRef(SourceMgr
.getCharacterData(Range
.getBegin()),
1696 WhitespaceLength
) == Text
) {
1699 auto Err
= Replaces
.add(tooling::Replacement(
1700 SourceMgr
, CharSourceRange::getCharRange(Range
), Text
));
1701 // FIXME: better error handling. For now, just print an error message in the
1704 llvm::errs() << llvm::toString(std::move(Err
)) << "\n";
1709 void WhitespaceManager::appendNewlineText(std::string
&Text
,
1710 unsigned Newlines
) {
1712 Text
.reserve(Text
.size() + 2 * Newlines
);
1713 for (unsigned i
= 0; i
< Newlines
; ++i
)
1714 Text
.append("\r\n");
1716 Text
.append(Newlines
, '\n');
1720 void WhitespaceManager::appendEscapedNewlineText(
1721 std::string
&Text
, unsigned Newlines
, unsigned PreviousEndOfTokenColumn
,
1722 unsigned EscapedNewlineColumn
) {
1725 std::max
<int>(1, EscapedNewlineColumn
- PreviousEndOfTokenColumn
- 1);
1726 for (unsigned i
= 0; i
< Newlines
; ++i
) {
1727 Text
.append(Spaces
, ' ');
1728 Text
.append(UseCRLF
? "\\\r\n" : "\\\n");
1729 Spaces
= std::max
<int>(0, EscapedNewlineColumn
- 1);
1734 void WhitespaceManager::appendIndentText(std::string
&Text
,
1735 unsigned IndentLevel
, unsigned Spaces
,
1736 unsigned WhitespaceStartColumn
,
1738 switch (Style
.UseTab
) {
1739 case FormatStyle::UT_Never
:
1740 Text
.append(Spaces
, ' ');
1742 case FormatStyle::UT_Always
: {
1743 if (Style
.TabWidth
) {
1744 unsigned FirstTabWidth
=
1745 Style
.TabWidth
- WhitespaceStartColumn
% Style
.TabWidth
;
1747 // Insert only spaces when we want to end up before the next tab.
1748 if (Spaces
< FirstTabWidth
|| Spaces
== 1) {
1749 Text
.append(Spaces
, ' ');
1752 // Align to the next tab.
1753 Spaces
-= FirstTabWidth
;
1756 Text
.append(Spaces
/ Style
.TabWidth
, '\t');
1757 Text
.append(Spaces
% Style
.TabWidth
, ' ');
1758 } else if (Spaces
== 1) {
1759 Text
.append(Spaces
, ' ');
1763 case FormatStyle::UT_ForIndentation
:
1764 if (WhitespaceStartColumn
== 0) {
1765 unsigned Indentation
= IndentLevel
* Style
.IndentWidth
;
1766 Spaces
= appendTabIndent(Text
, Spaces
, Indentation
);
1768 Text
.append(Spaces
, ' ');
1770 case FormatStyle::UT_ForContinuationAndIndentation
:
1771 if (WhitespaceStartColumn
== 0)
1772 Spaces
= appendTabIndent(Text
, Spaces
, Spaces
);
1773 Text
.append(Spaces
, ' ');
1775 case FormatStyle::UT_AlignWithSpaces
:
1776 if (WhitespaceStartColumn
== 0) {
1777 unsigned Indentation
=
1778 IsAligned
? IndentLevel
* Style
.IndentWidth
: Spaces
;
1779 Spaces
= appendTabIndent(Text
, Spaces
, Indentation
);
1781 Text
.append(Spaces
, ' ');
1786 unsigned WhitespaceManager::appendTabIndent(std::string
&Text
, unsigned Spaces
,
1787 unsigned Indentation
) {
1788 // This happens, e.g. when a line in a block comment is indented less than the
1790 if (Indentation
> Spaces
)
1791 Indentation
= Spaces
;
1792 if (Style
.TabWidth
) {
1793 unsigned Tabs
= Indentation
/ Style
.TabWidth
;
1794 Text
.append(Tabs
, '\t');
1795 Spaces
-= Tabs
* Style
.TabWidth
;
1800 } // namespace format
1801 } // namespace clang