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());
29 WhitespaceManager::Change::Change(const FormatToken
&Tok
,
30 bool CreateReplacement
,
31 SourceRange OriginalWhitespaceRange
,
32 int Spaces
, unsigned StartOfTokenColumn
,
33 unsigned NewlinesBefore
,
34 StringRef PreviousLinePostfix
,
35 StringRef CurrentLinePrefix
, bool IsAligned
,
36 bool ContinuesPPDirective
, bool IsInsideToken
)
37 : Tok(&Tok
), CreateReplacement(CreateReplacement
),
38 OriginalWhitespaceRange(OriginalWhitespaceRange
),
39 StartOfTokenColumn(StartOfTokenColumn
), NewlinesBefore(NewlinesBefore
),
40 PreviousLinePostfix(PreviousLinePostfix
),
41 CurrentLinePrefix(CurrentLinePrefix
), IsAligned(IsAligned
),
42 ContinuesPPDirective(ContinuesPPDirective
), Spaces(Spaces
),
43 IsInsideToken(IsInsideToken
), IsTrailingComment(false), TokenLength(0),
44 PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
45 StartOfBlockComment(nullptr), IndentationOffset(0), ConditionalsLevel(0) {
48 void WhitespaceManager::replaceWhitespace(FormatToken
&Tok
, unsigned Newlines
,
50 unsigned StartOfTokenColumn
,
51 bool IsAligned
, bool InPPDirective
) {
54 Tok
.setDecision((Newlines
> 0) ? FD_Break
: FD_Continue
);
55 Changes
.push_back(Change(Tok
, /*CreateReplacement=*/true, Tok
.WhitespaceRange
,
56 Spaces
, StartOfTokenColumn
, Newlines
, "", "",
57 IsAligned
, InPPDirective
&& !Tok
.IsFirst
,
58 /*IsInsideToken=*/false));
61 void WhitespaceManager::addUntouchableToken(const FormatToken
&Tok
,
65 Changes
.push_back(Change(Tok
, /*CreateReplacement=*/false,
66 Tok
.WhitespaceRange
, /*Spaces=*/0,
67 Tok
.OriginalColumn
, Tok
.NewlinesBefore
, "", "",
68 /*IsAligned=*/false, InPPDirective
&& !Tok
.IsFirst
,
69 /*IsInsideToken=*/false));
73 WhitespaceManager::addReplacement(const tooling::Replacement
&Replacement
) {
74 return Replaces
.add(Replacement
);
77 bool WhitespaceManager::inputUsesCRLF(StringRef Text
, bool DefaultToCRLF
) {
78 size_t LF
= Text
.count('\n');
79 size_t CR
= Text
.count('\r') * 2;
80 return LF
== CR
? DefaultToCRLF
: CR
> LF
;
83 void WhitespaceManager::replaceWhitespaceInToken(
84 const FormatToken
&Tok
, unsigned Offset
, unsigned ReplaceChars
,
85 StringRef PreviousPostfix
, StringRef CurrentPrefix
, bool InPPDirective
,
86 unsigned Newlines
, int Spaces
) {
89 SourceLocation Start
= Tok
.getStartOfNonWhitespace().getLocWithOffset(Offset
);
91 Change(Tok
, /*CreateReplacement=*/true,
92 SourceRange(Start
, Start
.getLocWithOffset(ReplaceChars
)), Spaces
,
93 std::max(0, Spaces
), Newlines
, PreviousPostfix
, CurrentPrefix
,
94 /*IsAligned=*/true, InPPDirective
&& !Tok
.IsFirst
,
95 /*IsInsideToken=*/true));
98 const tooling::Replacements
&WhitespaceManager::generateReplacements() {
102 llvm::sort(Changes
, Change::IsBeforeInFile(SourceMgr
));
103 calculateLineBreakInformation();
104 alignConsecutiveMacros();
105 alignConsecutiveDeclarations();
106 alignConsecutiveBitFields();
107 alignConsecutiveAssignments();
108 alignChainedConditionals();
109 alignTrailingComments();
110 alignEscapedNewlines();
111 alignArrayInitializers();
117 void WhitespaceManager::calculateLineBreakInformation() {
118 Changes
[0].PreviousEndOfTokenColumn
= 0;
119 Change
*LastOutsideTokenChange
= &Changes
[0];
120 for (unsigned i
= 1, e
= Changes
.size(); i
!= e
; ++i
) {
121 SourceLocation OriginalWhitespaceStart
=
122 Changes
[i
].OriginalWhitespaceRange
.getBegin();
123 SourceLocation PreviousOriginalWhitespaceEnd
=
124 Changes
[i
- 1].OriginalWhitespaceRange
.getEnd();
125 unsigned OriginalWhitespaceStartOffset
=
126 SourceMgr
.getFileOffset(OriginalWhitespaceStart
);
127 unsigned PreviousOriginalWhitespaceEndOffset
=
128 SourceMgr
.getFileOffset(PreviousOriginalWhitespaceEnd
);
129 assert(PreviousOriginalWhitespaceEndOffset
<=
130 OriginalWhitespaceStartOffset
);
131 const char *const PreviousOriginalWhitespaceEndData
=
132 SourceMgr
.getCharacterData(PreviousOriginalWhitespaceEnd
);
133 StringRef
Text(PreviousOriginalWhitespaceEndData
,
134 SourceMgr
.getCharacterData(OriginalWhitespaceStart
) -
135 PreviousOriginalWhitespaceEndData
);
136 // Usually consecutive changes would occur in consecutive tokens. This is
137 // not the case however when analyzing some preprocessor runs of the
138 // annotated lines. For example, in this code:
146 // one of the runs will produce the sequence of lines marked with line 1, 2
147 // and 3. So the two consecutive whitespace changes just before '// line 2'
148 // and before '#endif // line 3' span multiple lines and tokens:
150 // #else B{change X}[// line 2
152 // ]{change Y}#endif // line 3
154 // For this reason, if the text between consecutive changes spans multiple
155 // newlines, the token length must be adjusted to the end of the original
156 // line of the token.
157 auto NewlinePos
= Text
.find_first_of('\n');
158 if (NewlinePos
== StringRef::npos
) {
159 Changes
[i
- 1].TokenLength
= OriginalWhitespaceStartOffset
-
160 PreviousOriginalWhitespaceEndOffset
+
161 Changes
[i
].PreviousLinePostfix
.size() +
162 Changes
[i
- 1].CurrentLinePrefix
.size();
164 Changes
[i
- 1].TokenLength
=
165 NewlinePos
+ Changes
[i
- 1].CurrentLinePrefix
.size();
168 // If there are multiple changes in this token, sum up all the changes until
169 // the end of the line.
170 if (Changes
[i
- 1].IsInsideToken
&& Changes
[i
- 1].NewlinesBefore
== 0) {
171 LastOutsideTokenChange
->TokenLength
+=
172 Changes
[i
- 1].TokenLength
+ Changes
[i
- 1].Spaces
;
174 LastOutsideTokenChange
= &Changes
[i
- 1];
177 Changes
[i
].PreviousEndOfTokenColumn
=
178 Changes
[i
- 1].StartOfTokenColumn
+ Changes
[i
- 1].TokenLength
;
180 Changes
[i
- 1].IsTrailingComment
=
181 (Changes
[i
].NewlinesBefore
> 0 || Changes
[i
].Tok
->is(tok::eof
) ||
182 (Changes
[i
].IsInsideToken
&& Changes
[i
].Tok
->is(tok::comment
))) &&
183 Changes
[i
- 1].Tok
->is(tok::comment
) &&
184 // FIXME: This is a dirty hack. The problem is that
185 // BreakableLineCommentSection does comment reflow changes and here is
186 // the aligning of trailing comments. Consider the case where we reflow
187 // the second line up in this example:
192 // That amounts to 2 changes by BreakableLineCommentSection:
193 // - the first, delimited by (), for the whitespace between the tokens,
194 // - and second, delimited by [], for the whitespace at the beginning
195 // of the second token:
200 // So in the end we have two changes like this:
202 // // line1()[ ]line 2
204 // Note that the OriginalWhitespaceStart of the second change is the
205 // same as the PreviousOriginalWhitespaceEnd of the first change.
206 // In this case, the below check ensures that the second change doesn't
207 // get treated as a trailing comment change here, since this might
208 // trigger additional whitespace to be wrongly inserted before "line 2"
209 // by the comment aligner here.
211 // For a proper solution we need a mechanism to say to WhitespaceManager
212 // that a particular change breaks the current sequence of trailing
214 OriginalWhitespaceStart
!= PreviousOriginalWhitespaceEnd
;
216 // FIXME: The last token is currently not always an eof token; in those
217 // cases, setting TokenLength of the last token to 0 is wrong.
218 Changes
.back().TokenLength
= 0;
219 Changes
.back().IsTrailingComment
= Changes
.back().Tok
->is(tok::comment
);
221 const WhitespaceManager::Change
*LastBlockComment
= nullptr;
222 for (auto &Change
: Changes
) {
223 // Reset the IsTrailingComment flag for changes inside of trailing comments
224 // so they don't get realigned later. Comment line breaks however still need
226 if (Change
.IsInsideToken
&& Change
.NewlinesBefore
== 0)
227 Change
.IsTrailingComment
= false;
228 Change
.StartOfBlockComment
= nullptr;
229 Change
.IndentationOffset
= 0;
230 if (Change
.Tok
->is(tok::comment
)) {
231 if (Change
.Tok
->is(TT_LineComment
) || !Change
.IsInsideToken
) {
232 LastBlockComment
= &Change
;
233 } else if ((Change
.StartOfBlockComment
= LastBlockComment
)) {
234 Change
.IndentationOffset
=
235 Change
.StartOfTokenColumn
-
236 Change
.StartOfBlockComment
->StartOfTokenColumn
;
239 LastBlockComment
= nullptr;
243 // Compute conditional nesting level
244 // Level is increased for each conditional, unless this conditional continues
245 // a chain of conditional, i.e. starts immediately after the colon of another
247 SmallVector
<bool, 16> ScopeStack
;
248 int ConditionalsLevel
= 0;
249 for (auto &Change
: Changes
) {
250 for (unsigned i
= 0, e
= Change
.Tok
->FakeLParens
.size(); i
!= e
; ++i
) {
251 bool isNestedConditional
=
252 Change
.Tok
->FakeLParens
[e
- 1 - i
] == prec::Conditional
&&
253 !(i
== 0 && Change
.Tok
->Previous
&&
254 Change
.Tok
->Previous
->is(TT_ConditionalExpr
) &&
255 Change
.Tok
->Previous
->is(tok::colon
));
256 if (isNestedConditional
)
258 ScopeStack
.push_back(isNestedConditional
);
261 Change
.ConditionalsLevel
= ConditionalsLevel
;
263 for (unsigned i
= Change
.Tok
->FakeRParens
; i
> 0 && ScopeStack
.size(); --i
)
264 if (ScopeStack
.pop_back_val())
269 // Align a single sequence of tokens, see AlignTokens below.
270 // Column - The token for which Matches returns true is moved to this column.
271 // RightJustify - Whether it is the token's right end or left end that gets
272 // moved to that column.
273 template <typename F
>
275 AlignTokenSequence(const FormatStyle
&Style
, unsigned Start
, unsigned End
,
276 unsigned Column
, bool RightJustify
, F
&&Matches
,
277 SmallVector
<WhitespaceManager::Change
, 16> &Changes
) {
278 bool FoundMatchOnLine
= false;
281 // ScopeStack keeps track of the current scope depth. It contains indices of
282 // the first token on each scope.
283 // We only run the "Matches" function on tokens from the outer-most scope.
284 // However, we do need to pay special attention to one class of tokens
285 // that are not in the outer-most scope, and that is function parameters
286 // which are split across multiple lines, as illustrated by this example:
290 // In the above example, we need to take special care to ensure that
291 // 'double z' is indented along with it's owning function 'b'.
292 // The same holds for calling a function:
293 // double a = foo(x);
294 // int b = bar(foo(y),
296 // Similar for broken string literals:
300 // Special handling is required for 'nested' ternary operators.
301 SmallVector
<unsigned, 16> ScopeStack
;
303 for (unsigned i
= Start
; i
!= End
; ++i
) {
304 if (ScopeStack
.size() != 0 &&
305 Changes
[i
].indentAndNestingLevel() <
306 Changes
[ScopeStack
.back()].indentAndNestingLevel()) {
307 ScopeStack
.pop_back();
310 // Compare current token to previous non-comment token to ensure whether
311 // it is in a deeper scope or not.
312 unsigned PreviousNonComment
= i
- 1;
313 while (PreviousNonComment
> Start
&&
314 Changes
[PreviousNonComment
].Tok
->is(tok::comment
)) {
315 --PreviousNonComment
;
317 if (i
!= Start
&& Changes
[i
].indentAndNestingLevel() >
318 Changes
[PreviousNonComment
].indentAndNestingLevel()) {
319 ScopeStack
.push_back(i
);
322 bool InsideNestedScope
= ScopeStack
.size() != 0;
323 bool ContinuedStringLiteral
= i
> Start
&&
324 Changes
[i
].Tok
->is(tok::string_literal
) &&
325 Changes
[i
- 1].Tok
->is(tok::string_literal
);
326 bool SkipMatchCheck
= InsideNestedScope
|| ContinuedStringLiteral
;
328 if (Changes
[i
].NewlinesBefore
> 0 && !SkipMatchCheck
) {
330 FoundMatchOnLine
= false;
333 // If this is the first matching token to be aligned, remember by how many
334 // spaces it has to be shifted, so the rest of the changes on the line are
335 // shifted by the same amount
336 if (!FoundMatchOnLine
&& !SkipMatchCheck
&& Matches(Changes
[i
])) {
337 FoundMatchOnLine
= true;
338 Shift
= Column
- (RightJustify
? Changes
[i
].TokenLength
: 0) -
339 Changes
[i
].StartOfTokenColumn
;
340 Changes
[i
].Spaces
+= Shift
;
341 // FIXME: This is a workaround that should be removed when we fix
342 // http://llvm.org/PR53699. An assertion later below verifies this.
343 if (Changes
[i
].NewlinesBefore
== 0) {
345 std::max(Changes
[i
].Spaces
,
346 static_cast<int>(Changes
[i
].Tok
->SpacesRequiredBefore
));
350 // This is for function parameters that are split across multiple lines,
351 // as mentioned in the ScopeStack comment.
352 if (InsideNestedScope
&& Changes
[i
].NewlinesBefore
> 0) {
353 unsigned ScopeStart
= ScopeStack
.back();
354 auto ShouldShiftBeAdded
= [&] {
355 // Function declaration
356 if (Changes
[ScopeStart
- 1].Tok
->is(TT_FunctionDeclarationName
))
360 if (Changes
[ScopeStart
- 1].Tok
->is(TT_LambdaLBrace
))
363 // Continued function declaration
364 if (ScopeStart
> Start
+ 1 &&
365 Changes
[ScopeStart
- 2].Tok
->is(TT_FunctionDeclarationName
)) {
369 // Continued function call
370 if (ScopeStart
> Start
+ 1 &&
371 Changes
[ScopeStart
- 2].Tok
->is(tok::identifier
) &&
372 Changes
[ScopeStart
- 1].Tok
->is(tok::l_paren
) &&
373 Changes
[ScopeStart
].Tok
->isNot(TT_LambdaLSquare
)) {
374 if (Changes
[i
].Tok
->MatchingParen
&&
375 Changes
[i
].Tok
->MatchingParen
->is(TT_LambdaLBrace
)) {
378 if (Changes
[ScopeStart
].NewlinesBefore
> 0)
380 if (Changes
[i
].Tok
->is(tok::l_brace
) &&
381 Changes
[i
].Tok
->is(BK_BracedInit
)) {
384 return Style
.BinPackArguments
;
388 if (Changes
[i
].Tok
->is(TT_ConditionalExpr
))
391 // Period Initializer .XXX = 1.
392 if (Changes
[i
].Tok
->is(TT_DesignatedInitializerPeriod
))
395 // Continued ternary operator
396 if (Changes
[i
].Tok
->Previous
&&
397 Changes
[i
].Tok
->Previous
->is(TT_ConditionalExpr
)) {
401 // Continued direct-list-initialization using braced list.
402 if (ScopeStart
> Start
+ 1 &&
403 Changes
[ScopeStart
- 2].Tok
->is(tok::identifier
) &&
404 Changes
[ScopeStart
- 1].Tok
->is(tok::l_brace
) &&
405 Changes
[i
].Tok
->is(tok::l_brace
) &&
406 Changes
[i
].Tok
->is(BK_BracedInit
)) {
410 // Continued braced list.
411 if (ScopeStart
> Start
+ 1 &&
412 Changes
[ScopeStart
- 2].Tok
->isNot(tok::identifier
) &&
413 Changes
[ScopeStart
- 1].Tok
->is(tok::l_brace
) &&
414 Changes
[i
].Tok
->isNot(tok::r_brace
)) {
415 for (unsigned OuterScopeStart
: llvm::reverse(ScopeStack
)) {
417 if (OuterScopeStart
> Start
&&
418 Changes
[OuterScopeStart
- 1].Tok
->is(TT_LambdaLBrace
)) {
422 if (Changes
[ScopeStart
].NewlinesBefore
> 0)
430 if (ShouldShiftBeAdded())
431 Changes
[i
].Spaces
+= Shift
;
434 if (ContinuedStringLiteral
)
435 Changes
[i
].Spaces
+= Shift
;
437 // We should not remove required spaces unless we break the line before.
438 assert(Shift
>= 0 || Changes
[i
].NewlinesBefore
> 0 ||
440 static_cast<int>(Changes
[i
].Tok
->SpacesRequiredBefore
) ||
441 Changes
[i
].Tok
->is(tok::eof
));
443 Changes
[i
].StartOfTokenColumn
+= Shift
;
444 if (i
+ 1 != Changes
.size())
445 Changes
[i
+ 1].PreviousEndOfTokenColumn
+= Shift
;
447 // If PointerAlignment is PAS_Right, keep *s or &s next to the token
448 if (Style
.PointerAlignment
== FormatStyle::PAS_Right
&&
449 Changes
[i
].Spaces
!= 0) {
450 for (int Previous
= i
- 1;
452 Changes
[Previous
].Tok
->getType() == TT_PointerOrReference
;
454 Changes
[Previous
+ 1].Spaces
-= Shift
;
455 Changes
[Previous
].Spaces
+= Shift
;
456 Changes
[Previous
].StartOfTokenColumn
+= Shift
;
462 // Walk through a subset of the changes, starting at StartAt, and find
463 // sequences of matching tokens to align. To do so, keep track of the lines and
464 // whether or not a matching token was found on a line. If a matching token is
465 // found, extend the current sequence. If the current line cannot be part of a
466 // sequence, e.g. because there is an empty line before it or it contains only
467 // non-matching tokens, finalize the previous sequence.
468 // The value returned is the token on which we stopped, either because we
469 // exhausted all items inside Changes, or because we hit a scope level higher
470 // than our initial scope.
471 // This function is recursive. Each invocation processes only the scope level
472 // equal to the initial level, which is the level of Changes[StartAt].
473 // If we encounter a scope level greater than the initial level, then we call
474 // ourselves recursively, thereby avoiding the pollution of the current state
475 // with the alignment requirements of the nested sub-level. This recursive
476 // behavior is necessary for aligning function prototypes that have one or more
478 // If this function encounters a scope level less than the initial level,
479 // it returns the current position.
480 // There is a non-obvious subtlety in the recursive behavior: Even though we
481 // defer processing of nested levels to recursive invocations of this
482 // function, when it comes time to align a sequence of tokens, we run the
483 // alignment on the entire sequence, including the nested levels.
484 // When doing so, most of the nested tokens are skipped, because their
485 // alignment was already handled by the recursive invocations of this function.
486 // However, the special exception is that we do NOT skip function parameters
487 // that are split across multiple lines. See the test case in FormatTest.cpp
488 // that mentions "split function parameter alignment" for an example of this.
489 // When the parameter RightJustify is true, the operator will be
490 // right-justified. It is used to align compound assignments like `+=` and `=`.
491 // When RightJustify and ACS.PadOperators are true, operators in each block to
492 // be aligned will be padded on the left to the same length before aligning.
493 template <typename F
>
494 static unsigned AlignTokens(const FormatStyle
&Style
, F
&&Matches
,
495 SmallVector
<WhitespaceManager::Change
, 16> &Changes
,
497 const FormatStyle::AlignConsecutiveStyle
&ACS
= {},
498 bool RightJustify
= false) {
499 // We arrange each line in 3 parts. The operator to be aligned (the anchor),
500 // and text to its left and right. In the aligned text the width of each part
501 // will be the maximum of that over the block that has been aligned. Maximum
502 // widths of each part so far. When RightJustify is true and ACS.PadOperators
503 // is false, the part from start of line to the right end of the anchor.
504 // Otherwise, only the part to the left of the anchor. Including the space
505 // that exists on its left from the start. Not including the padding added on
506 // the left to right-justify the anchor.
507 unsigned WidthLeft
= 0;
508 // The operator to be aligned when RightJustify is true and ACS.PadOperators
509 // is false. 0 otherwise.
510 unsigned WidthAnchor
= 0;
511 // Width to the right of the anchor. Plus width of the anchor when
512 // RightJustify is false.
513 unsigned WidthRight
= 0;
515 // Line number of the start and the end of the current token sequence.
516 unsigned StartOfSequence
= 0;
517 unsigned EndOfSequence
= 0;
519 // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
520 // abort when we hit any token in a higher scope than the starting one.
521 auto IndentAndNestingLevel
= StartAt
< Changes
.size()
522 ? Changes
[StartAt
].indentAndNestingLevel()
523 : std::tuple
<unsigned, unsigned, unsigned>();
525 // Keep track of the number of commas before the matching tokens, we will only
526 // align a sequence of matching tokens if they are preceded by the same number
528 unsigned CommasBeforeLastMatch
= 0;
529 unsigned CommasBeforeMatch
= 0;
531 // Whether a matching token has been found on the current line.
532 bool FoundMatchOnLine
= false;
534 // Whether the current line consists purely of comments.
535 bool LineIsComment
= true;
537 // Aligns a sequence of matching tokens, on the MinColumn column.
539 // Sequences start from the first matching token to align, and end at the
540 // first token of the first line that doesn't need to be aligned.
542 // We need to adjust the StartOfTokenColumn of each Change that is on a line
543 // containing any matching token to be aligned and located after such token.
544 auto AlignCurrentSequence
= [&] {
545 if (StartOfSequence
> 0 && StartOfSequence
< EndOfSequence
) {
546 AlignTokenSequence(Style
, StartOfSequence
, EndOfSequence
,
547 WidthLeft
+ WidthAnchor
, RightJustify
, Matches
,
557 unsigned i
= StartAt
;
558 for (unsigned e
= Changes
.size(); i
!= e
; ++i
) {
559 if (Changes
[i
].indentAndNestingLevel() < IndentAndNestingLevel
)
562 if (Changes
[i
].NewlinesBefore
!= 0) {
563 CommasBeforeMatch
= 0;
566 // Whether to break the alignment sequence because of an empty line.
567 bool EmptyLineBreak
=
568 (Changes
[i
].NewlinesBefore
> 1) && !ACS
.AcrossEmptyLines
;
570 // Whether to break the alignment sequence because of a line without a
573 !FoundMatchOnLine
&& !(LineIsComment
&& ACS
.AcrossComments
);
575 if (EmptyLineBreak
|| NoMatchBreak
)
576 AlignCurrentSequence();
578 // A new line starts, re-initialize line status tracking bools.
579 // Keep the match state if a string literal is continued on this line.
580 if (i
== 0 || !Changes
[i
].Tok
->is(tok::string_literal
) ||
581 !Changes
[i
- 1].Tok
->is(tok::string_literal
)) {
582 FoundMatchOnLine
= false;
584 LineIsComment
= true;
587 if (!Changes
[i
].Tok
->is(tok::comment
))
588 LineIsComment
= false;
590 if (Changes
[i
].Tok
->is(tok::comma
)) {
592 } else if (Changes
[i
].indentAndNestingLevel() > IndentAndNestingLevel
) {
593 // Call AlignTokens recursively, skipping over this scope block.
594 unsigned StoppedAt
= AlignTokens(Style
, Matches
, Changes
, i
, ACS
);
599 if (!Matches(Changes
[i
]))
602 // If there is more than one matching token per line, or if the number of
603 // preceding commas, do not match anymore, end the sequence.
604 if (FoundMatchOnLine
|| CommasBeforeMatch
!= CommasBeforeLastMatch
)
605 AlignCurrentSequence();
607 CommasBeforeLastMatch
= CommasBeforeMatch
;
608 FoundMatchOnLine
= true;
610 if (StartOfSequence
== 0)
613 unsigned ChangeWidthLeft
= Changes
[i
].StartOfTokenColumn
;
614 unsigned ChangeWidthAnchor
= 0;
615 unsigned ChangeWidthRight
= 0;
617 if (ACS
.PadOperators
)
618 ChangeWidthAnchor
= Changes
[i
].TokenLength
;
620 ChangeWidthLeft
+= Changes
[i
].TokenLength
;
622 ChangeWidthRight
= Changes
[i
].TokenLength
;
623 for (unsigned j
= i
+ 1; j
!= e
&& Changes
[j
].NewlinesBefore
== 0; ++j
) {
624 ChangeWidthRight
+= Changes
[j
].Spaces
;
625 // Changes are generally 1:1 with the tokens, but a change could also be
626 // inside of a token, in which case it's counted more than once: once for
627 // the whitespace surrounding the token (!IsInsideToken) and once for
628 // each whitespace change within it (IsInsideToken).
629 // Therefore, changes inside of a token should only count the space.
630 if (!Changes
[j
].IsInsideToken
)
631 ChangeWidthRight
+= Changes
[j
].TokenLength
;
634 // If we are restricted by the maximum column width, end the sequence.
635 unsigned NewLeft
= std::max(ChangeWidthLeft
, WidthLeft
);
636 unsigned NewAnchor
= std::max(ChangeWidthAnchor
, WidthAnchor
);
637 unsigned NewRight
= std::max(ChangeWidthRight
, WidthRight
);
638 // `ColumnLimit == 0` means there is no column limit.
639 if (Style
.ColumnLimit
!= 0 &&
640 Style
.ColumnLimit
< NewLeft
+ NewAnchor
+ NewRight
) {
641 AlignCurrentSequence();
643 WidthLeft
= ChangeWidthLeft
;
644 WidthAnchor
= ChangeWidthAnchor
;
645 WidthRight
= ChangeWidthRight
;
648 WidthAnchor
= NewAnchor
;
649 WidthRight
= NewRight
;
654 AlignCurrentSequence();
658 // Aligns a sequence of matching tokens, on the MinColumn column.
660 // Sequences start from the first matching token to align, and end at the
661 // first token of the first line that doesn't need to be aligned.
663 // We need to adjust the StartOfTokenColumn of each Change that is on a line
664 // containing any matching token to be aligned and located after such token.
665 static void AlignMacroSequence(
666 unsigned &StartOfSequence
, unsigned &EndOfSequence
, unsigned &MinColumn
,
667 unsigned &MaxColumn
, bool &FoundMatchOnLine
,
668 std::function
<bool(const WhitespaceManager::Change
&C
)> AlignMacrosMatches
,
669 SmallVector
<WhitespaceManager::Change
, 16> &Changes
) {
670 if (StartOfSequence
> 0 && StartOfSequence
< EndOfSequence
) {
672 FoundMatchOnLine
= false;
675 for (unsigned I
= StartOfSequence
; I
!= EndOfSequence
; ++I
) {
676 if (Changes
[I
].NewlinesBefore
> 0) {
678 FoundMatchOnLine
= false;
681 // If this is the first matching token to be aligned, remember by how many
682 // spaces it has to be shifted, so the rest of the changes on the line are
683 // shifted by the same amount
684 if (!FoundMatchOnLine
&& AlignMacrosMatches(Changes
[I
])) {
685 FoundMatchOnLine
= true;
686 Shift
= MinColumn
- Changes
[I
].StartOfTokenColumn
;
687 Changes
[I
].Spaces
+= Shift
;
691 Changes
[I
].StartOfTokenColumn
+= Shift
;
692 if (I
+ 1 != Changes
.size())
693 Changes
[I
+ 1].PreviousEndOfTokenColumn
+= Shift
;
698 MaxColumn
= UINT_MAX
;
703 void WhitespaceManager::alignConsecutiveMacros() {
704 if (!Style
.AlignConsecutiveMacros
.Enabled
)
707 auto AlignMacrosMatches
= [](const Change
&C
) {
708 const FormatToken
*Current
= C
.Tok
;
709 unsigned SpacesRequiredBefore
= 1;
711 if (Current
->SpacesRequiredBefore
== 0 || !Current
->Previous
)
714 Current
= Current
->Previous
;
716 // If token is a ")", skip over the parameter list, to the
717 // token that precedes the "("
718 if (Current
->is(tok::r_paren
) && Current
->MatchingParen
) {
719 Current
= Current
->MatchingParen
->Previous
;
720 SpacesRequiredBefore
= 0;
723 if (!Current
|| !Current
->is(tok::identifier
))
726 if (!Current
->Previous
|| !Current
->Previous
->is(tok::pp_define
))
729 // For a macro function, 0 spaces are required between the
730 // identifier and the lparen that opens the parameter list.
731 // For a simple macro, 1 space is required between the
732 // identifier and the first token of the defined value.
733 return Current
->Next
->SpacesRequiredBefore
== SpacesRequiredBefore
;
736 unsigned MinColumn
= 0;
737 unsigned MaxColumn
= UINT_MAX
;
739 // Start and end of the token sequence we're processing.
740 unsigned StartOfSequence
= 0;
741 unsigned EndOfSequence
= 0;
743 // Whether a matching token has been found on the current line.
744 bool FoundMatchOnLine
= false;
746 // Whether the current line consists only of comments
747 bool LineIsComment
= true;
750 for (unsigned E
= Changes
.size(); I
!= E
; ++I
) {
751 if (Changes
[I
].NewlinesBefore
!= 0) {
754 // Whether to break the alignment sequence because of an empty line.
755 bool EmptyLineBreak
= (Changes
[I
].NewlinesBefore
> 1) &&
756 !Style
.AlignConsecutiveMacros
.AcrossEmptyLines
;
758 // Whether to break the alignment sequence because of a line without a
762 !(LineIsComment
&& Style
.AlignConsecutiveMacros
.AcrossComments
);
764 if (EmptyLineBreak
|| NoMatchBreak
) {
765 AlignMacroSequence(StartOfSequence
, EndOfSequence
, MinColumn
, MaxColumn
,
766 FoundMatchOnLine
, AlignMacrosMatches
, Changes
);
769 // A new line starts, re-initialize line status tracking bools.
770 FoundMatchOnLine
= false;
771 LineIsComment
= true;
774 if (!Changes
[I
].Tok
->is(tok::comment
))
775 LineIsComment
= false;
777 if (!AlignMacrosMatches(Changes
[I
]))
780 FoundMatchOnLine
= true;
782 if (StartOfSequence
== 0)
785 unsigned ChangeMinColumn
= Changes
[I
].StartOfTokenColumn
;
786 int LineLengthAfter
= -Changes
[I
].Spaces
;
787 for (unsigned j
= I
; j
!= E
&& Changes
[j
].NewlinesBefore
== 0; ++j
)
788 LineLengthAfter
+= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
789 unsigned ChangeMaxColumn
= Style
.ColumnLimit
- LineLengthAfter
;
791 MinColumn
= std::max(MinColumn
, ChangeMinColumn
);
792 MaxColumn
= std::min(MaxColumn
, ChangeMaxColumn
);
796 AlignMacroSequence(StartOfSequence
, EndOfSequence
, MinColumn
, MaxColumn
,
797 FoundMatchOnLine
, AlignMacrosMatches
, Changes
);
800 void WhitespaceManager::alignConsecutiveAssignments() {
801 if (!Style
.AlignConsecutiveAssignments
.Enabled
)
806 [&](const Change
&C
) {
807 // Do not align on equal signs that are first on a line.
808 if (C
.NewlinesBefore
> 0)
811 // Do not align on equal signs that are last on a line.
812 if (&C
!= &Changes
.back() && (&C
+ 1)->NewlinesBefore
> 0)
815 // Do not align operator= overloads.
816 FormatToken
*Previous
= C
.Tok
->getPreviousNonComment();
817 if (Previous
&& Previous
->is(tok::kw_operator
))
820 return Style
.AlignConsecutiveAssignments
.AlignCompound
821 ? C
.Tok
->getPrecedence() == prec::Assignment
822 : C
.Tok
->is(tok::equal
);
824 Changes
, /*StartAt=*/0, Style
.AlignConsecutiveAssignments
,
825 /*RightJustify=*/true);
828 void WhitespaceManager::alignConsecutiveBitFields() {
829 if (!Style
.AlignConsecutiveBitFields
.Enabled
)
834 [&](Change
const &C
) {
835 // Do not align on ':' that is first on a line.
836 if (C
.NewlinesBefore
> 0)
839 // Do not align on ':' that is last on a line.
840 if (&C
!= &Changes
.back() && (&C
+ 1)->NewlinesBefore
> 0)
843 return C
.Tok
->is(TT_BitFieldColon
);
845 Changes
, /*StartAt=*/0, Style
.AlignConsecutiveBitFields
);
848 void WhitespaceManager::alignConsecutiveDeclarations() {
849 if (!Style
.AlignConsecutiveDeclarations
.Enabled
)
854 [](Change
const &C
) {
855 // tok::kw_operator is necessary for aligning operator overload
857 if (C
.Tok
->isOneOf(TT_FunctionDeclarationName
, tok::kw_operator
))
859 if (C
.Tok
->isNot(TT_StartOfName
))
861 if (C
.Tok
->Previous
&&
862 C
.Tok
->Previous
->is(TT_StatementAttributeLikeMacro
))
864 // Check if there is a subsequent name that starts the same declaration.
865 for (FormatToken
*Next
= C
.Tok
->Next
; Next
; Next
= Next
->Next
) {
866 if (Next
->is(tok::comment
))
868 if (Next
->is(TT_PointerOrReference
))
870 if (!Next
->Tok
.getIdentifierInfo())
872 if (Next
->isOneOf(TT_StartOfName
, TT_FunctionDeclarationName
,
879 Changes
, /*StartAt=*/0, Style
.AlignConsecutiveDeclarations
);
882 void WhitespaceManager::alignChainedConditionals() {
883 if (Style
.BreakBeforeTernaryOperators
) {
886 [](Change
const &C
) {
887 // Align question operators and last colon
888 return C
.Tok
->is(TT_ConditionalExpr
) &&
889 ((C
.Tok
->is(tok::question
) && !C
.NewlinesBefore
) ||
890 (C
.Tok
->is(tok::colon
) && C
.Tok
->Next
&&
891 (C
.Tok
->Next
->FakeLParens
.size() == 0 ||
892 C
.Tok
->Next
->FakeLParens
.back() != prec::Conditional
)));
894 Changes
, /*StartAt=*/0);
896 static auto AlignWrappedOperand
= [](Change
const &C
) {
897 FormatToken
*Previous
= C
.Tok
->getPreviousNonComment();
898 return C
.NewlinesBefore
&& Previous
&& Previous
->is(TT_ConditionalExpr
) &&
899 (Previous
->is(tok::colon
) &&
900 (C
.Tok
->FakeLParens
.size() == 0 ||
901 C
.Tok
->FakeLParens
.back() != prec::Conditional
));
903 // Ensure we keep alignment of wrapped operands with non-wrapped operands
904 // Since we actually align the operators, the wrapped operands need the
905 // extra offset to be properly aligned.
906 for (Change
&C
: Changes
)
907 if (AlignWrappedOperand(C
))
908 C
.StartOfTokenColumn
-= 2;
911 [this](Change
const &C
) {
912 // Align question operators if next operand is not wrapped, as
913 // well as wrapped operands after question operator or last
914 // colon in conditional sequence
915 return (C
.Tok
->is(TT_ConditionalExpr
) && C
.Tok
->is(tok::question
) &&
916 &C
!= &Changes
.back() && (&C
+ 1)->NewlinesBefore
== 0 &&
917 !(&C
+ 1)->IsTrailingComment
) ||
918 AlignWrappedOperand(C
);
920 Changes
, /*StartAt=*/0);
924 void WhitespaceManager::alignTrailingComments() {
925 unsigned MinColumn
= 0;
926 unsigned MaxColumn
= UINT_MAX
;
927 unsigned StartOfSequence
= 0;
928 bool BreakBeforeNext
= false;
929 unsigned Newlines
= 0;
930 for (unsigned i
= 0, e
= Changes
.size(); i
!= e
; ++i
) {
931 if (Changes
[i
].StartOfBlockComment
)
933 Newlines
+= Changes
[i
].NewlinesBefore
;
934 if (!Changes
[i
].IsTrailingComment
)
937 unsigned ChangeMinColumn
= Changes
[i
].StartOfTokenColumn
;
938 unsigned ChangeMaxColumn
;
940 if (Style
.ColumnLimit
== 0)
941 ChangeMaxColumn
= UINT_MAX
;
942 else if (Style
.ColumnLimit
>= Changes
[i
].TokenLength
)
943 ChangeMaxColumn
= Style
.ColumnLimit
- Changes
[i
].TokenLength
;
945 ChangeMaxColumn
= ChangeMinColumn
;
947 // If we don't create a replacement for this change, we have to consider
948 // it to be immovable.
949 if (!Changes
[i
].CreateReplacement
)
950 ChangeMaxColumn
= ChangeMinColumn
;
952 if (i
+ 1 != e
&& Changes
[i
+ 1].ContinuesPPDirective
)
953 ChangeMaxColumn
-= 2;
954 // If this comment follows an } in column 0, it probably documents the
955 // closing of a namespace and we don't want to align it.
956 bool FollowsRBraceInColumn0
= i
> 0 && Changes
[i
].NewlinesBefore
== 0 &&
957 Changes
[i
- 1].Tok
->is(tok::r_brace
) &&
958 Changes
[i
- 1].StartOfTokenColumn
== 0;
959 bool WasAlignedWithStartOfNextLine
= false;
960 if (Changes
[i
].NewlinesBefore
== 1) { // A comment on its own line.
961 unsigned CommentColumn
= SourceMgr
.getSpellingColumnNumber(
962 Changes
[i
].OriginalWhitespaceRange
.getEnd());
963 for (unsigned j
= i
+ 1; j
!= e
; ++j
) {
964 if (Changes
[j
].Tok
->is(tok::comment
))
967 unsigned NextColumn
= SourceMgr
.getSpellingColumnNumber(
968 Changes
[j
].OriginalWhitespaceRange
.getEnd());
969 // The start of the next token was previously aligned with the
970 // start of this comment.
971 WasAlignedWithStartOfNextLine
=
972 CommentColumn
== NextColumn
||
973 CommentColumn
== NextColumn
+ Style
.IndentWidth
;
977 if (!Style
.AlignTrailingComments
|| FollowsRBraceInColumn0
) {
978 alignTrailingComments(StartOfSequence
, i
, MinColumn
);
979 MinColumn
= ChangeMinColumn
;
980 MaxColumn
= ChangeMinColumn
;
982 } else if (BreakBeforeNext
|| Newlines
> 1 ||
983 (ChangeMinColumn
> MaxColumn
|| ChangeMaxColumn
< MinColumn
) ||
984 // Break the comment sequence if the previous line did not end
985 // in a trailing comment.
986 (Changes
[i
].NewlinesBefore
== 1 && i
> 0 &&
987 !Changes
[i
- 1].IsTrailingComment
) ||
988 WasAlignedWithStartOfNextLine
) {
989 alignTrailingComments(StartOfSequence
, i
, MinColumn
);
990 MinColumn
= ChangeMinColumn
;
991 MaxColumn
= ChangeMaxColumn
;
994 MinColumn
= std::max(MinColumn
, ChangeMinColumn
);
995 MaxColumn
= std::min(MaxColumn
, ChangeMaxColumn
);
997 BreakBeforeNext
= (i
== 0) || (Changes
[i
].NewlinesBefore
> 1) ||
998 // Never start a sequence with a comment at the beginning
1000 (Changes
[i
].NewlinesBefore
== 1 && StartOfSequence
== i
);
1003 alignTrailingComments(StartOfSequence
, Changes
.size(), MinColumn
);
1006 void WhitespaceManager::alignTrailingComments(unsigned Start
, unsigned End
,
1008 for (unsigned i
= Start
; i
!= End
; ++i
) {
1010 if (Changes
[i
].IsTrailingComment
)
1011 Shift
= Column
- Changes
[i
].StartOfTokenColumn
;
1012 if (Changes
[i
].StartOfBlockComment
) {
1013 Shift
= Changes
[i
].IndentationOffset
+
1014 Changes
[i
].StartOfBlockComment
->StartOfTokenColumn
-
1015 Changes
[i
].StartOfTokenColumn
;
1019 Changes
[i
].Spaces
+= Shift
;
1020 if (i
+ 1 != Changes
.size())
1021 Changes
[i
+ 1].PreviousEndOfTokenColumn
+= Shift
;
1022 Changes
[i
].StartOfTokenColumn
+= Shift
;
1026 void WhitespaceManager::alignEscapedNewlines() {
1027 if (Style
.AlignEscapedNewlines
== FormatStyle::ENAS_DontAlign
)
1030 bool AlignLeft
= Style
.AlignEscapedNewlines
== FormatStyle::ENAS_Left
;
1031 unsigned MaxEndOfLine
= AlignLeft
? 0 : Style
.ColumnLimit
;
1032 unsigned StartOfMacro
= 0;
1033 for (unsigned i
= 1, e
= Changes
.size(); i
< e
; ++i
) {
1034 Change
&C
= Changes
[i
];
1035 if (C
.NewlinesBefore
> 0) {
1036 if (C
.ContinuesPPDirective
) {
1037 MaxEndOfLine
= std::max(C
.PreviousEndOfTokenColumn
+ 2, MaxEndOfLine
);
1039 alignEscapedNewlines(StartOfMacro
+ 1, i
, MaxEndOfLine
);
1040 MaxEndOfLine
= AlignLeft
? 0 : Style
.ColumnLimit
;
1045 alignEscapedNewlines(StartOfMacro
+ 1, Changes
.size(), MaxEndOfLine
);
1048 void WhitespaceManager::alignEscapedNewlines(unsigned Start
, unsigned End
,
1050 for (unsigned i
= Start
; i
< End
; ++i
) {
1051 Change
&C
= Changes
[i
];
1052 if (C
.NewlinesBefore
> 0) {
1053 assert(C
.ContinuesPPDirective
);
1054 if (C
.PreviousEndOfTokenColumn
+ 1 > Column
)
1055 C
.EscapedNewlineColumn
= 0;
1057 C
.EscapedNewlineColumn
= Column
;
1062 void WhitespaceManager::alignArrayInitializers() {
1063 if (Style
.AlignArrayOfStructures
== FormatStyle::AIAS_None
)
1066 for (unsigned ChangeIndex
= 1U, ChangeEnd
= Changes
.size();
1067 ChangeIndex
< ChangeEnd
; ++ChangeIndex
) {
1068 auto &C
= Changes
[ChangeIndex
];
1069 if (C
.Tok
->IsArrayInitializer
) {
1070 bool FoundComplete
= false;
1071 for (unsigned InsideIndex
= ChangeIndex
+ 1; InsideIndex
< ChangeEnd
;
1073 if (Changes
[InsideIndex
].Tok
== C
.Tok
->MatchingParen
) {
1074 alignArrayInitializers(ChangeIndex
, InsideIndex
+ 1);
1075 ChangeIndex
= InsideIndex
+ 1;
1076 FoundComplete
= true;
1081 ChangeIndex
= ChangeEnd
;
1086 void WhitespaceManager::alignArrayInitializers(unsigned Start
, unsigned End
) {
1088 if (Style
.AlignArrayOfStructures
== FormatStyle::AIAS_Right
)
1089 alignArrayInitializersRightJustified(getCells(Start
, End
));
1090 else if (Style
.AlignArrayOfStructures
== FormatStyle::AIAS_Left
)
1091 alignArrayInitializersLeftJustified(getCells(Start
, End
));
1094 void WhitespaceManager::alignArrayInitializersRightJustified(
1095 CellDescriptions
&&CellDescs
) {
1096 if (!CellDescs
.isRectangular())
1099 auto &Cells
= CellDescs
.Cells
;
1100 // Now go through and fixup the spaces.
1101 auto *CellIter
= Cells
.begin();
1102 for (auto i
= 0U; i
< CellDescs
.CellCounts
[0]; ++i
, ++CellIter
) {
1103 unsigned NetWidth
= 0U;
1104 if (isSplitCell(*CellIter
))
1105 NetWidth
= getNetWidth(Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
);
1106 auto CellWidth
= getMaximumCellWidth(CellIter
, NetWidth
);
1108 if (Changes
[CellIter
->Index
].Tok
->is(tok::r_brace
)) {
1109 // So in here we want to see if there is a brace that falls
1110 // on a line that was split. If so on that line we make sure that
1111 // the spaces in front of the brace are enough.
1112 const auto *Next
= CellIter
;
1114 const FormatToken
*Previous
= Changes
[Next
->Index
].Tok
->Previous
;
1115 if (Previous
&& Previous
->isNot(TT_LineComment
)) {
1116 Changes
[Next
->Index
].Spaces
= 0;
1117 Changes
[Next
->Index
].NewlinesBefore
= 0;
1119 Next
= Next
->NextColumnElement
;
1121 // Unless the array is empty, we need the position of all the
1122 // immediately adjacent cells
1123 if (CellIter
!= Cells
.begin()) {
1125 getNetWidth(Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
);
1126 auto MaxNetWidth
= getMaximumNetWidth(
1127 Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
,
1128 CellDescs
.CellCounts
[0], CellDescs
.CellCounts
.size());
1129 if (ThisNetWidth
< MaxNetWidth
)
1130 Changes
[CellIter
->Index
].Spaces
= (MaxNetWidth
- ThisNetWidth
);
1132 auto Offset
= std::distance(Cells
.begin(), CellIter
);
1133 for (const auto *Next
= CellIter
->NextColumnElement
; Next
!= nullptr;
1134 Next
= Next
->NextColumnElement
) {
1135 auto *Start
= (Cells
.begin() + RowCount
* CellDescs
.CellCounts
[0]);
1136 auto *End
= Start
+ Offset
;
1137 ThisNetWidth
= getNetWidth(Start
, End
, CellDescs
.InitialSpaces
);
1138 if (ThisNetWidth
< MaxNetWidth
)
1139 Changes
[Next
->Index
].Spaces
= (MaxNetWidth
- ThisNetWidth
);
1145 calculateCellWidth(CellIter
->Index
, CellIter
->EndIndex
, true) +
1147 if (Changes
[CellIter
->Index
].NewlinesBefore
== 0) {
1148 Changes
[CellIter
->Index
].Spaces
= (CellWidth
- (ThisWidth
+ NetWidth
));
1149 Changes
[CellIter
->Index
].Spaces
+= (i
> 0) ? 1 : 0;
1151 alignToStartOfCell(CellIter
->Index
, CellIter
->EndIndex
);
1152 for (const auto *Next
= CellIter
->NextColumnElement
; Next
!= nullptr;
1153 Next
= Next
->NextColumnElement
) {
1155 calculateCellWidth(Next
->Index
, Next
->EndIndex
, true) + NetWidth
;
1156 if (Changes
[Next
->Index
].NewlinesBefore
== 0) {
1157 Changes
[Next
->Index
].Spaces
= (CellWidth
- ThisWidth
);
1158 Changes
[Next
->Index
].Spaces
+= (i
> 0) ? 1 : 0;
1160 alignToStartOfCell(Next
->Index
, Next
->EndIndex
);
1166 void WhitespaceManager::alignArrayInitializersLeftJustified(
1167 CellDescriptions
&&CellDescs
) {
1169 if (!CellDescs
.isRectangular())
1172 auto &Cells
= CellDescs
.Cells
;
1173 // Now go through and fixup the spaces.
1174 auto *CellIter
= Cells
.begin();
1175 // The first cell needs to be against the left brace.
1176 if (Changes
[CellIter
->Index
].NewlinesBefore
== 0)
1177 Changes
[CellIter
->Index
].Spaces
= 0;
1179 Changes
[CellIter
->Index
].Spaces
= CellDescs
.InitialSpaces
;
1181 for (auto i
= 1U; i
< CellDescs
.CellCounts
[0]; i
++, ++CellIter
) {
1182 auto MaxNetWidth
= getMaximumNetWidth(
1183 Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
,
1184 CellDescs
.CellCounts
[0], CellDescs
.CellCounts
.size());
1186 getNetWidth(Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
);
1187 if (Changes
[CellIter
->Index
].NewlinesBefore
== 0) {
1188 Changes
[CellIter
->Index
].Spaces
=
1189 MaxNetWidth
- ThisNetWidth
+
1190 (Changes
[CellIter
->Index
].Tok
->isNot(tok::r_brace
) ? 1 : 0);
1193 auto Offset
= std::distance(Cells
.begin(), CellIter
);
1194 for (const auto *Next
= CellIter
->NextColumnElement
; Next
!= nullptr;
1195 Next
= Next
->NextColumnElement
) {
1196 if (RowCount
> CellDescs
.CellCounts
.size())
1198 auto *Start
= (Cells
.begin() + RowCount
* CellDescs
.CellCounts
[0]);
1199 auto *End
= Start
+ Offset
;
1200 auto ThisNetWidth
= getNetWidth(Start
, End
, CellDescs
.InitialSpaces
);
1201 if (Changes
[Next
->Index
].NewlinesBefore
== 0) {
1202 Changes
[Next
->Index
].Spaces
=
1203 MaxNetWidth
- ThisNetWidth
+
1204 (Changes
[Next
->Index
].Tok
->isNot(tok::r_brace
) ? 1 : 0);
1211 bool WhitespaceManager::isSplitCell(const CellDescription
&Cell
) {
1214 for (const auto *Next
= Cell
.NextColumnElement
; Next
!= nullptr;
1215 Next
= Next
->NextColumnElement
) {
1222 WhitespaceManager::CellDescriptions
WhitespaceManager::getCells(unsigned Start
,
1227 SmallVector
<unsigned> CellCounts
;
1228 unsigned InitialSpaces
= 0;
1229 unsigned InitialTokenLength
= 0;
1230 unsigned EndSpaces
= 0;
1231 SmallVector
<CellDescription
> Cells
;
1232 const FormatToken
*MatchingParen
= nullptr;
1233 for (unsigned i
= Start
; i
< End
; ++i
) {
1234 auto &C
= Changes
[i
];
1235 if (C
.Tok
->is(tok::l_brace
))
1237 else if (C
.Tok
->is(tok::r_brace
))
1240 if (C
.Tok
->is(tok::l_brace
)) {
1242 MatchingParen
= C
.Tok
->MatchingParen
;
1243 if (InitialSpaces
== 0) {
1244 InitialSpaces
= C
.Spaces
+ C
.TokenLength
;
1245 InitialTokenLength
= C
.TokenLength
;
1247 for (; Changes
[j
].NewlinesBefore
== 0 && j
> Start
; --j
) {
1248 InitialSpaces
+= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
1249 InitialTokenLength
+= Changes
[j
].TokenLength
;
1251 if (C
.NewlinesBefore
== 0) {
1252 InitialSpaces
+= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
1253 InitialTokenLength
+= Changes
[j
].TokenLength
;
1256 } else if (C
.Tok
->is(tok::comma
)) {
1258 Cells
.back().EndIndex
= i
;
1259 if (C
.Tok
->getNextNonComment()->isNot(tok::r_brace
)) // dangling comma
1262 } else if (Depth
== 1) {
1263 if (C
.Tok
== MatchingParen
) {
1265 Cells
.back().EndIndex
= i
;
1266 Cells
.push_back(CellDescription
{i
, ++Cell
, i
+ 1, false, nullptr});
1267 CellCounts
.push_back(C
.Tok
->Previous
->isNot(tok::comma
) ? Cell
+ 1
1269 // Go to the next non-comment and ensure there is a break in front
1270 const auto *NextNonComment
= C
.Tok
->getNextNonComment();
1271 while (NextNonComment
->is(tok::comma
))
1272 NextNonComment
= NextNonComment
->getNextNonComment();
1274 while (Changes
[j
].Tok
!= NextNonComment
&& j
< End
)
1276 if (j
< End
&& Changes
[j
].NewlinesBefore
== 0 &&
1277 Changes
[j
].Tok
->isNot(tok::r_brace
)) {
1278 Changes
[j
].NewlinesBefore
= 1;
1279 // Account for the added token lengths
1280 Changes
[j
].Spaces
= InitialSpaces
- InitialTokenLength
;
1282 } else if (C
.Tok
->is(tok::comment
)) {
1283 // Trailing comments stay at a space past the last token
1284 C
.Spaces
= Changes
[i
- 1].Tok
->is(tok::comma
) ? 1 : 2;
1285 } else if (C
.Tok
->is(tok::l_brace
)) {
1286 // We need to make sure that the ending braces is aligned to the
1287 // start of our initializer
1289 for (; j
> 0 && !Changes
[j
].Tok
->ArrayInitializerLineStart
; --j
)
1290 ; // Nothing the loop does the work
1291 EndSpaces
= Changes
[j
].Spaces
;
1293 } else if (Depth
== 0 && C
.Tok
->is(tok::r_brace
)) {
1294 C
.NewlinesBefore
= 1;
1295 C
.Spaces
= EndSpaces
;
1297 if (C
.Tok
->StartsColumn
) {
1298 // This gets us past tokens that have been split over multiple
1300 bool HasSplit
= false;
1301 if (Changes
[i
].NewlinesBefore
> 0) {
1302 // So if we split a line previously and the tail line + this token is
1303 // less then the column limit we remove the split here and just put
1304 // the column start at a space past the comma
1306 // FIXME This if branch covers the cases where the column is not
1307 // the first column. This leads to weird pathologies like the formatting
1308 // auto foo = Items{
1313 // Well if it doesn't lead to that it's indicative that the line
1314 // breaking should be revisited. Unfortunately alot of other options
1315 // interact with this
1317 if ((j
- 1) > Start
&& Changes
[j
].Tok
->is(tok::comma
) &&
1318 Changes
[j
- 1].NewlinesBefore
> 0) {
1320 auto LineLimit
= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
1321 if (LineLimit
< Style
.ColumnLimit
) {
1322 Changes
[i
].NewlinesBefore
= 0;
1323 Changes
[i
].Spaces
= 1;
1327 while (Changes
[i
].NewlinesBefore
> 0 && Changes
[i
].Tok
== C
.Tok
) {
1328 Changes
[i
].Spaces
= InitialSpaces
;
1332 if (Changes
[i
].Tok
!= C
.Tok
)
1334 Cells
.push_back(CellDescription
{i
, Cell
, i
, HasSplit
, nullptr});
1338 return linkCells({Cells
, CellCounts
, InitialSpaces
});
1341 unsigned WhitespaceManager::calculateCellWidth(unsigned Start
, unsigned End
,
1342 bool WithSpaces
) const {
1343 unsigned CellWidth
= 0;
1344 for (auto i
= Start
; i
< End
; i
++) {
1345 if (Changes
[i
].NewlinesBefore
> 0)
1347 CellWidth
+= Changes
[i
].TokenLength
;
1348 CellWidth
+= (WithSpaces
? Changes
[i
].Spaces
: 0);
1353 void WhitespaceManager::alignToStartOfCell(unsigned Start
, unsigned End
) {
1354 if ((End
- Start
) <= 1)
1356 // If the line is broken anywhere in there make sure everything
1357 // is aligned to the parent
1358 for (auto i
= Start
+ 1; i
< End
; i
++)
1359 if (Changes
[i
].NewlinesBefore
> 0)
1360 Changes
[i
].Spaces
= Changes
[Start
].Spaces
;
1363 WhitespaceManager::CellDescriptions
1364 WhitespaceManager::linkCells(CellDescriptions
&&CellDesc
) {
1365 auto &Cells
= CellDesc
.Cells
;
1366 for (auto *CellIter
= Cells
.begin(); CellIter
!= Cells
.end(); ++CellIter
) {
1367 if (CellIter
->NextColumnElement
== nullptr &&
1368 ((CellIter
+ 1) != Cells
.end())) {
1369 for (auto *NextIter
= CellIter
+ 1; NextIter
!= Cells
.end(); ++NextIter
) {
1370 if (NextIter
->Cell
== CellIter
->Cell
) {
1371 CellIter
->NextColumnElement
= &(*NextIter
);
1377 return std::move(CellDesc
);
1380 void WhitespaceManager::generateChanges() {
1381 for (unsigned i
= 0, e
= Changes
.size(); i
!= e
; ++i
) {
1382 const Change
&C
= Changes
[i
];
1383 if (i
> 0 && Changes
[i
- 1].OriginalWhitespaceRange
.getBegin() ==
1384 C
.OriginalWhitespaceRange
.getBegin()) {
1385 // Do not generate two replacements for the same location.
1388 if (C
.CreateReplacement
) {
1389 std::string ReplacementText
= C
.PreviousLinePostfix
;
1390 if (C
.ContinuesPPDirective
) {
1391 appendEscapedNewlineText(ReplacementText
, C
.NewlinesBefore
,
1392 C
.PreviousEndOfTokenColumn
,
1393 C
.EscapedNewlineColumn
);
1395 appendNewlineText(ReplacementText
, C
.NewlinesBefore
);
1397 // FIXME: This assert should hold if we computed the column correctly.
1398 // assert((int)C.StartOfTokenColumn >= C.Spaces);
1400 ReplacementText
, C
.Tok
->IndentLevel
, std::max(0, C
.Spaces
),
1401 std::max((int)C
.StartOfTokenColumn
, C
.Spaces
) - std::max(0, C
.Spaces
),
1403 ReplacementText
.append(C
.CurrentLinePrefix
);
1404 storeReplacement(C
.OriginalWhitespaceRange
, ReplacementText
);
1409 void WhitespaceManager::storeReplacement(SourceRange Range
, StringRef Text
) {
1410 unsigned WhitespaceLength
= SourceMgr
.getFileOffset(Range
.getEnd()) -
1411 SourceMgr
.getFileOffset(Range
.getBegin());
1412 // Don't create a replacement, if it does not change anything.
1413 if (StringRef(SourceMgr
.getCharacterData(Range
.getBegin()),
1414 WhitespaceLength
) == Text
) {
1417 auto Err
= Replaces
.add(tooling::Replacement(
1418 SourceMgr
, CharSourceRange::getCharRange(Range
), Text
));
1419 // FIXME: better error handling. For now, just print an error message in the
1422 llvm::errs() << llvm::toString(std::move(Err
)) << "\n";
1427 void WhitespaceManager::appendNewlineText(std::string
&Text
,
1428 unsigned Newlines
) {
1430 Text
.reserve(Text
.size() + 2 * Newlines
);
1431 for (unsigned i
= 0; i
< Newlines
; ++i
)
1432 Text
.append("\r\n");
1434 Text
.append(Newlines
, '\n');
1438 void WhitespaceManager::appendEscapedNewlineText(
1439 std::string
&Text
, unsigned Newlines
, unsigned PreviousEndOfTokenColumn
,
1440 unsigned EscapedNewlineColumn
) {
1443 std::max
<int>(1, EscapedNewlineColumn
- PreviousEndOfTokenColumn
- 1);
1444 for (unsigned i
= 0; i
< Newlines
; ++i
) {
1445 Text
.append(Spaces
, ' ');
1446 Text
.append(UseCRLF
? "\\\r\n" : "\\\n");
1447 Spaces
= std::max
<int>(0, EscapedNewlineColumn
- 1);
1452 void WhitespaceManager::appendIndentText(std::string
&Text
,
1453 unsigned IndentLevel
, unsigned Spaces
,
1454 unsigned WhitespaceStartColumn
,
1456 switch (Style
.UseTab
) {
1457 case FormatStyle::UT_Never
:
1458 Text
.append(Spaces
, ' ');
1460 case FormatStyle::UT_Always
: {
1461 if (Style
.TabWidth
) {
1462 unsigned FirstTabWidth
=
1463 Style
.TabWidth
- WhitespaceStartColumn
% Style
.TabWidth
;
1465 // Insert only spaces when we want to end up before the next tab.
1466 if (Spaces
< FirstTabWidth
|| Spaces
== 1) {
1467 Text
.append(Spaces
, ' ');
1470 // Align to the next tab.
1471 Spaces
-= FirstTabWidth
;
1474 Text
.append(Spaces
/ Style
.TabWidth
, '\t');
1475 Text
.append(Spaces
% Style
.TabWidth
, ' ');
1476 } else if (Spaces
== 1) {
1477 Text
.append(Spaces
, ' ');
1481 case FormatStyle::UT_ForIndentation
:
1482 if (WhitespaceStartColumn
== 0) {
1483 unsigned Indentation
= IndentLevel
* Style
.IndentWidth
;
1484 Spaces
= appendTabIndent(Text
, Spaces
, Indentation
);
1486 Text
.append(Spaces
, ' ');
1488 case FormatStyle::UT_ForContinuationAndIndentation
:
1489 if (WhitespaceStartColumn
== 0)
1490 Spaces
= appendTabIndent(Text
, Spaces
, Spaces
);
1491 Text
.append(Spaces
, ' ');
1493 case FormatStyle::UT_AlignWithSpaces
:
1494 if (WhitespaceStartColumn
== 0) {
1495 unsigned Indentation
=
1496 IsAligned
? IndentLevel
* Style
.IndentWidth
: Spaces
;
1497 Spaces
= appendTabIndent(Text
, Spaces
, Indentation
);
1499 Text
.append(Spaces
, ' ');
1504 unsigned WhitespaceManager::appendTabIndent(std::string
&Text
, unsigned Spaces
,
1505 unsigned Indentation
) {
1506 // This happens, e.g. when a line in a block comment is indented less than the
1508 if (Indentation
> Spaces
)
1509 Indentation
= Spaces
;
1510 if (Style
.TabWidth
) {
1511 unsigned Tabs
= Indentation
/ Style
.TabWidth
;
1512 Text
.append(Tabs
, '\t');
1513 Spaces
-= Tabs
* Style
.TabWidth
;
1518 } // namespace format
1519 } // namespace clang