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