Coverage Report

Created: 2020-02-18 08:44

/Users/buildslave/jenkins/workspace/coverage/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
17
namespace clang {
18
namespace format {
19
20
bool WhitespaceManager::Change::IsBeforeInFile::operator()(
21
475k
    const Change &C1, const Change &C2) const {
22
475k
  return SourceMgr.isBeforeInTranslationUnit(
23
475k
      C1.OriginalWhitespaceRange.getBegin(),
24
475k
      C2.OriginalWhitespaceRange.getBegin());
25
475k
}
26
27
WhitespaceManager::Change::Change(const FormatToken &Tok,
28
                                  bool CreateReplacement,
29
                                  SourceRange OriginalWhitespaceRange,
30
                                  int Spaces, unsigned StartOfTokenColumn,
31
                                  unsigned NewlinesBefore,
32
                                  StringRef PreviousLinePostfix,
33
                                  StringRef CurrentLinePrefix,
34
                                  bool ContinuesPPDirective, bool IsInsideToken)
35
    : Tok(&Tok), CreateReplacement(CreateReplacement),
36
      OriginalWhitespaceRange(OriginalWhitespaceRange),
37
      StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
38
      PreviousLinePostfix(PreviousLinePostfix),
39
      CurrentLinePrefix(CurrentLinePrefix),
40
      ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces),
41
      IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0),
42
      PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
43
242k
      StartOfBlockComment(nullptr), IndentationOffset(0) {}
44
45
void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
46
                                          unsigned Spaces,
47
                                          unsigned StartOfTokenColumn,
48
219k
                                          bool InPPDirective) {
49
219k
  if (Tok.Finalized)
50
2.25k
    return;
51
217k
  Tok.Decision = (Newlines > 0) ? 
FD_Break28.2k
:
FD_Continue189k
;
52
217k
  Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange,
53
217k
                           Spaces, StartOfTokenColumn, Newlines, "", "",
54
217k
                           InPPDirective && 
!Tok.IsFirst1.65k
,
55
217k
                           /*IsInsideToken=*/false));
56
217k
}
57
58
void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
59
24.0k
                                            bool InPPDirective) {
60
24.0k
  if (Tok.Finalized)
61
24
    return;
62
24.0k
  Changes.push_back(Change(Tok, /*CreateReplacement=*/false,
63
24.0k
                           Tok.WhitespaceRange, /*Spaces=*/0,
64
24.0k
                           Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
65
24.0k
                           InPPDirective && 
!Tok.IsFirst1.86k
,
66
24.0k
                           /*IsInsideToken=*/false));
67
24.0k
}
68
69
llvm::Error
70
193
WhitespaceManager::addReplacement(const tooling::Replacement &Replacement) {
71
193
  return Replaces.add(Replacement);
72
193
}
73
74
void WhitespaceManager::replaceWhitespaceInToken(
75
    const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
76
    StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
77
1.12k
    unsigned Newlines, int Spaces) {
78
1.12k
  if (Tok.Finalized)
79
4
    return;
80
1.11k
  SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
81
1.11k
  Changes.push_back(
82
1.11k
      Change(Tok, /*CreateReplacement=*/true,
83
1.11k
             SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces,
84
1.11k
             std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,
85
1.11k
             InPPDirective && 
!Tok.IsFirst21
, /*IsInsideToken=*/true));
86
1.11k
}
87
88
14.7k
const tooling::Replacements &WhitespaceManager::generateReplacements() {
89
14.7k
  if (Changes.empty())
90
40
    return Replaces;
91
14.7k
92
14.7k
  llvm::sort(Changes, Change::IsBeforeInFile(SourceMgr));
93
14.7k
  calculateLineBreakInformation();
94
14.7k
  alignConsecutiveMacros();
95
14.7k
  alignConsecutiveDeclarations();
96
14.7k
  alignConsecutiveAssignments();
97
14.7k
  alignTrailingComments();
98
14.7k
  alignEscapedNewlines();
99
14.7k
  generateChanges();
100
14.7k
101
14.7k
  return Replaces;
102
14.7k
}
103
104
14.7k
void WhitespaceManager::calculateLineBreakInformation() {
105
14.7k
  Changes[0].PreviousEndOfTokenColumn = 0;
106
14.7k
  Change *LastOutsideTokenChange = &Changes[0];
107
242k
  for (unsigned i = 1, e = Changes.size(); i != e; 
++i228k
) {
108
228k
    SourceLocation OriginalWhitespaceStart =
109
228k
        Changes[i].OriginalWhitespaceRange.getBegin();
110
228k
    SourceLocation PreviousOriginalWhitespaceEnd =
111
228k
        Changes[i - 1].OriginalWhitespaceRange.getEnd();
112
228k
    unsigned OriginalWhitespaceStartOffset =
113
228k
        SourceMgr.getFileOffset(OriginalWhitespaceStart);
114
228k
    unsigned PreviousOriginalWhitespaceEndOffset =
115
228k
        SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd);
116
228k
    assert(PreviousOriginalWhitespaceEndOffset <=
117
228k
           OriginalWhitespaceStartOffset);
118
228k
    const char *const PreviousOriginalWhitespaceEndData =
119
228k
        SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd);
120
228k
    StringRef Text(PreviousOriginalWhitespaceEndData,
121
228k
                   SourceMgr.getCharacterData(OriginalWhitespaceStart) -
122
228k
                       PreviousOriginalWhitespaceEndData);
123
228k
    // Usually consecutive changes would occur in consecutive tokens. This is
124
228k
    // not the case however when analyzing some preprocessor runs of the
125
228k
    // annotated lines. For example, in this code:
126
228k
    //
127
228k
    // #if A // line 1
128
228k
    // int i = 1;
129
228k
    // #else B // line 2
130
228k
    // int i = 2;
131
228k
    // #endif // line 3
132
228k
    //
133
228k
    // one of the runs will produce the sequence of lines marked with line 1, 2
134
228k
    // and 3. So the two consecutive whitespace changes just before '// line 2'
135
228k
    // and before '#endif // line 3' span multiple lines and tokens:
136
228k
    //
137
228k
    // #else B{change X}[// line 2
138
228k
    // int i = 2;
139
228k
    // ]{change Y}#endif // line 3
140
228k
    //
141
228k
    // For this reason, if the text between consecutive changes spans multiple
142
228k
    // newlines, the token length must be adjusted to the end of the original
143
228k
    // line of the token.
144
228k
    auto NewlinePos = Text.find_first_of('\n');
145
228k
    if (NewlinePos == StringRef::npos) {
146
227k
      Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset -
147
227k
                                   PreviousOriginalWhitespaceEndOffset +
148
227k
                                   Changes[i].PreviousLinePostfix.size() +
149
227k
                                   Changes[i - 1].CurrentLinePrefix.size();
150
227k
    } else {
151
160
      Changes[i - 1].TokenLength =
152
160
          NewlinePos + Changes[i - 1].CurrentLinePrefix.size();
153
160
    }
154
228k
155
228k
    // If there are multiple changes in this token, sum up all the changes until
156
228k
    // the end of the line.
157
228k
    if (Changes[i - 1].IsInsideToken && 
Changes[i - 1].NewlinesBefore == 01.11k
)
158
249
      LastOutsideTokenChange->TokenLength +=
159
249
          Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
160
227k
    else
161
227k
      LastOutsideTokenChange = &Changes[i - 1];
162
228k
163
228k
    Changes[i].PreviousEndOfTokenColumn =
164
228k
        Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
165
228k
166
228k
    Changes[i - 1].IsTrailingComment =
167
228k
        (Changes[i].NewlinesBefore > 0 || 
Changes[i].Tok->is(tok::eof)194k
||
168
228k
         
(181k
Changes[i].IsInsideToken181k
&&
Changes[i].Tok->is(tok::comment)249
)) &&
169
228k
        
Changes[i - 1].Tok->is(tok::comment)46.9k
&&
170
228k
        // FIXME: This is a dirty hack. The problem is that
171
228k
        // BreakableLineCommentSection does comment reflow changes and here is
172
228k
        // the aligning of trailing comments. Consider the case where we reflow
173
228k
        // the second line up in this example:
174
228k
        //
175
228k
        // // line 1
176
228k
        // // line 2
177
228k
        //
178
228k
        // That amounts to 2 changes by BreakableLineCommentSection:
179
228k
        //  - the first, delimited by (), for the whitespace between the tokens,
180
228k
        //  - and second, delimited by [], for the whitespace at the beginning
181
228k
        //  of the second token:
182
228k
        //
183
228k
        // // line 1(
184
228k
        // )[// ]line 2
185
228k
        //
186
228k
        // So in the end we have two changes like this:
187
228k
        //
188
228k
        // // line1()[ ]line 2
189
228k
        //
190
228k
        // Note that the OriginalWhitespaceStart of the second change is the
191
228k
        // same as the PreviousOriginalWhitespaceEnd of the first change.
192
228k
        // In this case, the below check ensures that the second change doesn't
193
228k
        // get treated as a trailing comment change here, since this might
194
228k
        // trigger additional whitespace to be wrongly inserted before "line 2"
195
228k
        // by the comment aligner here.
196
228k
        //
197
228k
        // For a proper solution we need a mechanism to say to WhitespaceManager
198
228k
        // that a particular change breaks the current sequence of trailing
199
228k
        // comments.
200
228k
        
OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd4.21k
;
201
228k
  }
202
14.7k
  // FIXME: The last token is currently not always an eof token; in those
203
14.7k
  // cases, setting TokenLength of the last token to 0 is wrong.
204
14.7k
  Changes.back().TokenLength = 0;
205
14.7k
  Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);
206
14.7k
207
14.7k
  const WhitespaceManager::Change *LastBlockComment = nullptr;
208
242k
  for (auto &Change : Changes) {
209
242k
    // Reset the IsTrailingComment flag for changes inside of trailing comments
210
242k
    // so they don't get realigned later. Comment line breaks however still need
211
242k
    // to be aligned.
212
242k
    if (Change.IsInsideToken && 
Change.NewlinesBefore == 01.11k
)
213
249
      Change.IsTrailingComment = false;
214
242k
    Change.StartOfBlockComment = nullptr;
215
242k
    Change.IndentationOffset = 0;
216
242k
    if (Change.Tok->is(tok::comment)) {
217
4.60k
      if (Change.Tok->is(TT_LineComment) || 
!Change.IsInsideToken1.04k
)
218
4.11k
        LastBlockComment = &Change;
219
493
      else {
220
493
        if ((Change.StartOfBlockComment = LastBlockComment))
221
493
          Change.IndentationOffset =
222
493
              Change.StartOfTokenColumn -
223
493
              Change.StartOfBlockComment->StartOfTokenColumn;
224
493
      }
225
238k
    } else {
226
238k
      LastBlockComment = nullptr;
227
238k
    }
228
242k
  }
229
14.7k
}
230
231
// Align a single sequence of tokens, see AlignTokens below.
232
template <typename F>
233
static void
234
AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
235
503
                   SmallVector<WhitespaceManager::Change, 16> &Changes) {
236
503
  bool FoundMatchOnLine = false;
237
503
  int Shift = 0;
238
503
239
503
  // ScopeStack keeps track of the current scope depth. It contains indices of
240
503
  // the first token on each scope.
241
503
  // We only run the "Matches" function on tokens from the outer-most scope.
242
503
  // However, we do need to pay special attention to one class of tokens
243
503
  // that are not in the outer-most scope, and that is function parameters
244
503
  // which are split across multiple lines, as illustrated by this example:
245
503
  //   double a(int x);
246
503
  //   int    b(int  y,
247
503
  //          double z);
248
503
  // In the above example, we need to take special care to ensure that
249
503
  // 'double z' is indented along with it's owning function 'b'.
250
503
  SmallVector<unsigned, 16> ScopeStack;
251
503
252
6.27k
  for (unsigned i = Start; i != End; 
++i5.77k
) {
253
5.77k
    if (ScopeStack.size() != 0 &&
254
5.77k
        Changes[i].indentAndNestingLevel() <
255
1.62k
            Changes[ScopeStack.back()].indentAndNestingLevel())
256
312
      ScopeStack.pop_back();
257
5.77k
258
5.77k
    // Compare current token to previous non-comment token to ensure whether
259
5.77k
    // it is in a deeper scope or not.
260
5.77k
    unsigned PreviousNonComment = i - 1;
261
5.86k
    while (PreviousNonComment > Start &&
262
5.86k
           
Changes[PreviousNonComment].Tok->is(tok::comment)4.86k
)
263
90
      PreviousNonComment--;
264
5.77k
    if (i != Start && Changes[i].indentAndNestingLevel() >
265
5.27k
                          Changes[PreviousNonComment].indentAndNestingLevel())
266
364
      ScopeStack.push_back(i);
267
5.77k
268
5.77k
    bool InsideNestedScope = ScopeStack.size() != 0;
269
5.77k
270
5.77k
    if (Changes[i].NewlinesBefore > 0 && 
!InsideNestedScope720
) {
271
499
      Shift = 0;
272
499
      FoundMatchOnLine = false;
273
499
    }
274
5.77k
275
5.77k
    // If this is the first matching token to be aligned, remember by how many
276
5.77k
    // spaces it has to be shifted, so the rest of the changes on the line are
277
5.77k
    // shifted by the same amount
278
5.77k
    if (!FoundMatchOnLine && 
!InsideNestedScope1.91k
&&
Matches(Changes[i])1.72k
) {
279
858
      FoundMatchOnLine = true;
280
858
      Shift = Column - Changes[i].StartOfTokenColumn;
281
858
      Changes[i].Spaces += Shift;
282
858
    }
283
5.77k
284
5.77k
    // This is for function parameters that are split across multiple lines,
285
5.77k
    // as mentioned in the ScopeStack comment.
286
5.77k
    if (InsideNestedScope && 
Changes[i].NewlinesBefore > 01.67k
) {
287
221
      unsigned ScopeStart = ScopeStack.back();
288
221
      if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) ||
289
221
          (ScopeStart > Start + 1 &&
290
221
           Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)))
291
30
        Changes[i].Spaces += Shift;
292
221
    }
293
5.77k
294
5.77k
    assert(Shift >= 0);
295
5.77k
    Changes[i].StartOfTokenColumn += Shift;
296
5.77k
    if (i + 1 != Changes.size())
297
5.59k
      Changes[i + 1].PreviousEndOfTokenColumn += Shift;
298
5.77k
  }
299
503
}
WhitespaceManager.cpp:void clang::format::AlignTokenSequence<clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&>(unsigned int, unsigned int, unsigned int, clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&)
Line
Count
Source
235
253
                   SmallVector<WhitespaceManager::Change, 16> &Changes) {
236
253
  bool FoundMatchOnLine = false;
237
253
  int Shift = 0;
238
253
239
253
  // ScopeStack keeps track of the current scope depth. It contains indices of
240
253
  // the first token on each scope.
241
253
  // We only run the "Matches" function on tokens from the outer-most scope.
242
253
  // However, we do need to pay special attention to one class of tokens
243
253
  // that are not in the outer-most scope, and that is function parameters
244
253
  // which are split across multiple lines, as illustrated by this example:
245
253
  //   double a(int x);
246
253
  //   int    b(int  y,
247
253
  //          double z);
248
253
  // In the above example, we need to take special care to ensure that
249
253
  // 'double z' is indented along with it's owning function 'b'.
250
253
  SmallVector<unsigned, 16> ScopeStack;
251
253
252
2.63k
  for (unsigned i = Start; i != End; 
++i2.38k
) {
253
2.38k
    if (ScopeStack.size() != 0 &&
254
2.38k
        Changes[i].indentAndNestingLevel() <
255
532
            Changes[ScopeStack.back()].indentAndNestingLevel())
256
112
      ScopeStack.pop_back();
257
2.38k
258
2.38k
    // Compare current token to previous non-comment token to ensure whether
259
2.38k
    // it is in a deeper scope or not.
260
2.38k
    unsigned PreviousNonComment = i - 1;
261
2.43k
    while (PreviousNonComment > Start &&
262
2.43k
           
Changes[PreviousNonComment].Tok->is(tok::comment)1.93k
)
263
57
      PreviousNonComment--;
264
2.38k
    if (i != Start && Changes[i].indentAndNestingLevel() >
265
2.12k
                          Changes[PreviousNonComment].indentAndNestingLevel())
266
133
      ScopeStack.push_back(i);
267
2.38k
268
2.38k
    bool InsideNestedScope = ScopeStack.size() != 0;
269
2.38k
270
2.38k
    if (Changes[i].NewlinesBefore > 0 && 
!InsideNestedScope293
) {
271
218
      Shift = 0;
272
218
      FoundMatchOnLine = false;
273
218
    }
274
2.38k
275
2.38k
    // If this is the first matching token to be aligned, remember by how many
276
2.38k
    // spaces it has to be shifted, so the rest of the changes on the line are
277
2.38k
    // shifted by the same amount
278
2.38k
    if (!FoundMatchOnLine && 
!InsideNestedScope972
&&
Matches(Changes[i])851
) {
279
395
      FoundMatchOnLine = true;
280
395
      Shift = Column - Changes[i].StartOfTokenColumn;
281
395
      Changes[i].Spaces += Shift;
282
395
    }
283
2.38k
284
2.38k
    // This is for function parameters that are split across multiple lines,
285
2.38k
    // as mentioned in the ScopeStack comment.
286
2.38k
    if (InsideNestedScope && 
Changes[i].NewlinesBefore > 0553
) {
287
75
      unsigned ScopeStart = ScopeStack.back();
288
75
      if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) ||
289
75
          (ScopeStart > Start + 1 &&
290
75
           Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)))
291
0
        Changes[i].Spaces += Shift;
292
75
    }
293
2.38k
294
2.38k
    assert(Shift >= 0);
295
2.38k
    Changes[i].StartOfTokenColumn += Shift;
296
2.38k
    if (i + 1 != Changes.size())
297
2.29k
      Changes[i + 1].PreviousEndOfTokenColumn += Shift;
298
2.38k
  }
299
253
}
WhitespaceManager.cpp:void clang::format::AlignTokenSequence<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_2&>(unsigned int, unsigned int, unsigned int, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_2&&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&)
Line
Count
Source
235
250
                   SmallVector<WhitespaceManager::Change, 16> &Changes) {
236
250
  bool FoundMatchOnLine = false;
237
250
  int Shift = 0;
238
250
239
250
  // ScopeStack keeps track of the current scope depth. It contains indices of
240
250
  // the first token on each scope.
241
250
  // We only run the "Matches" function on tokens from the outer-most scope.
242
250
  // However, we do need to pay special attention to one class of tokens
243
250
  // that are not in the outer-most scope, and that is function parameters
244
250
  // which are split across multiple lines, as illustrated by this example:
245
250
  //   double a(int x);
246
250
  //   int    b(int  y,
247
250
  //          double z);
248
250
  // In the above example, we need to take special care to ensure that
249
250
  // 'double z' is indented along with it's owning function 'b'.
250
250
  SmallVector<unsigned, 16> ScopeStack;
251
250
252
3.64k
  for (unsigned i = Start; i != End; 
++i3.39k
) {
253
3.39k
    if (ScopeStack.size() != 0 &&
254
3.39k
        Changes[i].indentAndNestingLevel() <
255
1.09k
            Changes[ScopeStack.back()].indentAndNestingLevel())
256
200
      ScopeStack.pop_back();
257
3.39k
258
3.39k
    // Compare current token to previous non-comment token to ensure whether
259
3.39k
    // it is in a deeper scope or not.
260
3.39k
    unsigned PreviousNonComment = i - 1;
261
3.42k
    while (PreviousNonComment > Start &&
262
3.42k
           
Changes[PreviousNonComment].Tok->is(tok::comment)2.92k
)
263
33
      PreviousNonComment--;
264
3.39k
    if (i != Start && Changes[i].indentAndNestingLevel() >
265
3.14k
                          Changes[PreviousNonComment].indentAndNestingLevel())
266
231
      ScopeStack.push_back(i);
267
3.39k
268
3.39k
    bool InsideNestedScope = ScopeStack.size() != 0;
269
3.39k
270
3.39k
    if (Changes[i].NewlinesBefore > 0 && 
!InsideNestedScope427
) {
271
281
      Shift = 0;
272
281
      FoundMatchOnLine = false;
273
281
    }
274
3.39k
275
3.39k
    // If this is the first matching token to be aligned, remember by how many
276
3.39k
    // spaces it has to be shifted, so the rest of the changes on the line are
277
3.39k
    // shifted by the same amount
278
3.39k
    if (!FoundMatchOnLine && 
!InsideNestedScope939
&&
Matches(Changes[i])872
) {
279
463
      FoundMatchOnLine = true;
280
463
      Shift = Column - Changes[i].StartOfTokenColumn;
281
463
      Changes[i].Spaces += Shift;
282
463
    }
283
3.39k
284
3.39k
    // This is for function parameters that are split across multiple lines,
285
3.39k
    // as mentioned in the ScopeStack comment.
286
3.39k
    if (InsideNestedScope && 
Changes[i].NewlinesBefore > 01.12k
) {
287
146
      unsigned ScopeStart = ScopeStack.back();
288
146
      if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) ||
289
146
          (ScopeStart > Start + 1 &&
290
146
           Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)))
291
30
        Changes[i].Spaces += Shift;
292
146
    }
293
3.39k
294
3.39k
    assert(Shift >= 0);
295
3.39k
    Changes[i].StartOfTokenColumn += Shift;
296
3.39k
    if (i + 1 != Changes.size())
297
3.30k
      Changes[i + 1].PreviousEndOfTokenColumn += Shift;
298
3.39k
  }
299
250
}
300
301
// Walk through a subset of the changes, starting at StartAt, and find
302
// sequences of matching tokens to align. To do so, keep track of the lines and
303
// whether or not a matching token was found on a line. If a matching token is
304
// found, extend the current sequence. If the current line cannot be part of a
305
// sequence, e.g. because there is an empty line before it or it contains only
306
// non-matching tokens, finalize the previous sequence.
307
// The value returned is the token on which we stopped, either because we
308
// exhausted all items inside Changes, or because we hit a scope level higher
309
// than our initial scope.
310
// This function is recursive. Each invocation processes only the scope level
311
// equal to the initial level, which is the level of Changes[StartAt].
312
// If we encounter a scope level greater than the initial level, then we call
313
// ourselves recursively, thereby avoiding the pollution of the current state
314
// with the alignment requirements of the nested sub-level. This recursive
315
// behavior is necessary for aligning function prototypes that have one or more
316
// arguments.
317
// If this function encounters a scope level less than the initial level,
318
// it returns the current position.
319
// There is a non-obvious subtlety in the recursive behavior: Even though we
320
// defer processing of nested levels to recursive invocations of this
321
// function, when it comes time to align a sequence of tokens, we run the
322
// alignment on the entire sequence, including the nested levels.
323
// When doing so, most of the nested tokens are skipped, because their
324
// alignment was already handled by the recursive invocations of this function.
325
// However, the special exception is that we do NOT skip function parameters
326
// that are split across multiple lines. See the test case in FormatTest.cpp
327
// that mentions "split function parameter alignment" for an example of this.
328
template <typename F>
329
static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
330
                            SmallVector<WhitespaceManager::Change, 16> &Changes,
331
1.25k
                            unsigned StartAt) {
332
1.25k
  unsigned MinColumn = 0;
333
1.25k
  unsigned MaxColumn = UINT_MAX;
334
1.25k
335
1.25k
  // Line number of the start and the end of the current token sequence.
336
1.25k
  unsigned StartOfSequence = 0;
337
1.25k
  unsigned EndOfSequence = 0;
338
1.25k
339
1.25k
  // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
340
1.25k
  // abort when we hit any token in a higher scope than the starting one.
341
1.25k
  auto IndentAndNestingLevel = StartAt < Changes.size()
342
1.25k
                                   ? Changes[StartAt].indentAndNestingLevel()
343
1.25k
                                   : 
std::pair<unsigned, unsigned>(0, 0)0
;
344
1.25k
345
1.25k
  // Keep track of the number of commas before the matching tokens, we will only
346
1.25k
  // align a sequence of matching tokens if they are preceded by the same number
347
1.25k
  // of commas.
348
1.25k
  unsigned CommasBeforeLastMatch = 0;
349
1.25k
  unsigned CommasBeforeMatch = 0;
350
1.25k
351
1.25k
  // Whether a matching token has been found on the current line.
352
1.25k
  bool FoundMatchOnLine = false;
353
1.25k
354
1.25k
  // Aligns a sequence of matching tokens, on the MinColumn column.
355
1.25k
  //
356
1.25k
  // Sequences start from the first matching token to align, and end at the
357
1.25k
  // first token of the first line that doesn't need to be aligned.
358
1.25k
  //
359
1.25k
  // We need to adjust the StartOfTokenColumn of each Change that is on a line
360
1.25k
  // containing any matching token to be aligned and located after such token.
361
2.09k
  auto AlignCurrentSequence = [&] {
362
2.09k
    if (StartOfSequence > 0 && 
StartOfSequence < EndOfSequence530
)
363
503
      AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
364
503
                         Changes);
365
2.09k
    MinColumn = 0;
366
2.09k
    MaxColumn = UINT_MAX;
367
2.09k
    StartOfSequence = 0;
368
2.09k
    EndOfSequence = 0;
369
2.09k
  };
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int)::'lambda'()::operator()() const
Line
Count
Source
361
447
  auto AlignCurrentSequence = [&] {
362
447
    if (StartOfSequence > 0 && 
StartOfSequence < EndOfSequence144
)
363
141
      AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
364
141
                         Changes);
365
447
    MinColumn = 0;
366
447
    MaxColumn = UINT_MAX;
367
447
    StartOfSequence = 0;
368
447
    EndOfSequence = 0;
369
447
  };
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int)::'lambda'()::operator()() const
Line
Count
Source
361
621
  auto AlignCurrentSequence = [&] {
362
621
    if (StartOfSequence > 0 && 
StartOfSequence < EndOfSequence124
)
363
112
      AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
364
112
                         Changes);
365
621
    MinColumn = 0;
366
621
    MaxColumn = UINT_MAX;
367
621
    StartOfSequence = 0;
368
621
    EndOfSequence = 0;
369
621
  };
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_2>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_2&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int)::'lambda'()::operator()() const
Line
Count
Source
361
378
  auto AlignCurrentSequence = [&] {
362
378
    if (StartOfSequence > 0 && 
StartOfSequence < EndOfSequence142
)
363
142
      AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
364
142
                         Changes);
365
378
    MinColumn = 0;
366
378
    MaxColumn = UINT_MAX;
367
378
    StartOfSequence = 0;
368
378
    EndOfSequence = 0;
369
378
  };
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_2&>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_2&&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int)::'lambda'()::operator()() const
Line
Count
Source
361
650
  auto AlignCurrentSequence = [&] {
362
650
    if (StartOfSequence > 0 && 
StartOfSequence < EndOfSequence120
)
363
108
      AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
364
108
                         Changes);
365
650
    MinColumn = 0;
366
650
    MaxColumn = UINT_MAX;
367
650
    StartOfSequence = 0;
368
650
    EndOfSequence = 0;
369
650
  };
370
1.25k
371
1.25k
  unsigned i = StartAt;
372
10.5k
  for (unsigned e = Changes.size(); i != e; 
++i9.27k
) {
373
10.2k
    if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
374
941
      break;
375
9.27k
376
9.27k
    if (Changes[i].NewlinesBefore != 0) {
377
1.37k
      CommasBeforeMatch = 0;
378
1.37k
      EndOfSequence = i;
379
1.37k
      // If there is a blank line, or if the last line didn't contain any
380
1.37k
      // matching token, the sequence ends here.
381
1.37k
      if (Changes[i].NewlinesBefore > 1 || 
!FoundMatchOnLine1.36k
)
382
763
        AlignCurrentSequence();
383
1.37k
384
1.37k
      FoundMatchOnLine = false;
385
1.37k
    }
386
9.27k
387
9.27k
    if (Changes[i].Tok->is(tok::comma)) {
388
252
      ++CommasBeforeMatch;
389
9.01k
    } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
390
941
      // Call AlignTokens recursively, skipping over this scope block.
391
941
      unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i);
392
941
      i = StoppedAt - 1;
393
941
      continue;
394
941
    }
395
8.32k
396
8.32k
    if (!Matches(Changes[i]))
397
7.43k
      continue;
398
894
399
894
    // If there is more than one matching token per line, or if the number of
400
894
    // preceding commas, do not match anymore, end the sequence.
401
894
    if (FoundMatchOnLine || 
CommasBeforeMatch != CommasBeforeLastMatch858
)
402
69
      AlignCurrentSequence();
403
894
404
894
    CommasBeforeLastMatch = CommasBeforeMatch;
405
894
    FoundMatchOnLine = true;
406
894
407
894
    if (StartOfSequence == 0)
408
518
      StartOfSequence = i;
409
894
410
894
    unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
411
894
    int LineLengthAfter = -Changes[i].Spaces;
412
5.20k
    for (unsigned j = i; j != e && 
Changes[j].NewlinesBefore == 05.08k
;
++j4.31k
)
413
4.31k
      LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
414
894
    unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
415
894
416
894
    // If we are restricted by the maximum column width, end the sequence.
417
894
    if (ChangeMinColumn > MaxColumn || 
ChangeMaxColumn < MinColumn888
||
418
894
        
CommasBeforeLastMatch != CommasBeforeMatch882
) {
419
12
      AlignCurrentSequence();
420
12
      StartOfSequence = i;
421
12
    }
422
894
423
894
    MinColumn = std::max(MinColumn, ChangeMinColumn);
424
894
    MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
425
894
  }
426
1.25k
427
1.25k
  EndOfSequence = i;
428
1.25k
  AlignCurrentSequence();
429
1.25k
  return i;
430
1.25k
}
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int)
Line
Count
Source
331
151
                            unsigned StartAt) {
332
151
  unsigned MinColumn = 0;
333
151
  unsigned MaxColumn = UINT_MAX;
334
151
335
151
  // Line number of the start and the end of the current token sequence.
336
151
  unsigned StartOfSequence = 0;
337
151
  unsigned EndOfSequence = 0;
338
151
339
151
  // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
340
151
  // abort when we hit any token in a higher scope than the starting one.
341
151
  auto IndentAndNestingLevel = StartAt < Changes.size()
342
151
                                   ? Changes[StartAt].indentAndNestingLevel()
343
151
                                   : 
std::pair<unsigned, unsigned>(0, 0)0
;
344
151
345
151
  // Keep track of the number of commas before the matching tokens, we will only
346
151
  // align a sequence of matching tokens if they are preceded by the same number
347
151
  // of commas.
348
151
  unsigned CommasBeforeLastMatch = 0;
349
151
  unsigned CommasBeforeMatch = 0;
350
151
351
151
  // Whether a matching token has been found on the current line.
352
151
  bool FoundMatchOnLine = false;
353
151
354
151
  // Aligns a sequence of matching tokens, on the MinColumn column.
355
151
  //
356
151
  // Sequences start from the first matching token to align, and end at the
357
151
  // first token of the first line that doesn't need to be aligned.
358
151
  //
359
151
  // We need to adjust the StartOfTokenColumn of each Change that is on a line
360
151
  // containing any matching token to be aligned and located after such token.
361
151
  auto AlignCurrentSequence = [&] {
362
151
    if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
363
151
      AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
364
151
                         Changes);
365
151
    MinColumn = 0;
366
151
    MaxColumn = UINT_MAX;
367
151
    StartOfSequence = 0;
368
151
    EndOfSequence = 0;
369
151
  };
370
151
371
151
  unsigned i = StartAt;
372
2.53k
  for (unsigned e = Changes.size(); i != e; 
++i2.38k
) {
373
2.38k
    if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
374
0
      break;
375
2.38k
376
2.38k
    if (Changes[i].NewlinesBefore != 0) {
377
434
      CommasBeforeMatch = 0;
378
434
      EndOfSequence = i;
379
434
      // If there is a blank line, or if the last line didn't contain any
380
434
      // matching token, the sequence ends here.
381
434
      if (Changes[i].NewlinesBefore > 1 || 
!FoundMatchOnLine431
)
382
257
        AlignCurrentSequence();
383
434
384
434
      FoundMatchOnLine = false;
385
434
    }
386
2.38k
387
2.38k
    if (Changes[i].Tok->is(tok::comma)) {
388
18
      ++CommasBeforeMatch;
389
2.36k
    } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
390
266
      // Call AlignTokens recursively, skipping over this scope block.
391
266
      unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i);
392
266
      i = StoppedAt - 1;
393
266
      continue;
394
266
    }
395
2.11k
396
2.11k
    if (!Matches(Changes[i]))
397
1.87k
      continue;
398
237
399
237
    // If there is more than one matching token per line, or if the number of
400
237
    // preceding commas, do not match anymore, end the sequence.
401
237
    if (FoundMatchOnLine || 
CommasBeforeMatch != CommasBeforeLastMatch225
)
402
33
      AlignCurrentSequence();
403
237
404
237
    CommasBeforeLastMatch = CommasBeforeMatch;
405
237
    FoundMatchOnLine = true;
406
237
407
237
    if (StartOfSequence == 0)
408
138
      StartOfSequence = i;
409
237
410
237
    unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
411
237
    int LineLengthAfter = -Changes[i].Spaces;
412
1.18k
    for (unsigned j = i; j != e && 
Changes[j].NewlinesBefore == 01.13k
;
++j945
)
413
945
      LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
414
237
    unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
415
237
416
237
    // If we are restricted by the maximum column width, end the sequence.
417
237
    if (ChangeMinColumn > MaxColumn || 
ChangeMaxColumn < MinColumn234
||
418
237
        
CommasBeforeLastMatch != CommasBeforeMatch231
) {
419
6
      AlignCurrentSequence();
420
6
      StartOfSequence = i;
421
6
    }
422
237
423
237
    MinColumn = std::max(MinColumn, ChangeMinColumn);
424
237
    MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
425
237
  }
426
151
427
151
  EndOfSequence = i;
428
151
  AlignCurrentSequence();
429
151
  return i;
430
151
}
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int)
Line
Count
Source
331
453
                            unsigned StartAt) {
332
453
  unsigned MinColumn = 0;
333
453
  unsigned MaxColumn = UINT_MAX;
334
453
335
453
  // Line number of the start and the end of the current token sequence.
336
453
  unsigned StartOfSequence = 0;
337
453
  unsigned EndOfSequence = 0;
338
453
339
453
  // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
340
453
  // abort when we hit any token in a higher scope than the starting one.
341
453
  auto IndentAndNestingLevel = StartAt < Changes.size()
342
453
                                   ? Changes[StartAt].indentAndNestingLevel()
343
453
                                   : 
std::pair<unsigned, unsigned>(0, 0)0
;
344
453
345
453
  // Keep track of the number of commas before the matching tokens, we will only
346
453
  // align a sequence of matching tokens if they are preceded by the same number
347
453
  // of commas.
348
453
  unsigned CommasBeforeLastMatch = 0;
349
453
  unsigned CommasBeforeMatch = 0;
350
453
351
453
  // Whether a matching token has been found on the current line.
352
453
  bool FoundMatchOnLine = false;
353
453
354
453
  // Aligns a sequence of matching tokens, on the MinColumn column.
355
453
  //
356
453
  // Sequences start from the first matching token to align, and end at the
357
453
  // first token of the first line that doesn't need to be aligned.
358
453
  //
359
453
  // We need to adjust the StartOfTokenColumn of each Change that is on a line
360
453
  // containing any matching token to be aligned and located after such token.
361
453
  auto AlignCurrentSequence = [&] {
362
453
    if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
363
453
      AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
364
453
                         Changes);
365
453
    MinColumn = 0;
366
453
    MaxColumn = UINT_MAX;
367
453
    StartOfSequence = 0;
368
453
    EndOfSequence = 0;
369
453
  };
370
453
371
453
  unsigned i = StartAt;
372
2.62k
  for (unsigned e = Changes.size(); i != e; 
++i2.17k
) {
373
2.62k
    if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
374
453
      break;
375
2.17k
376
2.17k
    if (Changes[i].NewlinesBefore != 0) {
377
254
      CommasBeforeMatch = 0;
378
254
      EndOfSequence = i;
379
254
      // If there is a blank line, or if the last line didn't contain any
380
254
      // matching token, the sequence ends here.
381
254
      if (Changes[i].NewlinesBefore > 1 || 
!FoundMatchOnLine253
)
382
147
        AlignCurrentSequence();
383
254
384
254
      FoundMatchOnLine = false;
385
254
    }
386
2.17k
387
2.17k
    if (Changes[i].Tok->is(tok::comma)) {
388
96
      ++CommasBeforeMatch;
389
2.07k
    } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
390
187
      // Call AlignTokens recursively, skipping over this scope block.
391
187
      unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i);
392
187
      i = StoppedAt - 1;
393
187
      continue;
394
187
    }
395
1.98k
396
1.98k
    if (!Matches(Changes[i]))
397
1.80k
      continue;
398
182
399
182
    // If there is more than one matching token per line, or if the number of
400
182
    // preceding commas, do not match anymore, end the sequence.
401
182
    if (FoundMatchOnLine || 
CommasBeforeMatch != CommasBeforeLastMatch170
)
402
21
      AlignCurrentSequence();
403
182
404
182
    CommasBeforeLastMatch = CommasBeforeMatch;
405
182
    FoundMatchOnLine = true;
406
182
407
182
    if (StartOfSequence == 0)
408
124
      StartOfSequence = i;
409
182
410
182
    unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
411
182
    int LineLengthAfter = -Changes[i].Spaces;
412
1.02k
    for (unsigned j = i; j != e && 
Changes[j].NewlinesBefore == 01.01k
;
++j838
)
413
838
      LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
414
182
    unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
415
182
416
182
    // If we are restricted by the maximum column width, end the sequence.
417
182
    if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn ||
418
182
        CommasBeforeLastMatch != CommasBeforeMatch) {
419
0
      AlignCurrentSequence();
420
0
      StartOfSequence = i;
421
0
    }
422
182
423
182
    MinColumn = std::max(MinColumn, ChangeMinColumn);
424
182
    MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
425
182
  }
426
453
427
453
  EndOfSequence = i;
428
453
  AlignCurrentSequence();
429
453
  return i;
430
453
}
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_2>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_2&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int)
Line
Count
Source
331
160
                            unsigned StartAt) {
332
160
  unsigned MinColumn = 0;
333
160
  unsigned MaxColumn = UINT_MAX;
334
160
335
160
  // Line number of the start and the end of the current token sequence.
336
160
  unsigned StartOfSequence = 0;
337
160
  unsigned EndOfSequence = 0;
338
160
339
160
  // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
340
160
  // abort when we hit any token in a higher scope than the starting one.
341
160
  auto IndentAndNestingLevel = StartAt < Changes.size()
342
160
                                   ? Changes[StartAt].indentAndNestingLevel()
343
160
                                   : 
std::pair<unsigned, unsigned>(0, 0)0
;
344
160
345
160
  // Keep track of the number of commas before the matching tokens, we will only
346
160
  // align a sequence of matching tokens if they are preceded by the same number
347
160
  // of commas.
348
160
  unsigned CommasBeforeLastMatch = 0;
349
160
  unsigned CommasBeforeMatch = 0;
350
160
351
160
  // Whether a matching token has been found on the current line.
352
160
  bool FoundMatchOnLine = false;
353
160
354
160
  // Aligns a sequence of matching tokens, on the MinColumn column.
355
160
  //
356
160
  // Sequences start from the first matching token to align, and end at the
357
160
  // first token of the first line that doesn't need to be aligned.
358
160
  //
359
160
  // We need to adjust the StartOfTokenColumn of each Change that is on a line
360
160
  // containing any matching token to be aligned and located after such token.
361
160
  auto AlignCurrentSequence = [&] {
362
160
    if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
363
160
      AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
364
160
                         Changes);
365
160
    MinColumn = 0;
366
160
    MaxColumn = UINT_MAX;
367
160
    StartOfSequence = 0;
368
160
    EndOfSequence = 0;
369
160
  };
370
160
371
160
  unsigned i = StartAt;
372
2.55k
  for (unsigned e = Changes.size(); i != e; 
++i2.39k
) {
373
2.39k
    if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
374
0
      break;
375
2.39k
376
2.39k
    if (Changes[i].NewlinesBefore != 0) {
377
413
      CommasBeforeMatch = 0;
378
413
      EndOfSequence = i;
379
413
      // If there is a blank line, or if the last line didn't contain any
380
413
      // matching token, the sequence ends here.
381
413
      if (Changes[i].NewlinesBefore > 1 || 
!FoundMatchOnLine410
)
382
212
        AlignCurrentSequence();
383
413
384
413
      FoundMatchOnLine = false;
385
413
    }
386
2.39k
387
2.39k
    if (Changes[i].Tok->is(tok::comma)) {
388
18
      ++CommasBeforeMatch;
389
2.37k
    } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
390
292
      // Call AlignTokens recursively, skipping over this scope block.
391
292
      unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i);
392
292
      i = StoppedAt - 1;
393
292
      continue;
394
292
    }
395
2.10k
396
2.10k
    if (!Matches(Changes[i]))
397
1.84k
      continue;
398
255
399
255
    // If there is more than one matching token per line, or if the number of
400
255
    // preceding commas, do not match anymore, end the sequence.
401
255
    if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)
402
0
      AlignCurrentSequence();
403
255
404
255
    CommasBeforeLastMatch = CommasBeforeMatch;
405
255
    FoundMatchOnLine = true;
406
255
407
255
    if (StartOfSequence == 0)
408
136
      StartOfSequence = i;
409
255
410
255
    unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
411
255
    int LineLengthAfter = -Changes[i].Spaces;
412
1.71k
    for (unsigned j = i; j != e && 
Changes[j].NewlinesBefore == 01.66k
;
++j1.45k
)
413
1.45k
      LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
414
255
    unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
415
255
416
255
    // If we are restricted by the maximum column width, end the sequence.
417
255
    if (ChangeMinColumn > MaxColumn || 
ChangeMaxColumn < MinColumn252
||
418
255
        
CommasBeforeLastMatch != CommasBeforeMatch249
) {
419
6
      AlignCurrentSequence();
420
6
      StartOfSequence = i;
421
6
    }
422
255
423
255
    MinColumn = std::max(MinColumn, ChangeMinColumn);
424
255
    MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
425
255
  }
426
160
427
160
  EndOfSequence = i;
428
160
  AlignCurrentSequence();
429
160
  return i;
430
160
}
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_2&>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_2&&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int)
Line
Count
Source
331
488
                            unsigned StartAt) {
332
488
  unsigned MinColumn = 0;
333
488
  unsigned MaxColumn = UINT_MAX;
334
488
335
488
  // Line number of the start and the end of the current token sequence.
336
488
  unsigned StartOfSequence = 0;
337
488
  unsigned EndOfSequence = 0;
338
488
339
488
  // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
340
488
  // abort when we hit any token in a higher scope than the starting one.
341
488
  auto IndentAndNestingLevel = StartAt < Changes.size()
342
488
                                   ? Changes[StartAt].indentAndNestingLevel()
343
488
                                   : 
std::pair<unsigned, unsigned>(0, 0)0
;
344
488
345
488
  // Keep track of the number of commas before the matching tokens, we will only
346
488
  // align a sequence of matching tokens if they are preceded by the same number
347
488
  // of commas.
348
488
  unsigned CommasBeforeLastMatch = 0;
349
488
  unsigned CommasBeforeMatch = 0;
350
488
351
488
  // Whether a matching token has been found on the current line.
352
488
  bool FoundMatchOnLine = false;
353
488
354
488
  // Aligns a sequence of matching tokens, on the MinColumn column.
355
488
  //
356
488
  // Sequences start from the first matching token to align, and end at the
357
488
  // first token of the first line that doesn't need to be aligned.
358
488
  //
359
488
  // We need to adjust the StartOfTokenColumn of each Change that is on a line
360
488
  // containing any matching token to be aligned and located after such token.
361
488
  auto AlignCurrentSequence = [&] {
362
488
    if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
363
488
      AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
364
488
                         Changes);
365
488
    MinColumn = 0;
366
488
    MaxColumn = UINT_MAX;
367
488
    StartOfSequence = 0;
368
488
    EndOfSequence = 0;
369
488
  };
370
488
371
488
  unsigned i = StartAt;
372
2.80k
  for (unsigned e = Changes.size(); i != e; 
++i2.32k
) {
373
2.80k
    if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
374
488
      break;
375
2.32k
376
2.32k
    if (Changes[i].NewlinesBefore != 0) {
377
275
      CommasBeforeMatch = 0;
378
275
      EndOfSequence = i;
379
275
      // If there is a blank line, or if the last line didn't contain any
380
275
      // matching token, the sequence ends here.
381
275
      if (Changes[i].NewlinesBefore > 1 || 
!FoundMatchOnLine274
)
382
147
        AlignCurrentSequence();
383
275
384
275
      FoundMatchOnLine = false;
385
275
    }
386
2.32k
387
2.32k
    if (Changes[i].Tok->is(tok::comma)) {
388
120
      ++CommasBeforeMatch;
389
2.20k
    } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
390
196
      // Call AlignTokens recursively, skipping over this scope block.
391
196
      unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i);
392
196
      i = StoppedAt - 1;
393
196
      continue;
394
196
    }
395
2.12k
396
2.12k
    if (!Matches(Changes[i]))
397
1.90k
      continue;
398
220
399
220
    // If there is more than one matching token per line, or if the number of
400
220
    // preceding commas, do not match anymore, end the sequence.
401
220
    if (FoundMatchOnLine || 
CommasBeforeMatch != CommasBeforeLastMatch208
)
402
15
      AlignCurrentSequence();
403
220
404
220
    CommasBeforeLastMatch = CommasBeforeMatch;
405
220
    FoundMatchOnLine = true;
406
220
407
220
    if (StartOfSequence == 0)
408
120
      StartOfSequence = i;
409
220
410
220
    unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
411
220
    int LineLengthAfter = -Changes[i].Spaces;
412
1.29k
    for (unsigned j = i; j != e && 
Changes[j].NewlinesBefore == 01.27k
;
++j1.07k
)
413
1.07k
      LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
414
220
    unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
415
220
416
220
    // If we are restricted by the maximum column width, end the sequence.
417
220
    if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn ||
418
220
        CommasBeforeLastMatch != CommasBeforeMatch) {
419
0
      AlignCurrentSequence();
420
0
      StartOfSequence = i;
421
0
    }
422
220
423
220
    MinColumn = std::max(MinColumn, ChangeMinColumn);
424
220
    MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
425
220
  }
426
488
427
488
  EndOfSequence = i;
428
488
  AlignCurrentSequence();
429
488
  return i;
430
488
}
431
432
// Aligns a sequence of matching tokens, on the MinColumn column.
433
//
434
// Sequences start from the first matching token to align, and end at the
435
// first token of the first line that doesn't need to be aligned.
436
//
437
// We need to adjust the StartOfTokenColumn of each Change that is on a line
438
// containing any matching token to be aligned and located after such token.
439
static void AlignMacroSequence(
440
    unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn,
441
    unsigned &MaxColumn, bool &FoundMatchOnLine,
442
    std::function<bool(const WhitespaceManager::Change &C)> AlignMacrosMatches,
443
1.00k
    SmallVector<WhitespaceManager::Change, 16> &Changes) {
444
1.00k
  if (StartOfSequence > 0 && 
StartOfSequence < EndOfSequence15
) {
445
15
446
15
    FoundMatchOnLine = false;
447
15
    int Shift = 0;
448
15
449
459
    for (unsigned I = StartOfSequence; I != EndOfSequence; 
++I444
) {
450
444
      if (Changes[I].NewlinesBefore > 0) {
451
39
        Shift = 0;
452
39
        FoundMatchOnLine = false;
453
39
      }
454
444
455
444
      // If this is the first matching token to be aligned, remember by how many
456
444
      // spaces it has to be shifted, so the rest of the changes on the line are
457
444
      // shifted by the same amount
458
444
      if (!FoundMatchOnLine && 
AlignMacrosMatches(Changes[I])279
) {
459
51
        FoundMatchOnLine = true;
460
51
        Shift = MinColumn - Changes[I].StartOfTokenColumn;
461
51
        Changes[I].Spaces += Shift;
462
51
      }
463
444
464
444
      assert(Shift >= 0);
465
444
      Changes[I].StartOfTokenColumn += Shift;
466
444
      if (I + 1 != Changes.size())
467
432
        Changes[I + 1].PreviousEndOfTokenColumn += Shift;
468
444
    }
469
15
  }
470
1.00k
471
1.00k
  MinColumn = 0;
472
1.00k
  MaxColumn = UINT_MAX;
473
1.00k
  StartOfSequence = 0;
474
1.00k
  EndOfSequence = 0;
475
1.00k
}
476
477
14.7k
void WhitespaceManager::alignConsecutiveMacros() {
478
14.7k
  if (!Style.AlignConsecutiveMacros)
479
14.4k
    return;
480
234
481
5.96k
  
auto AlignMacrosMatches = [](const Change &C) 234
{
482
5.96k
    const FormatToken *Current = C.Tok;
483
5.96k
    unsigned SpacesRequiredBefore = 1;
484
5.96k
485
5.96k
    if (Current->SpacesRequiredBefore == 0 || 
!Current->Previous4.10k
)
486
2.99k
      return false;
487
2.97k
488
2.97k
    Current = Current->Previous;
489
2.97k
490
2.97k
    // If token is a ")", skip over the parameter list, to the
491
2.97k
    // token that precedes the "("
492
2.97k
    if (Current->is(tok::r_paren) && 
Current->MatchingParen121
) {
493
121
      Current = Current->MatchingParen->Previous;
494
121
      SpacesRequiredBefore = 0;
495
121
    }
496
2.97k
497
2.97k
    if (!Current || !Current->is(tok::identifier))
498
1.93k
      return false;
499
1.03k
500
1.03k
    if (!Current->Previous || 
!Current->Previous->is(tok::pp_define)942
)
501
930
      return false;
502
102
503
102
    // For a macro function, 0 spaces are required between the
504
102
    // identifier and the lparen that opens the parameter list.
505
102
    // For a simple macro, 1 space is required between the
506
102
    // identifier and the first token of the defined value.
507
102
    return Current->Next->SpacesRequiredBefore == SpacesRequiredBefore;
508
102
  };
509
234
510
234
  unsigned MinColumn = 0;
511
234
  unsigned MaxColumn = UINT_MAX;
512
234
513
234
  // Start and end of the token sequence we're processing.
514
234
  unsigned StartOfSequence = 0;
515
234
  unsigned EndOfSequence = 0;
516
234
517
234
  // Whether a matching token has been found on the current line.
518
234
  bool FoundMatchOnLine = false;
519
234
520
234
  unsigned I = 0;
521
5.92k
  for (unsigned E = Changes.size(); I != E; 
++I5.68k
) {
522
5.68k
    if (Changes[I].NewlinesBefore != 0) {
523
806
      EndOfSequence = I;
524
806
      // If there is a blank line, or if the last line didn't contain any
525
806
      // matching token, the sequence ends here.
526
806
      if (Changes[I].NewlinesBefore > 1 || 
!FoundMatchOnLine799
)
527
767
        AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn,
528
767
                           FoundMatchOnLine, AlignMacrosMatches, Changes);
529
806
530
806
      FoundMatchOnLine = false;
531
806
    }
532
5.68k
533
5.68k
    if (!AlignMacrosMatches(Changes[I]))
534
5.63k
      continue;
535
51
536
51
    FoundMatchOnLine = true;
537
51
538
51
    if (StartOfSequence == 0)
539
15
      StartOfSequence = I;
540
51
541
51
    unsigned ChangeMinColumn = Changes[I].StartOfTokenColumn;
542
51
    int LineLengthAfter = -Changes[I].Spaces;
543
267
    for (unsigned j = I; j != E && 
Changes[j].NewlinesBefore == 0255
;
++j216
)
544
216
      LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
545
51
    unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
546
51
547
51
    MinColumn = std::max(MinColumn, ChangeMinColumn);
548
51
    MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
549
51
  }
550
234
551
234
  EndOfSequence = I;
552
234
  AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn,
553
234
                     FoundMatchOnLine, AlignMacrosMatches, Changes);
554
234
}
555
556
14.7k
void WhitespaceManager::alignConsecutiveAssignments() {
557
14.7k
  if (!Style.AlignConsecutiveAssignments)
558
14.5k
    return;
559
151
560
151
  AlignTokens(
561
151
      Style,
562
4.95k
      [&](const Change &C) {
563
4.95k
        // Do not align on equal signs that are first on a line.
564
4.95k
        if (C.NewlinesBefore > 0)
565
815
          return false;
566
4.13k
567
4.13k
        // Do not align on equal signs that are last on a line.
568
4.13k
        if (&C != &Changes.back() && 
(&C + 1)->NewlinesBefore > 04.02k
)
569
592
          return false;
570
3.54k
571
3.54k
        return C.Tok->is(tok::equal);
572
3.54k
      },
573
151
      Changes, /*StartAt=*/0);
574
151
}
575
576
14.7k
void WhitespaceManager::alignConsecutiveDeclarations() {
577
14.7k
  if (!Style.AlignConsecutiveDeclarations)
578
14.5k
    return;
579
160
580
160
  // FIXME: Currently we don't handle properly the PointerAlignment: Right
581
160
  // The * and & are not aligned and are left dangling. Something has to be done
582
160
  // about it, but it raises the question of alignment of code like:
583
160
  //   const char* const* v1;
584
160
  //   float const* v2;
585
160
  //   SomeVeryLongType const& v3;
586
160
  AlignTokens(
587
160
      Style,
588
5.09k
      [](Change const &C) {
589
5.09k
        // tok::kw_operator is necessary for aligning operator overload
590
5.09k
        // definitions.
591
5.09k
        if (C.Tok->isOneOf(TT_FunctionDeclarationName, tok::kw_operator))
592
144
          return true;
593
4.95k
        if (C.Tok->isNot(TT_StartOfName))
594
4.15k
          return false;
595
796
        // Check if there is a subsequent name that starts the same declaration.
596
798
        
for (FormatToken *Next = C.Tok->Next; 796
Next;
Next = Next->Next2
) {
597
798
          if (Next->is(tok::comment))
598
2
            continue;
599
796
          if (!Next->Tok.getIdentifierInfo())
600
794
            break;
601
2
          if (Next->isOneOf(TT_StartOfName, TT_FunctionDeclarationName,
602
2
                            tok::kw_operator))
603
2
            return false;
604
2
        }
605
796
        
return true794
;
606
796
      },
607
160
      Changes, /*StartAt=*/0);
608
160
}
609
610
14.7k
void WhitespaceManager::alignTrailingComments() {
611
14.7k
  unsigned MinColumn = 0;
612
14.7k
  unsigned MaxColumn = UINT_MAX;
613
14.7k
  unsigned StartOfSequence = 0;
614
14.7k
  bool BreakBeforeNext = false;
615
14.7k
  unsigned Newlines = 0;
616
257k
  for (unsigned i = 0, e = Changes.size(); i != e; 
++i242k
) {
617
242k
    if (Changes[i].StartOfBlockComment)
618
493
      continue;
619
242k
    Newlines += Changes[i].NewlinesBefore;
620
242k
    if (!Changes[i].IsTrailingComment)
621
238k
      continue;
622
3.36k
623
3.36k
    unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
624
3.36k
    unsigned ChangeMaxColumn;
625
3.36k
626
3.36k
    if (Style.ColumnLimit == 0)
627
158
      ChangeMaxColumn = UINT_MAX;
628
3.36k
    else 
if (3.20k
Style.ColumnLimit >= Changes[i].TokenLength3.20k
)
629
3.16k
      ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
630
47
    else
631
47
      ChangeMaxColumn = ChangeMinColumn;
632
3.36k
633
3.36k
    // If we don't create a replacement for this change, we have to consider
634
3.36k
    // it to be immovable.
635
3.36k
    if (!Changes[i].CreateReplacement)
636
469
      ChangeMaxColumn = ChangeMinColumn;
637
3.36k
638
3.36k
    if (i + 1 != e && 
Changes[i + 1].ContinuesPPDirective3.36k
)
639
68
      ChangeMaxColumn -= 2;
640
3.36k
    // If this comment follows an } in column 0, it probably documents the
641
3.36k
    // closing of a namespace and we don't want to align it.
642
3.36k
    bool FollowsRBraceInColumn0 = i > 0 && 
Changes[i].NewlinesBefore == 03.04k
&&
643
3.36k
                                  
Changes[i - 1].Tok->is(tok::r_brace)1.76k
&&
644
3.36k
                                  
Changes[i - 1].StartOfTokenColumn == 0834
;
645
3.36k
    bool WasAlignedWithStartOfNextLine = false;
646
3.36k
    if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
647
1.24k
      unsigned CommentColumn = SourceMgr.getSpellingColumnNumber(
648
1.24k
          Changes[i].OriginalWhitespaceRange.getEnd());
649
4.72k
      for (unsigned j = i + 1; j != e; 
++j3.47k
) {
650
4.72k
        if (Changes[j].Tok->is(tok::comment))
651
3.47k
          continue;
652
1.24k
653
1.24k
        unsigned NextColumn = SourceMgr.getSpellingColumnNumber(
654
1.24k
            Changes[j].OriginalWhitespaceRange.getEnd());
655
1.24k
        // The start of the next token was previously aligned with the
656
1.24k
        // start of this comment.
657
1.24k
        WasAlignedWithStartOfNextLine =
658
1.24k
            CommentColumn == NextColumn ||
659
1.24k
            
CommentColumn == NextColumn + Style.IndentWidth595
;
660
1.24k
        break;
661
1.24k
      }
662
1.24k
    }
663
3.36k
    if (!Style.AlignTrailingComments || 
FollowsRBraceInColumn03.27k
) {
664
419
      alignTrailingComments(StartOfSequence, i, MinColumn);
665
419
      MinColumn = ChangeMinColumn;
666
419
      MaxColumn = ChangeMinColumn;
667
419
      StartOfSequence = i;
668
2.94k
    } else if (BreakBeforeNext || 
Newlines > 12.28k
||
669
2.94k
               
(1.54k
ChangeMinColumn > MaxColumn1.54k
||
ChangeMaxColumn < MinColumn1.53k
) ||
670
2.94k
               // Break the comment sequence if the previous line did not end
671
2.94k
               // in a trailing comment.
672
2.94k
               
(1.53k
Changes[i].NewlinesBefore == 11.53k
&&
i > 0395
&&
673
1.53k
                
!Changes[i - 1].IsTrailingComment392
) ||
674
2.94k
               
WasAlignedWithStartOfNextLine1.24k
) {
675
1.74k
      alignTrailingComments(StartOfSequence, i, MinColumn);
676
1.74k
      MinColumn = ChangeMinColumn;
677
1.74k
      MaxColumn = ChangeMaxColumn;
678
1.74k
      StartOfSequence = i;
679
1.74k
    } else {
680
1.20k
      MinColumn = std::max(MinColumn, ChangeMinColumn);
681
1.20k
      MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
682
1.20k
    }
683
3.36k
    BreakBeforeNext = (i == 0) || 
(Changes[i].NewlinesBefore > 1)3.04k
||
684
3.36k
                      // Never start a sequence with a comment at the beginning
685
3.36k
                      // of the line.
686
3.36k
                      
(3.00k
Changes[i].NewlinesBefore == 13.00k
&&
StartOfSequence == i1.24k
);
687
3.36k
    Newlines = 0;
688
3.36k
  }
689
14.7k
  alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
690
14.7k
}
691
692
void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
693
16.8k
                                              unsigned Column) {
694
259k
  for (unsigned i = Start; i != End; 
++i242k
) {
695
242k
    int Shift = 0;
696
242k
    if (Changes[i].IsTrailingComment) {
697
3.80k
      Shift = Column - Changes[i].StartOfTokenColumn;
698
3.80k
    }
699
242k
    if (Changes[i].StartOfBlockComment) {
700
493
      Shift = Changes[i].IndentationOffset +
701
493
              Changes[i].StartOfBlockComment->StartOfTokenColumn -
702
493
              Changes[i].StartOfTokenColumn;
703
493
    }
704
242k
    assert(Shift >= 0);
705
242k
    Changes[i].Spaces += Shift;
706
242k
    if (i + 1 != Changes.size())
707
228k
      Changes[i + 1].PreviousEndOfTokenColumn += Shift;
708
242k
    Changes[i].StartOfTokenColumn += Shift;
709
242k
  }
710
16.8k
}
711
712
14.7k
void WhitespaceManager::alignEscapedNewlines() {
713
14.7k
  if (Style.AlignEscapedNewlines == FormatStyle::ENAS_DontAlign)
714
7
    return;
715
14.6k
716
14.6k
  bool AlignLeft = Style.AlignEscapedNewlines == FormatStyle::ENAS_Left;
717
14.6k
  unsigned MaxEndOfLine = AlignLeft ? 
03.14k
:
Style.ColumnLimit11.5k
;
718
14.6k
  unsigned StartOfMacro = 0;
719
242k
  for (unsigned i = 1, e = Changes.size(); i < e; 
++i227k
) {
720
227k
    Change &C = Changes[i];
721
227k
    if (C.NewlinesBefore > 0) {
722
33.2k
      if (C.ContinuesPPDirective) {
723
583
        MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine);
724
32.6k
      } else {
725
32.6k
        alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
726
32.6k
        MaxEndOfLine = AlignLeft ? 
06.45k
:
Style.ColumnLimit26.2k
;
727
32.6k
        StartOfMacro = i;
728
32.6k
      }
729
33.2k
    }
730
227k
  }
731
14.6k
  alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
732
14.6k
}
733
734
void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End,
735
47.3k
                                             unsigned Column) {
736
242k
  for (unsigned i = Start; i < End; 
++i195k
) {
737
195k
    Change &C = Changes[i];
738
195k
    if (C.NewlinesBefore > 0) {
739
583
      assert(C.ContinuesPPDirective);
740
583
      if (C.PreviousEndOfTokenColumn + 1 > Column)
741
0
        C.EscapedNewlineColumn = 0;
742
583
      else
743
583
        C.EscapedNewlineColumn = Column;
744
583
    }
745
195k
  }
746
47.3k
}
747
748
14.7k
void WhitespaceManager::generateChanges() {
749
257k
  for (unsigned i = 0, e = Changes.size(); i != e; 
++i242k
) {
750
242k
    const Change &C = Changes[i];
751
242k
    if (i > 0) {
752
228k
      assert(Changes[i - 1].OriginalWhitespaceRange.getBegin() !=
753
228k
                 C.OriginalWhitespaceRange.getBegin() &&
754
228k
             "Generating two replacements for the same location");
755
228k
    }
756
242k
    if (C.CreateReplacement) {
757
218k
      std::string ReplacementText = C.PreviousLinePostfix;
758
218k
      if (C.ContinuesPPDirective)
759
552
        appendEscapedNewlineText(ReplacementText, C.NewlinesBefore,
760
552
                                 C.PreviousEndOfTokenColumn,
761
552
                                 C.EscapedNewlineColumn);
762
218k
      else
763
218k
        appendNewlineText(ReplacementText, C.NewlinesBefore);
764
218k
      appendIndentText(ReplacementText, C.Tok->IndentLevel,
765
218k
                       std::max(0, C.Spaces),
766
218k
                       C.StartOfTokenColumn - std::max(0, C.Spaces));
767
218k
      ReplacementText.append(C.CurrentLinePrefix);
768
218k
      storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
769
218k
    }
770
242k
  }
771
14.7k
}
772
773
218k
void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) {
774
218k
  unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) -
775
218k
                              SourceMgr.getFileOffset(Range.getBegin());
776
218k
  // Don't create a replacement, if it does not change anything.
777
218k
  if (StringRef(SourceMgr.getCharacterData(Range.getBegin()),
778
218k
                WhitespaceLength) == Text)
779
199k
    return;
780
18.9k
  auto Err = Replaces.add(tooling::Replacement(
781
18.9k
      SourceMgr, CharSourceRange::getCharRange(Range), Text));
782
18.9k
  // FIXME: better error handling. For now, just print an error message in the
783
18.9k
  // release version.
784
18.9k
  if (Err) {
785
0
    llvm::errs() << llvm::toString(std::move(Err)) << "\n";
786
0
    assert(false);
787
0
  }
788
18.9k
}
789
790
void WhitespaceManager::appendNewlineText(std::string &Text,
791
218k
                                          unsigned Newlines) {
792
247k
  for (unsigned i = 0; i < Newlines; 
++i28.9k
)
793
28.9k
    Text.append(UseCRLF ? 
"\r\n"40
:
"\n"28.8k
);
794
218k
}
795
796
void WhitespaceManager::appendEscapedNewlineText(
797
    std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn,
798
552
    unsigned EscapedNewlineColumn) {
799
552
  if (Newlines > 0) {
800
549
    unsigned Spaces =
801
549
        std::max<int>(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1);
802
1.10k
    for (unsigned i = 0; i < Newlines; 
++i554
) {
803
554
      Text.append(Spaces, ' ');
804
554
      Text.append(UseCRLF ? 
"\\\r\n"7
:
"\\\n"547
);
805
554
      Spaces = std::max<int>(0, EscapedNewlineColumn - 1);
806
554
    }
807
549
  }
808
552
}
809
810
void WhitespaceManager::appendIndentText(std::string &Text,
811
                                         unsigned IndentLevel, unsigned Spaces,
812
218k
                                         unsigned WhitespaceStartColumn) {
813
218k
  switch (Style.UseTab) {
814
217k
  case FormatStyle::UT_Never:
815
217k
    Text.append(Spaces, ' ');
816
217k
    break;
817
481
  case FormatStyle::UT_Always: {
818
481
    if (Style.TabWidth) {
819
463
      unsigned FirstTabWidth =
820
463
          Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
821
463
822
463
      // Insert only spaces when we want to end up before the next tab.
823
463
      if (Spaces < FirstTabWidth || 
Spaces == 1116
) {
824
368
        Text.append(Spaces, ' ');
825
368
        break;
826
368
      }
827
95
      // Align to the next tab.
828
95
      Spaces -= FirstTabWidth;
829
95
      Text.append("\t");
830
95
831
95
      Text.append(Spaces / Style.TabWidth, '\t');
832
95
      Text.append(Spaces % Style.TabWidth, ' ');
833
95
    } else 
if (18
Spaces == 118
) {
834
2
      Text.append(Spaces, ' ');
835
2
    }
836
481
    
break113
;
837
481
  }
838
481
  case FormatStyle::UT_ForIndentation:
839
304
    if (WhitespaceStartColumn == 0) {
840
144
      unsigned Indentation = IndentLevel * Style.IndentWidth;
841
144
      // This happens, e.g. when a line in a block comment is indented less than
842
144
      // the first one.
843
144
      if (Indentation > Spaces)
844
2
        Indentation = Spaces;
845
144
      if (Style.TabWidth) {
846
136
        unsigned Tabs = Indentation / Style.TabWidth;
847
136
        Text.append(Tabs, '\t');
848
136
        Spaces -= Tabs * Style.TabWidth;
849
136
      }
850
144
    }
851
304
    Text.append(Spaces, ' ');
852
304
    break;
853
722
  case FormatStyle::UT_ForContinuationAndIndentation:
854
722
    if (WhitespaceStartColumn == 0 && 
Style.TabWidth305
) {
855
297
      unsigned Tabs = Spaces / Style.TabWidth;
856
297
      Text.append(Tabs, '\t');
857
297
      Spaces -= Tabs * Style.TabWidth;
858
297
    }
859
722
    Text.append(Spaces, ' ');
860
722
    break;
861
218k
  }
862
218k
}
863
864
} // namespace format
865
} // namespace clang