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
) {
52 auto PPBranchDirectiveStartsLine
= [&Tok
] {
53 return Tok
.is(tok::hash
) && !Tok
.Previous
&& Tok
.Next
&&
54 Tok
.Next
->isOneOf(tok::pp_if
, tok::pp_ifdef
, tok::pp_ifndef
,
55 tok::pp_elif
, tok::pp_elifdef
, tok::pp_elifndef
,
56 tok::pp_else
, tok::pp_endif
);
58 if ((Tok
.Finalized
&& !PPBranchDirectiveStartsLine()) ||
59 (Tok
.MacroCtx
&& Tok
.MacroCtx
->Role
== MR_ExpandedArg
)) {
62 Tok
.setDecision((Newlines
> 0) ? FD_Break
: FD_Continue
);
63 Changes
.push_back(Change(Tok
, /*CreateReplacement=*/true, Tok
.WhitespaceRange
,
64 Spaces
, StartOfTokenColumn
, Newlines
, "", "",
65 IsAligned
, InPPDirective
&& !Tok
.IsFirst
,
66 /*IsInsideToken=*/false));
69 void WhitespaceManager::addUntouchableToken(const FormatToken
&Tok
,
71 if (Tok
.Finalized
|| (Tok
.MacroCtx
&& Tok
.MacroCtx
->Role
== MR_ExpandedArg
))
73 Changes
.push_back(Change(Tok
, /*CreateReplacement=*/false,
74 Tok
.WhitespaceRange
, /*Spaces=*/0,
75 Tok
.OriginalColumn
, Tok
.NewlinesBefore
, "", "",
76 /*IsAligned=*/false, InPPDirective
&& !Tok
.IsFirst
,
77 /*IsInsideToken=*/false));
81 WhitespaceManager::addReplacement(const tooling::Replacement
&Replacement
) {
82 return Replaces
.add(Replacement
);
85 bool WhitespaceManager::inputUsesCRLF(StringRef Text
, bool DefaultToCRLF
) {
86 size_t LF
= Text
.count('\n');
87 size_t CR
= Text
.count('\r') * 2;
88 return LF
== CR
? DefaultToCRLF
: CR
> LF
;
91 void WhitespaceManager::replaceWhitespaceInToken(
92 const FormatToken
&Tok
, unsigned Offset
, unsigned ReplaceChars
,
93 StringRef PreviousPostfix
, StringRef CurrentPrefix
, bool InPPDirective
,
94 unsigned Newlines
, int Spaces
) {
95 if (Tok
.Finalized
|| (Tok
.MacroCtx
&& Tok
.MacroCtx
->Role
== MR_ExpandedArg
))
97 SourceLocation Start
= Tok
.getStartOfNonWhitespace().getLocWithOffset(Offset
);
99 Change(Tok
, /*CreateReplacement=*/true,
100 SourceRange(Start
, Start
.getLocWithOffset(ReplaceChars
)), Spaces
,
101 std::max(0, Spaces
), Newlines
, PreviousPostfix
, CurrentPrefix
,
102 /*IsAligned=*/true, InPPDirective
&& !Tok
.IsFirst
,
103 /*IsInsideToken=*/true));
106 const tooling::Replacements
&WhitespaceManager::generateReplacements() {
110 llvm::sort(Changes
, Change::IsBeforeInFile(SourceMgr
));
111 calculateLineBreakInformation();
112 alignConsecutiveMacros();
113 alignConsecutiveDeclarations();
114 alignConsecutiveBitFields();
115 alignConsecutiveAssignments();
116 alignChainedConditionals();
117 alignTrailingComments();
118 alignEscapedNewlines();
119 alignArrayInitializers();
125 void WhitespaceManager::calculateLineBreakInformation() {
126 Changes
[0].PreviousEndOfTokenColumn
= 0;
127 Change
*LastOutsideTokenChange
= &Changes
[0];
128 for (unsigned i
= 1, e
= Changes
.size(); i
!= e
; ++i
) {
129 SourceLocation OriginalWhitespaceStart
=
130 Changes
[i
].OriginalWhitespaceRange
.getBegin();
131 SourceLocation PreviousOriginalWhitespaceEnd
=
132 Changes
[i
- 1].OriginalWhitespaceRange
.getEnd();
133 unsigned OriginalWhitespaceStartOffset
=
134 SourceMgr
.getFileOffset(OriginalWhitespaceStart
);
135 unsigned PreviousOriginalWhitespaceEndOffset
=
136 SourceMgr
.getFileOffset(PreviousOriginalWhitespaceEnd
);
137 assert(PreviousOriginalWhitespaceEndOffset
<=
138 OriginalWhitespaceStartOffset
);
139 const char *const PreviousOriginalWhitespaceEndData
=
140 SourceMgr
.getCharacterData(PreviousOriginalWhitespaceEnd
);
141 StringRef
Text(PreviousOriginalWhitespaceEndData
,
142 SourceMgr
.getCharacterData(OriginalWhitespaceStart
) -
143 PreviousOriginalWhitespaceEndData
);
144 // Usually consecutive changes would occur in consecutive tokens. This is
145 // not the case however when analyzing some preprocessor runs of the
146 // annotated lines. For example, in this code:
154 // one of the runs will produce the sequence of lines marked with line 1, 2
155 // and 3. So the two consecutive whitespace changes just before '// line 2'
156 // and before '#endif // line 3' span multiple lines and tokens:
158 // #else B{change X}[// line 2
160 // ]{change Y}#endif // line 3
162 // For this reason, if the text between consecutive changes spans multiple
163 // newlines, the token length must be adjusted to the end of the original
164 // line of the token.
165 auto NewlinePos
= Text
.find_first_of('\n');
166 if (NewlinePos
== StringRef::npos
) {
167 Changes
[i
- 1].TokenLength
= OriginalWhitespaceStartOffset
-
168 PreviousOriginalWhitespaceEndOffset
+
169 Changes
[i
].PreviousLinePostfix
.size() +
170 Changes
[i
- 1].CurrentLinePrefix
.size();
172 Changes
[i
- 1].TokenLength
=
173 NewlinePos
+ Changes
[i
- 1].CurrentLinePrefix
.size();
176 // If there are multiple changes in this token, sum up all the changes until
177 // the end of the line.
178 if (Changes
[i
- 1].IsInsideToken
&& Changes
[i
- 1].NewlinesBefore
== 0) {
179 LastOutsideTokenChange
->TokenLength
+=
180 Changes
[i
- 1].TokenLength
+ Changes
[i
- 1].Spaces
;
182 LastOutsideTokenChange
= &Changes
[i
- 1];
185 Changes
[i
].PreviousEndOfTokenColumn
=
186 Changes
[i
- 1].StartOfTokenColumn
+ Changes
[i
- 1].TokenLength
;
188 Changes
[i
- 1].IsTrailingComment
=
189 (Changes
[i
].NewlinesBefore
> 0 || Changes
[i
].Tok
->is(tok::eof
) ||
190 (Changes
[i
].IsInsideToken
&& Changes
[i
].Tok
->is(tok::comment
))) &&
191 Changes
[i
- 1].Tok
->is(tok::comment
) &&
192 // FIXME: This is a dirty hack. The problem is that
193 // BreakableLineCommentSection does comment reflow changes and here is
194 // the aligning of trailing comments. Consider the case where we reflow
195 // the second line up in this example:
200 // That amounts to 2 changes by BreakableLineCommentSection:
201 // - the first, delimited by (), for the whitespace between the tokens,
202 // - and second, delimited by [], for the whitespace at the beginning
203 // of the second token:
208 // So in the end we have two changes like this:
210 // // line1()[ ]line 2
212 // Note that the OriginalWhitespaceStart of the second change is the
213 // same as the PreviousOriginalWhitespaceEnd of the first change.
214 // In this case, the below check ensures that the second change doesn't
215 // get treated as a trailing comment change here, since this might
216 // trigger additional whitespace to be wrongly inserted before "line 2"
217 // by the comment aligner here.
219 // For a proper solution we need a mechanism to say to WhitespaceManager
220 // that a particular change breaks the current sequence of trailing
222 OriginalWhitespaceStart
!= PreviousOriginalWhitespaceEnd
;
224 // FIXME: The last token is currently not always an eof token; in those
225 // cases, setting TokenLength of the last token to 0 is wrong.
226 Changes
.back().TokenLength
= 0;
227 Changes
.back().IsTrailingComment
= Changes
.back().Tok
->is(tok::comment
);
229 const WhitespaceManager::Change
*LastBlockComment
= nullptr;
230 for (auto &Change
: Changes
) {
231 // Reset the IsTrailingComment flag for changes inside of trailing comments
232 // so they don't get realigned later. Comment line breaks however still need
234 if (Change
.IsInsideToken
&& Change
.NewlinesBefore
== 0)
235 Change
.IsTrailingComment
= false;
236 Change
.StartOfBlockComment
= nullptr;
237 Change
.IndentationOffset
= 0;
238 if (Change
.Tok
->is(tok::comment
)) {
239 if (Change
.Tok
->is(TT_LineComment
) || !Change
.IsInsideToken
) {
240 LastBlockComment
= &Change
;
241 } else if ((Change
.StartOfBlockComment
= LastBlockComment
)) {
242 Change
.IndentationOffset
=
243 Change
.StartOfTokenColumn
-
244 Change
.StartOfBlockComment
->StartOfTokenColumn
;
247 LastBlockComment
= nullptr;
251 // Compute conditional nesting level
252 // Level is increased for each conditional, unless this conditional continues
253 // a chain of conditional, i.e. starts immediately after the colon of another
255 SmallVector
<bool, 16> ScopeStack
;
256 int ConditionalsLevel
= 0;
257 for (auto &Change
: Changes
) {
258 for (unsigned i
= 0, e
= Change
.Tok
->FakeLParens
.size(); i
!= e
; ++i
) {
259 bool isNestedConditional
=
260 Change
.Tok
->FakeLParens
[e
- 1 - i
] == prec::Conditional
&&
261 !(i
== 0 && Change
.Tok
->Previous
&&
262 Change
.Tok
->Previous
->is(TT_ConditionalExpr
) &&
263 Change
.Tok
->Previous
->is(tok::colon
));
264 if (isNestedConditional
)
266 ScopeStack
.push_back(isNestedConditional
);
269 Change
.ConditionalsLevel
= ConditionalsLevel
;
271 for (unsigned i
= Change
.Tok
->FakeRParens
; i
> 0 && ScopeStack
.size(); --i
)
272 if (ScopeStack
.pop_back_val())
277 // Align a single sequence of tokens, see AlignTokens below.
278 // Column - The token for which Matches returns true is moved to this column.
279 // RightJustify - Whether it is the token's right end or left end that gets
280 // moved to that column.
281 template <typename F
>
283 AlignTokenSequence(const FormatStyle
&Style
, unsigned Start
, unsigned End
,
284 unsigned Column
, bool RightJustify
, F
&&Matches
,
285 SmallVector
<WhitespaceManager::Change
, 16> &Changes
) {
286 bool FoundMatchOnLine
= false;
289 // ScopeStack keeps track of the current scope depth. It contains indices of
290 // the first token on each scope.
291 // We only run the "Matches" function on tokens from the outer-most scope.
292 // However, we do need to pay special attention to one class of tokens
293 // that are not in the outer-most scope, and that is function parameters
294 // which are split across multiple lines, as illustrated by this example:
298 // In the above example, we need to take special care to ensure that
299 // 'double z' is indented along with it's owning function 'b'.
300 // The same holds for calling a function:
301 // double a = foo(x);
302 // int b = bar(foo(y),
304 // Similar for broken string literals:
308 // Special handling is required for 'nested' ternary operators.
309 SmallVector
<unsigned, 16> ScopeStack
;
311 for (unsigned i
= Start
; i
!= End
; ++i
) {
312 if (ScopeStack
.size() != 0 &&
313 Changes
[i
].indentAndNestingLevel() <
314 Changes
[ScopeStack
.back()].indentAndNestingLevel()) {
315 ScopeStack
.pop_back();
318 // Compare current token to previous non-comment token to ensure whether
319 // it is in a deeper scope or not.
320 unsigned PreviousNonComment
= i
- 1;
321 while (PreviousNonComment
> Start
&&
322 Changes
[PreviousNonComment
].Tok
->is(tok::comment
)) {
323 --PreviousNonComment
;
325 if (i
!= Start
&& Changes
[i
].indentAndNestingLevel() >
326 Changes
[PreviousNonComment
].indentAndNestingLevel()) {
327 ScopeStack
.push_back(i
);
330 bool InsideNestedScope
= ScopeStack
.size() != 0;
331 bool ContinuedStringLiteral
= i
> Start
&&
332 Changes
[i
].Tok
->is(tok::string_literal
) &&
333 Changes
[i
- 1].Tok
->is(tok::string_literal
);
334 bool SkipMatchCheck
= InsideNestedScope
|| ContinuedStringLiteral
;
336 if (Changes
[i
].NewlinesBefore
> 0 && !SkipMatchCheck
) {
338 FoundMatchOnLine
= false;
341 // If this is the first matching token to be aligned, remember by how many
342 // spaces it has to be shifted, so the rest of the changes on the line are
343 // shifted by the same amount
344 if (!FoundMatchOnLine
&& !SkipMatchCheck
&& Matches(Changes
[i
])) {
345 FoundMatchOnLine
= true;
346 Shift
= Column
- (RightJustify
? Changes
[i
].TokenLength
: 0) -
347 Changes
[i
].StartOfTokenColumn
;
348 Changes
[i
].Spaces
+= Shift
;
349 // FIXME: This is a workaround that should be removed when we fix
350 // http://llvm.org/PR53699. An assertion later below verifies this.
351 if (Changes
[i
].NewlinesBefore
== 0) {
353 std::max(Changes
[i
].Spaces
,
354 static_cast<int>(Changes
[i
].Tok
->SpacesRequiredBefore
));
358 // This is for function parameters that are split across multiple lines,
359 // as mentioned in the ScopeStack comment.
360 if (InsideNestedScope
&& Changes
[i
].NewlinesBefore
> 0) {
361 unsigned ScopeStart
= ScopeStack
.back();
362 auto ShouldShiftBeAdded
= [&] {
363 // Function declaration
364 if (Changes
[ScopeStart
- 1].Tok
->is(TT_FunctionDeclarationName
))
368 if (Changes
[ScopeStart
- 1].Tok
->is(TT_LambdaLBrace
))
371 // Continued function declaration
372 if (ScopeStart
> Start
+ 1 &&
373 Changes
[ScopeStart
- 2].Tok
->is(TT_FunctionDeclarationName
)) {
377 // Continued function call
378 if (ScopeStart
> Start
+ 1 &&
379 Changes
[ScopeStart
- 2].Tok
->is(tok::identifier
) &&
380 Changes
[ScopeStart
- 1].Tok
->is(tok::l_paren
) &&
381 Changes
[ScopeStart
].Tok
->isNot(TT_LambdaLSquare
)) {
382 if (Changes
[i
].Tok
->MatchingParen
&&
383 Changes
[i
].Tok
->MatchingParen
->is(TT_LambdaLBrace
)) {
386 if (Changes
[ScopeStart
].NewlinesBefore
> 0)
388 if (Changes
[i
].Tok
->is(tok::l_brace
) &&
389 Changes
[i
].Tok
->is(BK_BracedInit
)) {
392 return Style
.BinPackArguments
;
396 if (Changes
[i
].Tok
->is(TT_ConditionalExpr
))
399 // Period Initializer .XXX = 1.
400 if (Changes
[i
].Tok
->is(TT_DesignatedInitializerPeriod
))
403 // Continued ternary operator
404 if (Changes
[i
].Tok
->Previous
&&
405 Changes
[i
].Tok
->Previous
->is(TT_ConditionalExpr
)) {
409 // Continued direct-list-initialization using braced list.
410 if (ScopeStart
> Start
+ 1 &&
411 Changes
[ScopeStart
- 2].Tok
->is(tok::identifier
) &&
412 Changes
[ScopeStart
- 1].Tok
->is(tok::l_brace
) &&
413 Changes
[i
].Tok
->is(tok::l_brace
) &&
414 Changes
[i
].Tok
->is(BK_BracedInit
)) {
418 // Continued braced list.
419 if (ScopeStart
> Start
+ 1 &&
420 Changes
[ScopeStart
- 2].Tok
->isNot(tok::identifier
) &&
421 Changes
[ScopeStart
- 1].Tok
->is(tok::l_brace
) &&
422 Changes
[i
].Tok
->isNot(tok::r_brace
)) {
423 for (unsigned OuterScopeStart
: llvm::reverse(ScopeStack
)) {
425 if (OuterScopeStart
> Start
&&
426 Changes
[OuterScopeStart
- 1].Tok
->is(TT_LambdaLBrace
)) {
430 if (Changes
[ScopeStart
].NewlinesBefore
> 0)
438 if (ShouldShiftBeAdded())
439 Changes
[i
].Spaces
+= Shift
;
442 if (ContinuedStringLiteral
)
443 Changes
[i
].Spaces
+= Shift
;
445 // We should not remove required spaces unless we break the line before.
446 assert(Shift
>= 0 || Changes
[i
].NewlinesBefore
> 0 ||
448 static_cast<int>(Changes
[i
].Tok
->SpacesRequiredBefore
) ||
449 Changes
[i
].Tok
->is(tok::eof
));
451 Changes
[i
].StartOfTokenColumn
+= Shift
;
452 if (i
+ 1 != Changes
.size())
453 Changes
[i
+ 1].PreviousEndOfTokenColumn
+= Shift
;
455 // If PointerAlignment is PAS_Right, keep *s or &s next to the token
456 if (Style
.PointerAlignment
== FormatStyle::PAS_Right
&&
457 Changes
[i
].Spaces
!= 0) {
458 for (int Previous
= i
- 1;
460 Changes
[Previous
].Tok
->getType() == TT_PointerOrReference
;
462 Changes
[Previous
+ 1].Spaces
-= Shift
;
463 Changes
[Previous
].Spaces
+= Shift
;
464 Changes
[Previous
].StartOfTokenColumn
+= Shift
;
470 // Walk through a subset of the changes, starting at StartAt, and find
471 // sequences of matching tokens to align. To do so, keep track of the lines and
472 // whether or not a matching token was found on a line. If a matching token is
473 // found, extend the current sequence. If the current line cannot be part of a
474 // sequence, e.g. because there is an empty line before it or it contains only
475 // non-matching tokens, finalize the previous sequence.
476 // The value returned is the token on which we stopped, either because we
477 // exhausted all items inside Changes, or because we hit a scope level higher
478 // than our initial scope.
479 // This function is recursive. Each invocation processes only the scope level
480 // equal to the initial level, which is the level of Changes[StartAt].
481 // If we encounter a scope level greater than the initial level, then we call
482 // ourselves recursively, thereby avoiding the pollution of the current state
483 // with the alignment requirements of the nested sub-level. This recursive
484 // behavior is necessary for aligning function prototypes that have one or more
486 // If this function encounters a scope level less than the initial level,
487 // it returns the current position.
488 // There is a non-obvious subtlety in the recursive behavior: Even though we
489 // defer processing of nested levels to recursive invocations of this
490 // function, when it comes time to align a sequence of tokens, we run the
491 // alignment on the entire sequence, including the nested levels.
492 // When doing so, most of the nested tokens are skipped, because their
493 // alignment was already handled by the recursive invocations of this function.
494 // However, the special exception is that we do NOT skip function parameters
495 // that are split across multiple lines. See the test case in FormatTest.cpp
496 // that mentions "split function parameter alignment" for an example of this.
497 // When the parameter RightJustify is true, the operator will be
498 // right-justified. It is used to align compound assignments like `+=` and `=`.
499 // When RightJustify and ACS.PadOperators are true, operators in each block to
500 // be aligned will be padded on the left to the same length before aligning.
501 template <typename F
>
502 static unsigned AlignTokens(const FormatStyle
&Style
, F
&&Matches
,
503 SmallVector
<WhitespaceManager::Change
, 16> &Changes
,
505 const FormatStyle::AlignConsecutiveStyle
&ACS
= {},
506 bool RightJustify
= false) {
507 // We arrange each line in 3 parts. The operator to be aligned (the anchor),
508 // and text to its left and right. In the aligned text the width of each part
509 // will be the maximum of that over the block that has been aligned. Maximum
510 // widths of each part so far. When RightJustify is true and ACS.PadOperators
511 // is false, the part from start of line to the right end of the anchor.
512 // Otherwise, only the part to the left of the anchor. Including the space
513 // that exists on its left from the start. Not including the padding added on
514 // the left to right-justify the anchor.
515 unsigned WidthLeft
= 0;
516 // The operator to be aligned when RightJustify is true and ACS.PadOperators
517 // is false. 0 otherwise.
518 unsigned WidthAnchor
= 0;
519 // Width to the right of the anchor. Plus width of the anchor when
520 // RightJustify is false.
521 unsigned WidthRight
= 0;
523 // Line number of the start and the end of the current token sequence.
524 unsigned StartOfSequence
= 0;
525 unsigned EndOfSequence
= 0;
527 // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
528 // abort when we hit any token in a higher scope than the starting one.
529 auto IndentAndNestingLevel
= StartAt
< Changes
.size()
530 ? Changes
[StartAt
].indentAndNestingLevel()
531 : std::tuple
<unsigned, unsigned, unsigned>();
533 // Keep track of the number of commas before the matching tokens, we will only
534 // align a sequence of matching tokens if they are preceded by the same number
536 unsigned CommasBeforeLastMatch
= 0;
537 unsigned CommasBeforeMatch
= 0;
539 // Whether a matching token has been found on the current line.
540 bool FoundMatchOnLine
= false;
542 // Whether the current line consists purely of comments.
543 bool LineIsComment
= true;
545 // Aligns a sequence of matching tokens, on the MinColumn column.
547 // Sequences start from the first matching token to align, and end at the
548 // first token of the first line that doesn't need to be aligned.
550 // We need to adjust the StartOfTokenColumn of each Change that is on a line
551 // containing any matching token to be aligned and located after such token.
552 auto AlignCurrentSequence
= [&] {
553 if (StartOfSequence
> 0 && StartOfSequence
< EndOfSequence
) {
554 AlignTokenSequence(Style
, StartOfSequence
, EndOfSequence
,
555 WidthLeft
+ WidthAnchor
, RightJustify
, Matches
,
565 unsigned i
= StartAt
;
566 for (unsigned e
= Changes
.size(); i
!= e
; ++i
) {
567 if (Changes
[i
].indentAndNestingLevel() < IndentAndNestingLevel
)
570 if (Changes
[i
].NewlinesBefore
!= 0) {
571 CommasBeforeMatch
= 0;
574 // Whether to break the alignment sequence because of an empty line.
575 bool EmptyLineBreak
=
576 (Changes
[i
].NewlinesBefore
> 1) && !ACS
.AcrossEmptyLines
;
578 // Whether to break the alignment sequence because of a line without a
581 !FoundMatchOnLine
&& !(LineIsComment
&& ACS
.AcrossComments
);
583 if (EmptyLineBreak
|| NoMatchBreak
)
584 AlignCurrentSequence();
586 // A new line starts, re-initialize line status tracking bools.
587 // Keep the match state if a string literal is continued on this line.
588 if (i
== 0 || !Changes
[i
].Tok
->is(tok::string_literal
) ||
589 !Changes
[i
- 1].Tok
->is(tok::string_literal
)) {
590 FoundMatchOnLine
= false;
592 LineIsComment
= true;
595 if (!Changes
[i
].Tok
->is(tok::comment
))
596 LineIsComment
= false;
598 if (Changes
[i
].Tok
->is(tok::comma
)) {
600 } else if (Changes
[i
].indentAndNestingLevel() > IndentAndNestingLevel
) {
601 // Call AlignTokens recursively, skipping over this scope block.
603 AlignTokens(Style
, Matches
, Changes
, i
, ACS
, RightJustify
);
608 if (!Matches(Changes
[i
]))
611 // If there is more than one matching token per line, or if the number of
612 // preceding commas, do not match anymore, end the sequence.
613 if (FoundMatchOnLine
|| CommasBeforeMatch
!= CommasBeforeLastMatch
)
614 AlignCurrentSequence();
616 CommasBeforeLastMatch
= CommasBeforeMatch
;
617 FoundMatchOnLine
= true;
619 if (StartOfSequence
== 0)
622 unsigned ChangeWidthLeft
= Changes
[i
].StartOfTokenColumn
;
623 unsigned ChangeWidthAnchor
= 0;
624 unsigned ChangeWidthRight
= 0;
626 if (ACS
.PadOperators
)
627 ChangeWidthAnchor
= Changes
[i
].TokenLength
;
629 ChangeWidthLeft
+= Changes
[i
].TokenLength
;
631 ChangeWidthRight
= Changes
[i
].TokenLength
;
632 for (unsigned j
= i
+ 1; j
!= e
&& Changes
[j
].NewlinesBefore
== 0; ++j
) {
633 ChangeWidthRight
+= Changes
[j
].Spaces
;
634 // Changes are generally 1:1 with the tokens, but a change could also be
635 // inside of a token, in which case it's counted more than once: once for
636 // the whitespace surrounding the token (!IsInsideToken) and once for
637 // each whitespace change within it (IsInsideToken).
638 // Therefore, changes inside of a token should only count the space.
639 if (!Changes
[j
].IsInsideToken
)
640 ChangeWidthRight
+= Changes
[j
].TokenLength
;
643 // If we are restricted by the maximum column width, end the sequence.
644 unsigned NewLeft
= std::max(ChangeWidthLeft
, WidthLeft
);
645 unsigned NewAnchor
= std::max(ChangeWidthAnchor
, WidthAnchor
);
646 unsigned NewRight
= std::max(ChangeWidthRight
, WidthRight
);
647 // `ColumnLimit == 0` means there is no column limit.
648 if (Style
.ColumnLimit
!= 0 &&
649 Style
.ColumnLimit
< NewLeft
+ NewAnchor
+ NewRight
) {
650 AlignCurrentSequence();
652 WidthLeft
= ChangeWidthLeft
;
653 WidthAnchor
= ChangeWidthAnchor
;
654 WidthRight
= ChangeWidthRight
;
657 WidthAnchor
= NewAnchor
;
658 WidthRight
= NewRight
;
663 AlignCurrentSequence();
667 // Aligns a sequence of matching tokens, on the MinColumn column.
669 // Sequences start from the first matching token to align, and end at the
670 // first token of the first line that doesn't need to be aligned.
672 // We need to adjust the StartOfTokenColumn of each Change that is on a line
673 // containing any matching token to be aligned and located after such token.
674 static void AlignMacroSequence(
675 unsigned &StartOfSequence
, unsigned &EndOfSequence
, unsigned &MinColumn
,
676 unsigned &MaxColumn
, bool &FoundMatchOnLine
,
677 std::function
<bool(const WhitespaceManager::Change
&C
)> AlignMacrosMatches
,
678 SmallVector
<WhitespaceManager::Change
, 16> &Changes
) {
679 if (StartOfSequence
> 0 && StartOfSequence
< EndOfSequence
) {
681 FoundMatchOnLine
= false;
684 for (unsigned I
= StartOfSequence
; I
!= EndOfSequence
; ++I
) {
685 if (Changes
[I
].NewlinesBefore
> 0) {
687 FoundMatchOnLine
= false;
690 // If this is the first matching token to be aligned, remember by how many
691 // spaces it has to be shifted, so the rest of the changes on the line are
692 // shifted by the same amount
693 if (!FoundMatchOnLine
&& AlignMacrosMatches(Changes
[I
])) {
694 FoundMatchOnLine
= true;
695 Shift
= MinColumn
- Changes
[I
].StartOfTokenColumn
;
696 Changes
[I
].Spaces
+= Shift
;
700 Changes
[I
].StartOfTokenColumn
+= Shift
;
701 if (I
+ 1 != Changes
.size())
702 Changes
[I
+ 1].PreviousEndOfTokenColumn
+= Shift
;
707 MaxColumn
= UINT_MAX
;
712 void WhitespaceManager::alignConsecutiveMacros() {
713 if (!Style
.AlignConsecutiveMacros
.Enabled
)
716 auto AlignMacrosMatches
= [](const Change
&C
) {
717 const FormatToken
*Current
= C
.Tok
;
718 unsigned SpacesRequiredBefore
= 1;
720 if (Current
->SpacesRequiredBefore
== 0 || !Current
->Previous
)
723 Current
= Current
->Previous
;
725 // If token is a ")", skip over the parameter list, to the
726 // token that precedes the "("
727 if (Current
->is(tok::r_paren
) && Current
->MatchingParen
) {
728 Current
= Current
->MatchingParen
->Previous
;
729 SpacesRequiredBefore
= 0;
732 if (!Current
|| !Current
->is(tok::identifier
))
735 if (!Current
->Previous
|| !Current
->Previous
->is(tok::pp_define
))
738 // For a macro function, 0 spaces are required between the
739 // identifier and the lparen that opens the parameter list.
740 // For a simple macro, 1 space is required between the
741 // identifier and the first token of the defined value.
742 return Current
->Next
->SpacesRequiredBefore
== SpacesRequiredBefore
;
745 unsigned MinColumn
= 0;
746 unsigned MaxColumn
= UINT_MAX
;
748 // Start and end of the token sequence we're processing.
749 unsigned StartOfSequence
= 0;
750 unsigned EndOfSequence
= 0;
752 // Whether a matching token has been found on the current line.
753 bool FoundMatchOnLine
= false;
755 // Whether the current line consists only of comments
756 bool LineIsComment
= true;
759 for (unsigned E
= Changes
.size(); I
!= E
; ++I
) {
760 if (Changes
[I
].NewlinesBefore
!= 0) {
763 // Whether to break the alignment sequence because of an empty line.
764 bool EmptyLineBreak
= (Changes
[I
].NewlinesBefore
> 1) &&
765 !Style
.AlignConsecutiveMacros
.AcrossEmptyLines
;
767 // Whether to break the alignment sequence because of a line without a
771 !(LineIsComment
&& Style
.AlignConsecutiveMacros
.AcrossComments
);
773 if (EmptyLineBreak
|| NoMatchBreak
) {
774 AlignMacroSequence(StartOfSequence
, EndOfSequence
, MinColumn
, MaxColumn
,
775 FoundMatchOnLine
, AlignMacrosMatches
, Changes
);
778 // A new line starts, re-initialize line status tracking bools.
779 FoundMatchOnLine
= false;
780 LineIsComment
= true;
783 if (!Changes
[I
].Tok
->is(tok::comment
))
784 LineIsComment
= false;
786 if (!AlignMacrosMatches(Changes
[I
]))
789 FoundMatchOnLine
= true;
791 if (StartOfSequence
== 0)
794 unsigned ChangeMinColumn
= Changes
[I
].StartOfTokenColumn
;
795 int LineLengthAfter
= -Changes
[I
].Spaces
;
796 for (unsigned j
= I
; j
!= E
&& Changes
[j
].NewlinesBefore
== 0; ++j
)
797 LineLengthAfter
+= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
798 unsigned ChangeMaxColumn
= Style
.ColumnLimit
- LineLengthAfter
;
800 MinColumn
= std::max(MinColumn
, ChangeMinColumn
);
801 MaxColumn
= std::min(MaxColumn
, ChangeMaxColumn
);
805 AlignMacroSequence(StartOfSequence
, EndOfSequence
, MinColumn
, MaxColumn
,
806 FoundMatchOnLine
, AlignMacrosMatches
, Changes
);
809 void WhitespaceManager::alignConsecutiveAssignments() {
810 if (!Style
.AlignConsecutiveAssignments
.Enabled
)
815 [&](const Change
&C
) {
816 // Do not align on equal signs that are first on a line.
817 if (C
.NewlinesBefore
> 0)
820 // Do not align on equal signs that are last on a line.
821 if (&C
!= &Changes
.back() && (&C
+ 1)->NewlinesBefore
> 0)
824 // Do not align operator= overloads.
825 FormatToken
*Previous
= C
.Tok
->getPreviousNonComment();
826 if (Previous
&& Previous
->is(tok::kw_operator
))
829 return Style
.AlignConsecutiveAssignments
.AlignCompound
830 ? C
.Tok
->getPrecedence() == prec::Assignment
831 : (C
.Tok
->is(tok::equal
) ||
832 // In Verilog the '<=' is not a compound assignment, thus
833 // it is aligned even when the AlignCompound option is not
835 (Style
.isVerilog() && C
.Tok
->is(tok::lessequal
) &&
836 C
.Tok
->getPrecedence() == prec::Assignment
));
838 Changes
, /*StartAt=*/0, Style
.AlignConsecutiveAssignments
,
839 /*RightJustify=*/true);
842 void WhitespaceManager::alignConsecutiveBitFields() {
843 if (!Style
.AlignConsecutiveBitFields
.Enabled
)
848 [&](Change
const &C
) {
849 // Do not align on ':' that is first on a line.
850 if (C
.NewlinesBefore
> 0)
853 // Do not align on ':' that is last on a line.
854 if (&C
!= &Changes
.back() && (&C
+ 1)->NewlinesBefore
> 0)
857 return C
.Tok
->is(TT_BitFieldColon
);
859 Changes
, /*StartAt=*/0, Style
.AlignConsecutiveBitFields
);
862 void WhitespaceManager::alignConsecutiveDeclarations() {
863 if (!Style
.AlignConsecutiveDeclarations
.Enabled
)
868 [](Change
const &C
) {
869 if (C
.Tok
->is(TT_FunctionDeclarationName
))
871 if (C
.Tok
->isNot(TT_StartOfName
))
873 if (C
.Tok
->Previous
&&
874 C
.Tok
->Previous
->is(TT_StatementAttributeLikeMacro
))
876 // Check if there is a subsequent name that starts the same declaration.
877 for (FormatToken
*Next
= C
.Tok
->Next
; Next
; Next
= Next
->Next
) {
878 if (Next
->is(tok::comment
))
880 if (Next
->is(TT_PointerOrReference
))
882 if (!Next
->Tok
.getIdentifierInfo())
884 if (Next
->isOneOf(TT_StartOfName
, TT_FunctionDeclarationName
,
891 Changes
, /*StartAt=*/0, Style
.AlignConsecutiveDeclarations
);
894 void WhitespaceManager::alignChainedConditionals() {
895 if (Style
.BreakBeforeTernaryOperators
) {
898 [](Change
const &C
) {
899 // Align question operators and last colon
900 return C
.Tok
->is(TT_ConditionalExpr
) &&
901 ((C
.Tok
->is(tok::question
) && !C
.NewlinesBefore
) ||
902 (C
.Tok
->is(tok::colon
) && C
.Tok
->Next
&&
903 (C
.Tok
->Next
->FakeLParens
.size() == 0 ||
904 C
.Tok
->Next
->FakeLParens
.back() != prec::Conditional
)));
906 Changes
, /*StartAt=*/0);
908 static auto AlignWrappedOperand
= [](Change
const &C
) {
909 FormatToken
*Previous
= C
.Tok
->getPreviousNonComment();
910 return C
.NewlinesBefore
&& Previous
&& Previous
->is(TT_ConditionalExpr
) &&
911 (Previous
->is(tok::colon
) &&
912 (C
.Tok
->FakeLParens
.size() == 0 ||
913 C
.Tok
->FakeLParens
.back() != prec::Conditional
));
915 // Ensure we keep alignment of wrapped operands with non-wrapped operands
916 // Since we actually align the operators, the wrapped operands need the
917 // extra offset to be properly aligned.
918 for (Change
&C
: Changes
)
919 if (AlignWrappedOperand(C
))
920 C
.StartOfTokenColumn
-= 2;
923 [this](Change
const &C
) {
924 // Align question operators if next operand is not wrapped, as
925 // well as wrapped operands after question operator or last
926 // colon in conditional sequence
927 return (C
.Tok
->is(TT_ConditionalExpr
) && C
.Tok
->is(tok::question
) &&
928 &C
!= &Changes
.back() && (&C
+ 1)->NewlinesBefore
== 0 &&
929 !(&C
+ 1)->IsTrailingComment
) ||
930 AlignWrappedOperand(C
);
932 Changes
, /*StartAt=*/0);
936 void WhitespaceManager::alignTrailingComments() {
937 unsigned MinColumn
= 0;
938 unsigned MaxColumn
= UINT_MAX
;
939 unsigned StartOfSequence
= 0;
940 bool BreakBeforeNext
= false;
941 unsigned Newlines
= 0;
942 unsigned int NewLineThreshold
= 1;
943 if (Style
.AlignTrailingComments
.Kind
== FormatStyle::TCAS_Always
)
944 NewLineThreshold
= Style
.AlignTrailingComments
.OverEmptyLines
+ 1;
946 for (unsigned i
= 0, e
= Changes
.size(); i
!= e
; ++i
) {
947 if (Changes
[i
].StartOfBlockComment
)
949 Newlines
+= Changes
[i
].NewlinesBefore
;
950 if (!Changes
[i
].IsTrailingComment
)
953 if (Style
.AlignTrailingComments
.Kind
== FormatStyle::TCAS_Leave
) {
954 auto OriginalSpaces
=
955 Changes
[i
].OriginalWhitespaceRange
.getEnd().getRawEncoding() -
956 Changes
[i
].OriginalWhitespaceRange
.getBegin().getRawEncoding() -
957 Changes
[i
].Tok
->NewlinesBefore
;
958 unsigned RestoredLineLength
= Changes
[i
].StartOfTokenColumn
+
959 Changes
[i
].TokenLength
+ OriginalSpaces
;
960 // If leaving comments makes the line exceed the column limit, give up to
961 // leave the comments.
962 if (RestoredLineLength
>= Style
.ColumnLimit
&& Style
.ColumnLimit
!= 0)
964 Changes
[i
].Spaces
= OriginalSpaces
;
968 unsigned ChangeMinColumn
= Changes
[i
].StartOfTokenColumn
;
969 unsigned ChangeMaxColumn
;
971 if (Style
.ColumnLimit
== 0)
972 ChangeMaxColumn
= UINT_MAX
;
973 else if (Style
.ColumnLimit
>= Changes
[i
].TokenLength
)
974 ChangeMaxColumn
= Style
.ColumnLimit
- Changes
[i
].TokenLength
;
976 ChangeMaxColumn
= ChangeMinColumn
;
978 // If we don't create a replacement for this change, we have to consider
979 // it to be immovable.
980 if (!Changes
[i
].CreateReplacement
)
981 ChangeMaxColumn
= ChangeMinColumn
;
983 if (i
+ 1 != e
&& Changes
[i
+ 1].ContinuesPPDirective
)
984 ChangeMaxColumn
-= 2;
985 // If this comment follows an } in column 0, it probably documents the
986 // closing of a namespace and we don't want to align it.
987 bool FollowsRBraceInColumn0
= i
> 0 && Changes
[i
].NewlinesBefore
== 0 &&
988 Changes
[i
- 1].Tok
->is(tok::r_brace
) &&
989 Changes
[i
- 1].StartOfTokenColumn
== 0;
990 bool WasAlignedWithStartOfNextLine
= false;
991 if (Changes
[i
].NewlinesBefore
>= 1) { // A comment on its own line.
992 unsigned CommentColumn
= SourceMgr
.getSpellingColumnNumber(
993 Changes
[i
].OriginalWhitespaceRange
.getEnd());
994 for (unsigned j
= i
+ 1; j
!= e
; ++j
) {
995 if (Changes
[j
].Tok
->is(tok::comment
))
998 unsigned NextColumn
= SourceMgr
.getSpellingColumnNumber(
999 Changes
[j
].OriginalWhitespaceRange
.getEnd());
1000 // The start of the next token was previously aligned with the
1001 // start of this comment.
1002 WasAlignedWithStartOfNextLine
=
1003 CommentColumn
== NextColumn
||
1004 CommentColumn
== NextColumn
+ Style
.IndentWidth
;
1008 if (Style
.AlignTrailingComments
.Kind
== FormatStyle::TCAS_Never
||
1009 FollowsRBraceInColumn0
) {
1010 alignTrailingComments(StartOfSequence
, i
, MinColumn
);
1011 MinColumn
= ChangeMinColumn
;
1012 MaxColumn
= ChangeMinColumn
;
1013 StartOfSequence
= i
;
1014 } else if (BreakBeforeNext
|| Newlines
> NewLineThreshold
||
1015 (ChangeMinColumn
> MaxColumn
|| ChangeMaxColumn
< MinColumn
) ||
1016 // Break the comment sequence if the previous line did not end
1017 // in a trailing comment.
1018 (Changes
[i
].NewlinesBefore
== 1 && i
> 0 &&
1019 !Changes
[i
- 1].IsTrailingComment
) ||
1020 WasAlignedWithStartOfNextLine
) {
1021 alignTrailingComments(StartOfSequence
, i
, MinColumn
);
1022 MinColumn
= ChangeMinColumn
;
1023 MaxColumn
= ChangeMaxColumn
;
1024 StartOfSequence
= i
;
1026 MinColumn
= std::max(MinColumn
, ChangeMinColumn
);
1027 MaxColumn
= std::min(MaxColumn
, ChangeMaxColumn
);
1029 BreakBeforeNext
= (i
== 0) || (Changes
[i
].NewlinesBefore
> 1) ||
1030 // Never start a sequence with a comment at the beginning
1032 (Changes
[i
].NewlinesBefore
== 1 && StartOfSequence
== i
);
1035 alignTrailingComments(StartOfSequence
, Changes
.size(), MinColumn
);
1038 void WhitespaceManager::alignTrailingComments(unsigned Start
, unsigned End
,
1040 for (unsigned i
= Start
; i
!= End
; ++i
) {
1042 if (Changes
[i
].IsTrailingComment
)
1043 Shift
= Column
- Changes
[i
].StartOfTokenColumn
;
1044 if (Changes
[i
].StartOfBlockComment
) {
1045 Shift
= Changes
[i
].IndentationOffset
+
1046 Changes
[i
].StartOfBlockComment
->StartOfTokenColumn
-
1047 Changes
[i
].StartOfTokenColumn
;
1051 Changes
[i
].Spaces
+= Shift
;
1052 if (i
+ 1 != Changes
.size())
1053 Changes
[i
+ 1].PreviousEndOfTokenColumn
+= Shift
;
1054 Changes
[i
].StartOfTokenColumn
+= Shift
;
1058 void WhitespaceManager::alignEscapedNewlines() {
1059 if (Style
.AlignEscapedNewlines
== FormatStyle::ENAS_DontAlign
)
1062 bool AlignLeft
= Style
.AlignEscapedNewlines
== FormatStyle::ENAS_Left
;
1063 unsigned MaxEndOfLine
= AlignLeft
? 0 : Style
.ColumnLimit
;
1064 unsigned StartOfMacro
= 0;
1065 for (unsigned i
= 1, e
= Changes
.size(); i
< e
; ++i
) {
1066 Change
&C
= Changes
[i
];
1067 if (C
.NewlinesBefore
> 0) {
1068 if (C
.ContinuesPPDirective
) {
1069 MaxEndOfLine
= std::max(C
.PreviousEndOfTokenColumn
+ 2, MaxEndOfLine
);
1071 alignEscapedNewlines(StartOfMacro
+ 1, i
, MaxEndOfLine
);
1072 MaxEndOfLine
= AlignLeft
? 0 : Style
.ColumnLimit
;
1077 alignEscapedNewlines(StartOfMacro
+ 1, Changes
.size(), MaxEndOfLine
);
1080 void WhitespaceManager::alignEscapedNewlines(unsigned Start
, unsigned End
,
1082 for (unsigned i
= Start
; i
< End
; ++i
) {
1083 Change
&C
= Changes
[i
];
1084 if (C
.NewlinesBefore
> 0) {
1085 assert(C
.ContinuesPPDirective
);
1086 if (C
.PreviousEndOfTokenColumn
+ 1 > Column
)
1087 C
.EscapedNewlineColumn
= 0;
1089 C
.EscapedNewlineColumn
= Column
;
1094 void WhitespaceManager::alignArrayInitializers() {
1095 if (Style
.AlignArrayOfStructures
== FormatStyle::AIAS_None
)
1098 for (unsigned ChangeIndex
= 1U, ChangeEnd
= Changes
.size();
1099 ChangeIndex
< ChangeEnd
; ++ChangeIndex
) {
1100 auto &C
= Changes
[ChangeIndex
];
1101 if (C
.Tok
->IsArrayInitializer
) {
1102 bool FoundComplete
= false;
1103 for (unsigned InsideIndex
= ChangeIndex
+ 1; InsideIndex
< ChangeEnd
;
1105 if (Changes
[InsideIndex
].Tok
== C
.Tok
->MatchingParen
) {
1106 alignArrayInitializers(ChangeIndex
, InsideIndex
+ 1);
1107 ChangeIndex
= InsideIndex
+ 1;
1108 FoundComplete
= true;
1113 ChangeIndex
= ChangeEnd
;
1118 void WhitespaceManager::alignArrayInitializers(unsigned Start
, unsigned End
) {
1120 if (Style
.AlignArrayOfStructures
== FormatStyle::AIAS_Right
)
1121 alignArrayInitializersRightJustified(getCells(Start
, End
));
1122 else if (Style
.AlignArrayOfStructures
== FormatStyle::AIAS_Left
)
1123 alignArrayInitializersLeftJustified(getCells(Start
, End
));
1126 void WhitespaceManager::alignArrayInitializersRightJustified(
1127 CellDescriptions
&&CellDescs
) {
1128 if (!CellDescs
.isRectangular())
1131 auto &Cells
= CellDescs
.Cells
;
1132 // Now go through and fixup the spaces.
1133 auto *CellIter
= Cells
.begin();
1134 for (auto i
= 0U; i
< CellDescs
.CellCounts
[0]; ++i
, ++CellIter
) {
1135 unsigned NetWidth
= 0U;
1136 if (isSplitCell(*CellIter
))
1137 NetWidth
= getNetWidth(Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
);
1138 auto CellWidth
= getMaximumCellWidth(CellIter
, NetWidth
);
1140 if (Changes
[CellIter
->Index
].Tok
->is(tok::r_brace
)) {
1141 // So in here we want to see if there is a brace that falls
1142 // on a line that was split. If so on that line we make sure that
1143 // the spaces in front of the brace are enough.
1144 const auto *Next
= CellIter
;
1146 const FormatToken
*Previous
= Changes
[Next
->Index
].Tok
->Previous
;
1147 if (Previous
&& Previous
->isNot(TT_LineComment
)) {
1148 Changes
[Next
->Index
].Spaces
= 0;
1149 Changes
[Next
->Index
].NewlinesBefore
= 0;
1151 Next
= Next
->NextColumnElement
;
1153 // Unless the array is empty, we need the position of all the
1154 // immediately adjacent cells
1155 if (CellIter
!= Cells
.begin()) {
1157 getNetWidth(Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
);
1158 auto MaxNetWidth
= getMaximumNetWidth(
1159 Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
,
1160 CellDescs
.CellCounts
[0], CellDescs
.CellCounts
.size());
1161 if (ThisNetWidth
< MaxNetWidth
)
1162 Changes
[CellIter
->Index
].Spaces
= (MaxNetWidth
- ThisNetWidth
);
1164 auto Offset
= std::distance(Cells
.begin(), CellIter
);
1165 for (const auto *Next
= CellIter
->NextColumnElement
; Next
;
1166 Next
= Next
->NextColumnElement
) {
1167 auto *Start
= (Cells
.begin() + RowCount
* CellDescs
.CellCounts
[0]);
1168 auto *End
= Start
+ Offset
;
1169 ThisNetWidth
= getNetWidth(Start
, End
, CellDescs
.InitialSpaces
);
1170 if (ThisNetWidth
< MaxNetWidth
)
1171 Changes
[Next
->Index
].Spaces
= (MaxNetWidth
- ThisNetWidth
);
1177 calculateCellWidth(CellIter
->Index
, CellIter
->EndIndex
, true) +
1179 if (Changes
[CellIter
->Index
].NewlinesBefore
== 0) {
1180 Changes
[CellIter
->Index
].Spaces
= (CellWidth
- (ThisWidth
+ NetWidth
));
1181 Changes
[CellIter
->Index
].Spaces
+= (i
> 0) ? 1 : 0;
1183 alignToStartOfCell(CellIter
->Index
, CellIter
->EndIndex
);
1184 for (const auto *Next
= CellIter
->NextColumnElement
; Next
;
1185 Next
= Next
->NextColumnElement
) {
1187 calculateCellWidth(Next
->Index
, Next
->EndIndex
, true) + NetWidth
;
1188 if (Changes
[Next
->Index
].NewlinesBefore
== 0) {
1189 Changes
[Next
->Index
].Spaces
= (CellWidth
- ThisWidth
);
1190 Changes
[Next
->Index
].Spaces
+= (i
> 0) ? 1 : 0;
1192 alignToStartOfCell(Next
->Index
, Next
->EndIndex
);
1198 void WhitespaceManager::alignArrayInitializersLeftJustified(
1199 CellDescriptions
&&CellDescs
) {
1201 if (!CellDescs
.isRectangular())
1204 auto &Cells
= CellDescs
.Cells
;
1205 // Now go through and fixup the spaces.
1206 auto *CellIter
= Cells
.begin();
1207 // The first cell needs to be against the left brace.
1208 if (Changes
[CellIter
->Index
].NewlinesBefore
== 0)
1209 Changes
[CellIter
->Index
].Spaces
= 0;
1211 Changes
[CellIter
->Index
].Spaces
= CellDescs
.InitialSpaces
;
1213 for (auto i
= 1U; i
< CellDescs
.CellCounts
[0]; i
++, ++CellIter
) {
1214 auto MaxNetWidth
= getMaximumNetWidth(
1215 Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
,
1216 CellDescs
.CellCounts
[0], CellDescs
.CellCounts
.size());
1218 getNetWidth(Cells
.begin(), CellIter
, CellDescs
.InitialSpaces
);
1219 if (Changes
[CellIter
->Index
].NewlinesBefore
== 0) {
1220 Changes
[CellIter
->Index
].Spaces
=
1221 MaxNetWidth
- ThisNetWidth
+
1222 (Changes
[CellIter
->Index
].Tok
->isNot(tok::r_brace
) ? 1 : 0);
1225 auto Offset
= std::distance(Cells
.begin(), CellIter
);
1226 for (const auto *Next
= CellIter
->NextColumnElement
; Next
;
1227 Next
= Next
->NextColumnElement
) {
1228 if (RowCount
> CellDescs
.CellCounts
.size())
1230 auto *Start
= (Cells
.begin() + RowCount
* CellDescs
.CellCounts
[0]);
1231 auto *End
= Start
+ Offset
;
1232 auto ThisNetWidth
= getNetWidth(Start
, End
, CellDescs
.InitialSpaces
);
1233 if (Changes
[Next
->Index
].NewlinesBefore
== 0) {
1234 Changes
[Next
->Index
].Spaces
=
1235 MaxNetWidth
- ThisNetWidth
+
1236 (Changes
[Next
->Index
].Tok
->isNot(tok::r_brace
) ? 1 : 0);
1243 bool WhitespaceManager::isSplitCell(const CellDescription
&Cell
) {
1246 for (const auto *Next
= Cell
.NextColumnElement
; Next
;
1247 Next
= Next
->NextColumnElement
) {
1254 WhitespaceManager::CellDescriptions
WhitespaceManager::getCells(unsigned Start
,
1259 SmallVector
<unsigned> CellCounts
;
1260 unsigned InitialSpaces
= 0;
1261 unsigned InitialTokenLength
= 0;
1262 unsigned EndSpaces
= 0;
1263 SmallVector
<CellDescription
> Cells
;
1264 const FormatToken
*MatchingParen
= nullptr;
1265 for (unsigned i
= Start
; i
< End
; ++i
) {
1266 auto &C
= Changes
[i
];
1267 if (C
.Tok
->is(tok::l_brace
))
1269 else if (C
.Tok
->is(tok::r_brace
))
1272 if (C
.Tok
->is(tok::l_brace
)) {
1274 MatchingParen
= C
.Tok
->MatchingParen
;
1275 if (InitialSpaces
== 0) {
1276 InitialSpaces
= C
.Spaces
+ C
.TokenLength
;
1277 InitialTokenLength
= C
.TokenLength
;
1279 for (; Changes
[j
].NewlinesBefore
== 0 && j
> Start
; --j
) {
1280 InitialSpaces
+= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
1281 InitialTokenLength
+= Changes
[j
].TokenLength
;
1283 if (C
.NewlinesBefore
== 0) {
1284 InitialSpaces
+= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
1285 InitialTokenLength
+= Changes
[j
].TokenLength
;
1288 } else if (C
.Tok
->is(tok::comma
)) {
1290 Cells
.back().EndIndex
= i
;
1291 if (C
.Tok
->getNextNonComment()->isNot(tok::r_brace
)) // dangling comma
1294 } else if (Depth
== 1) {
1295 if (C
.Tok
== MatchingParen
) {
1297 Cells
.back().EndIndex
= i
;
1298 Cells
.push_back(CellDescription
{i
, ++Cell
, i
+ 1, false, nullptr});
1299 CellCounts
.push_back(C
.Tok
->Previous
->isNot(tok::comma
) ? Cell
+ 1
1301 // Go to the next non-comment and ensure there is a break in front
1302 const auto *NextNonComment
= C
.Tok
->getNextNonComment();
1303 while (NextNonComment
->is(tok::comma
))
1304 NextNonComment
= NextNonComment
->getNextNonComment();
1306 while (Changes
[j
].Tok
!= NextNonComment
&& j
< End
)
1308 if (j
< End
&& Changes
[j
].NewlinesBefore
== 0 &&
1309 Changes
[j
].Tok
->isNot(tok::r_brace
)) {
1310 Changes
[j
].NewlinesBefore
= 1;
1311 // Account for the added token lengths
1312 Changes
[j
].Spaces
= InitialSpaces
- InitialTokenLength
;
1314 } else if (C
.Tok
->is(tok::comment
)) {
1315 // Trailing comments stay at a space past the last token
1316 C
.Spaces
= Changes
[i
- 1].Tok
->is(tok::comma
) ? 1 : 2;
1317 } else if (C
.Tok
->is(tok::l_brace
)) {
1318 // We need to make sure that the ending braces is aligned to the
1319 // start of our initializer
1321 for (; j
> 0 && !Changes
[j
].Tok
->ArrayInitializerLineStart
; --j
)
1322 ; // Nothing the loop does the work
1323 EndSpaces
= Changes
[j
].Spaces
;
1325 } else if (Depth
== 0 && C
.Tok
->is(tok::r_brace
)) {
1326 C
.NewlinesBefore
= 1;
1327 C
.Spaces
= EndSpaces
;
1329 if (C
.Tok
->StartsColumn
) {
1330 // This gets us past tokens that have been split over multiple
1332 bool HasSplit
= false;
1333 if (Changes
[i
].NewlinesBefore
> 0) {
1334 // So if we split a line previously and the tail line + this token is
1335 // less then the column limit we remove the split here and just put
1336 // the column start at a space past the comma
1338 // FIXME This if branch covers the cases where the column is not
1339 // the first column. This leads to weird pathologies like the formatting
1340 // auto foo = Items{
1345 // Well if it doesn't lead to that it's indicative that the line
1346 // breaking should be revisited. Unfortunately alot of other options
1347 // interact with this
1349 if ((j
- 1) > Start
&& Changes
[j
].Tok
->is(tok::comma
) &&
1350 Changes
[j
- 1].NewlinesBefore
> 0) {
1352 auto LineLimit
= Changes
[j
].Spaces
+ Changes
[j
].TokenLength
;
1353 if (LineLimit
< Style
.ColumnLimit
) {
1354 Changes
[i
].NewlinesBefore
= 0;
1355 Changes
[i
].Spaces
= 1;
1359 while (Changes
[i
].NewlinesBefore
> 0 && Changes
[i
].Tok
== C
.Tok
) {
1360 Changes
[i
].Spaces
= InitialSpaces
;
1364 if (Changes
[i
].Tok
!= C
.Tok
)
1366 Cells
.push_back(CellDescription
{i
, Cell
, i
, HasSplit
, nullptr});
1370 return linkCells({Cells
, CellCounts
, InitialSpaces
});
1373 unsigned WhitespaceManager::calculateCellWidth(unsigned Start
, unsigned End
,
1374 bool WithSpaces
) const {
1375 unsigned CellWidth
= 0;
1376 for (auto i
= Start
; i
< End
; i
++) {
1377 if (Changes
[i
].NewlinesBefore
> 0)
1379 CellWidth
+= Changes
[i
].TokenLength
;
1380 CellWidth
+= (WithSpaces
? Changes
[i
].Spaces
: 0);
1385 void WhitespaceManager::alignToStartOfCell(unsigned Start
, unsigned End
) {
1386 if ((End
- Start
) <= 1)
1388 // If the line is broken anywhere in there make sure everything
1389 // is aligned to the parent
1390 for (auto i
= Start
+ 1; i
< End
; i
++)
1391 if (Changes
[i
].NewlinesBefore
> 0)
1392 Changes
[i
].Spaces
= Changes
[Start
].Spaces
;
1395 WhitespaceManager::CellDescriptions
1396 WhitespaceManager::linkCells(CellDescriptions
&&CellDesc
) {
1397 auto &Cells
= CellDesc
.Cells
;
1398 for (auto *CellIter
= Cells
.begin(); CellIter
!= Cells
.end(); ++CellIter
) {
1399 if (!CellIter
->NextColumnElement
&& (CellIter
+ 1) != Cells
.end()) {
1400 for (auto *NextIter
= CellIter
+ 1; NextIter
!= Cells
.end(); ++NextIter
) {
1401 if (NextIter
->Cell
== CellIter
->Cell
) {
1402 CellIter
->NextColumnElement
= &(*NextIter
);
1408 return std::move(CellDesc
);
1411 void WhitespaceManager::generateChanges() {
1412 for (unsigned i
= 0, e
= Changes
.size(); i
!= e
; ++i
) {
1413 const Change
&C
= Changes
[i
];
1414 if (i
> 0 && Changes
[i
- 1].OriginalWhitespaceRange
.getBegin() ==
1415 C
.OriginalWhitespaceRange
.getBegin()) {
1416 // Do not generate two replacements for the same location.
1419 if (C
.CreateReplacement
) {
1420 std::string ReplacementText
= C
.PreviousLinePostfix
;
1421 if (C
.ContinuesPPDirective
) {
1422 appendEscapedNewlineText(ReplacementText
, C
.NewlinesBefore
,
1423 C
.PreviousEndOfTokenColumn
,
1424 C
.EscapedNewlineColumn
);
1426 appendNewlineText(ReplacementText
, C
.NewlinesBefore
);
1428 // FIXME: This assert should hold if we computed the column correctly.
1429 // assert((int)C.StartOfTokenColumn >= C.Spaces);
1431 ReplacementText
, C
.Tok
->IndentLevel
, std::max(0, C
.Spaces
),
1432 std::max((int)C
.StartOfTokenColumn
, C
.Spaces
) - std::max(0, C
.Spaces
),
1434 ReplacementText
.append(C
.CurrentLinePrefix
);
1435 storeReplacement(C
.OriginalWhitespaceRange
, ReplacementText
);
1440 void WhitespaceManager::storeReplacement(SourceRange Range
, StringRef Text
) {
1441 unsigned WhitespaceLength
= SourceMgr
.getFileOffset(Range
.getEnd()) -
1442 SourceMgr
.getFileOffset(Range
.getBegin());
1443 // Don't create a replacement, if it does not change anything.
1444 if (StringRef(SourceMgr
.getCharacterData(Range
.getBegin()),
1445 WhitespaceLength
) == Text
) {
1448 auto Err
= Replaces
.add(tooling::Replacement(
1449 SourceMgr
, CharSourceRange::getCharRange(Range
), Text
));
1450 // FIXME: better error handling. For now, just print an error message in the
1453 llvm::errs() << llvm::toString(std::move(Err
)) << "\n";
1458 void WhitespaceManager::appendNewlineText(std::string
&Text
,
1459 unsigned Newlines
) {
1461 Text
.reserve(Text
.size() + 2 * Newlines
);
1462 for (unsigned i
= 0; i
< Newlines
; ++i
)
1463 Text
.append("\r\n");
1465 Text
.append(Newlines
, '\n');
1469 void WhitespaceManager::appendEscapedNewlineText(
1470 std::string
&Text
, unsigned Newlines
, unsigned PreviousEndOfTokenColumn
,
1471 unsigned EscapedNewlineColumn
) {
1474 std::max
<int>(1, EscapedNewlineColumn
- PreviousEndOfTokenColumn
- 1);
1475 for (unsigned i
= 0; i
< Newlines
; ++i
) {
1476 Text
.append(Spaces
, ' ');
1477 Text
.append(UseCRLF
? "\\\r\n" : "\\\n");
1478 Spaces
= std::max
<int>(0, EscapedNewlineColumn
- 1);
1483 void WhitespaceManager::appendIndentText(std::string
&Text
,
1484 unsigned IndentLevel
, unsigned Spaces
,
1485 unsigned WhitespaceStartColumn
,
1487 switch (Style
.UseTab
) {
1488 case FormatStyle::UT_Never
:
1489 Text
.append(Spaces
, ' ');
1491 case FormatStyle::UT_Always
: {
1492 if (Style
.TabWidth
) {
1493 unsigned FirstTabWidth
=
1494 Style
.TabWidth
- WhitespaceStartColumn
% Style
.TabWidth
;
1496 // Insert only spaces when we want to end up before the next tab.
1497 if (Spaces
< FirstTabWidth
|| Spaces
== 1) {
1498 Text
.append(Spaces
, ' ');
1501 // Align to the next tab.
1502 Spaces
-= FirstTabWidth
;
1505 Text
.append(Spaces
/ Style
.TabWidth
, '\t');
1506 Text
.append(Spaces
% Style
.TabWidth
, ' ');
1507 } else if (Spaces
== 1) {
1508 Text
.append(Spaces
, ' ');
1512 case FormatStyle::UT_ForIndentation
:
1513 if (WhitespaceStartColumn
== 0) {
1514 unsigned Indentation
= IndentLevel
* Style
.IndentWidth
;
1515 Spaces
= appendTabIndent(Text
, Spaces
, Indentation
);
1517 Text
.append(Spaces
, ' ');
1519 case FormatStyle::UT_ForContinuationAndIndentation
:
1520 if (WhitespaceStartColumn
== 0)
1521 Spaces
= appendTabIndent(Text
, Spaces
, Spaces
);
1522 Text
.append(Spaces
, ' ');
1524 case FormatStyle::UT_AlignWithSpaces
:
1525 if (WhitespaceStartColumn
== 0) {
1526 unsigned Indentation
=
1527 IsAligned
? IndentLevel
* Style
.IndentWidth
: Spaces
;
1528 Spaces
= appendTabIndent(Text
, Spaces
, Indentation
);
1530 Text
.append(Spaces
, ' ');
1535 unsigned WhitespaceManager::appendTabIndent(std::string
&Text
, unsigned Spaces
,
1536 unsigned Indentation
) {
1537 // This happens, e.g. when a line in a block comment is indented less than the
1539 if (Indentation
> Spaces
)
1540 Indentation
= Spaces
;
1541 if (Style
.TabWidth
) {
1542 unsigned Tabs
= Indentation
/ Style
.TabWidth
;
1543 Text
.append(Tabs
, '\t');
1544 Spaces
-= Tabs
* Style
.TabWidth
;
1549 } // namespace format
1550 } // namespace clang