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