Coverage Report

Created: 2024-01-17 10:31

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