/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 | | #include "llvm/ADT/SmallVector.h" |
17 | | #include <algorithm> |
18 | | |
19 | | namespace clang { |
20 | | namespace format { |
21 | | |
22 | | bool WhitespaceManager::Change::IsBeforeInFile::operator()( |
23 | 739k | const Change &C1, const Change &C2) const { |
24 | 739k | return SourceMgr.isBeforeInTranslationUnit( |
25 | 739k | C1.OriginalWhitespaceRange.getBegin(), |
26 | 739k | C2.OriginalWhitespaceRange.getBegin()); |
27 | 739k | } |
28 | | |
29 | | WhitespaceManager::Change::Change(const FormatToken &Tok, |
30 | | bool CreateReplacement, |
31 | | SourceRange OriginalWhitespaceRange, |
32 | | int Spaces, unsigned StartOfTokenColumn, |
33 | | unsigned NewlinesBefore, |
34 | | StringRef PreviousLinePostfix, |
35 | | StringRef CurrentLinePrefix, bool IsAligned, |
36 | | bool ContinuesPPDirective, bool IsInsideToken) |
37 | | : Tok(&Tok), CreateReplacement(CreateReplacement), |
38 | | OriginalWhitespaceRange(OriginalWhitespaceRange), |
39 | | StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore), |
40 | | PreviousLinePostfix(PreviousLinePostfix), |
41 | | CurrentLinePrefix(CurrentLinePrefix), IsAligned(IsAligned), |
42 | | ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces), |
43 | | IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0), |
44 | | PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0), |
45 | 376k | StartOfBlockComment(nullptr), IndentationOffset(0), ConditionalsLevel(0) { |
46 | 376k | } |
47 | | |
48 | | void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines, |
49 | | unsigned Spaces, |
50 | | unsigned StartOfTokenColumn, |
51 | 355k | bool IsAligned, bool InPPDirective) { |
52 | 355k | if (Tok.Finalized) |
53 | 4.33k | return; |
54 | 351k | Tok.setDecision((Newlines > 0) ? FD_Break44.8k : FD_Continue306k ); |
55 | 351k | Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange, |
56 | 351k | Spaces, StartOfTokenColumn, Newlines, "", "", |
57 | 351k | IsAligned, InPPDirective && !Tok.IsFirst2.00k , |
58 | 351k | /*IsInsideToken=*/false)); |
59 | 351k | } |
60 | | |
61 | | void WhitespaceManager::addUntouchableToken(const FormatToken &Tok, |
62 | 24.1k | bool InPPDirective) { |
63 | 24.1k | if (Tok.Finalized) |
64 | 24 | return; |
65 | 24.1k | Changes.push_back(Change(Tok, /*CreateReplacement=*/false, |
66 | 24.1k | Tok.WhitespaceRange, /*Spaces=*/0, |
67 | 24.1k | Tok.OriginalColumn, Tok.NewlinesBefore, "", "", |
68 | 24.1k | /*IsAligned=*/false, InPPDirective && !Tok.IsFirst1.86k , |
69 | 24.1k | /*IsInsideToken=*/false)); |
70 | 24.1k | } |
71 | | |
72 | | llvm::Error |
73 | 196 | WhitespaceManager::addReplacement(const tooling::Replacement &Replacement) { |
74 | 196 | return Replaces.add(Replacement); |
75 | 196 | } |
76 | | |
77 | 22.6k | bool WhitespaceManager::inputUsesCRLF(StringRef Text, bool DefaultToCRLF) { |
78 | 22.6k | size_t LF = Text.count('\n'); |
79 | 22.6k | size_t CR = Text.count('\r') * 2; |
80 | 22.6k | return LF == CR ? DefaultToCRLF14.5k : CR > LF8.11k ; |
81 | 22.6k | } |
82 | | |
83 | | void WhitespaceManager::replaceWhitespaceInToken( |
84 | | const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, |
85 | | StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, |
86 | 1.75k | unsigned Newlines, int Spaces) { |
87 | 1.75k | if (Tok.Finalized) |
88 | 4 | return; |
89 | 1.74k | SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset); |
90 | 1.74k | Changes.push_back( |
91 | 1.74k | Change(Tok, /*CreateReplacement=*/true, |
92 | 1.74k | SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces, |
93 | 1.74k | std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix, |
94 | 1.74k | /*IsAligned=*/true, InPPDirective && !Tok.IsFirst21 , |
95 | 1.74k | /*IsInsideToken=*/true)); |
96 | 1.74k | } |
97 | | |
98 | 22.6k | const tooling::Replacements &WhitespaceManager::generateReplacements() { |
99 | 22.6k | if (Changes.empty()) |
100 | 72 | return Replaces; |
101 | | |
102 | 22.5k | llvm::sort(Changes, Change::IsBeforeInFile(SourceMgr)); |
103 | 22.5k | calculateLineBreakInformation(); |
104 | 22.5k | alignConsecutiveMacros(); |
105 | 22.5k | alignConsecutiveDeclarations(); |
106 | 22.5k | alignConsecutiveBitFields(); |
107 | 22.5k | alignConsecutiveAssignments(); |
108 | 22.5k | alignChainedConditionals(); |
109 | 22.5k | alignTrailingComments(); |
110 | 22.5k | alignEscapedNewlines(); |
111 | 22.5k | alignArrayInitializers(); |
112 | 22.5k | generateChanges(); |
113 | | |
114 | 22.5k | return Replaces; |
115 | 22.6k | } |
116 | | |
117 | 22.5k | void WhitespaceManager::calculateLineBreakInformation() { |
118 | 22.5k | Changes[0].PreviousEndOfTokenColumn = 0; |
119 | 22.5k | Change *LastOutsideTokenChange = &Changes[0]; |
120 | 376k | for (unsigned i = 1, e = Changes.size(); i != e; ++i354k ) { |
121 | 354k | SourceLocation OriginalWhitespaceStart = |
122 | 354k | Changes[i].OriginalWhitespaceRange.getBegin(); |
123 | 354k | SourceLocation PreviousOriginalWhitespaceEnd = |
124 | 354k | Changes[i - 1].OriginalWhitespaceRange.getEnd(); |
125 | 354k | unsigned OriginalWhitespaceStartOffset = |
126 | 354k | SourceMgr.getFileOffset(OriginalWhitespaceStart); |
127 | 354k | unsigned PreviousOriginalWhitespaceEndOffset = |
128 | 354k | SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd); |
129 | 354k | assert(PreviousOriginalWhitespaceEndOffset <= |
130 | 354k | OriginalWhitespaceStartOffset); |
131 | 0 | const char *const PreviousOriginalWhitespaceEndData = |
132 | 354k | SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd); |
133 | 354k | StringRef Text(PreviousOriginalWhitespaceEndData, |
134 | 354k | SourceMgr.getCharacterData(OriginalWhitespaceStart) - |
135 | 354k | PreviousOriginalWhitespaceEndData); |
136 | | // Usually consecutive changes would occur in consecutive tokens. This is |
137 | | // not the case however when analyzing some preprocessor runs of the |
138 | | // annotated lines. For example, in this code: |
139 | | // |
140 | | // #if A // line 1 |
141 | | // int i = 1; |
142 | | // #else B // line 2 |
143 | | // int i = 2; |
144 | | // #endif // line 3 |
145 | | // |
146 | | // one of the runs will produce the sequence of lines marked with line 1, 2 |
147 | | // and 3. So the two consecutive whitespace changes just before '// line 2' |
148 | | // and before '#endif // line 3' span multiple lines and tokens: |
149 | | // |
150 | | // #else B{change X}[// line 2 |
151 | | // int i = 2; |
152 | | // ]{change Y}#endif // line 3 |
153 | | // |
154 | | // For this reason, if the text between consecutive changes spans multiple |
155 | | // newlines, the token length must be adjusted to the end of the original |
156 | | // line of the token. |
157 | 354k | auto NewlinePos = Text.find_first_of('\n'); |
158 | 354k | if (NewlinePos == StringRef::npos) { |
159 | 353k | Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset - |
160 | 353k | PreviousOriginalWhitespaceEndOffset + |
161 | 353k | Changes[i].PreviousLinePostfix.size() + |
162 | 353k | Changes[i - 1].CurrentLinePrefix.size(); |
163 | 353k | } else { |
164 | 424 | Changes[i - 1].TokenLength = |
165 | 424 | NewlinePos + Changes[i - 1].CurrentLinePrefix.size(); |
166 | 424 | } |
167 | | |
168 | | // If there are multiple changes in this token, sum up all the changes until |
169 | | // the end of the line. |
170 | 354k | if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 01.74k ) { |
171 | 469 | LastOutsideTokenChange->TokenLength += |
172 | 469 | Changes[i - 1].TokenLength + Changes[i - 1].Spaces; |
173 | 353k | } else { |
174 | 353k | LastOutsideTokenChange = &Changes[i - 1]; |
175 | 353k | } |
176 | | |
177 | 354k | Changes[i].PreviousEndOfTokenColumn = |
178 | 354k | Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength; |
179 | | |
180 | 354k | Changes[i - 1].IsTrailingComment = |
181 | 354k | (Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof)304k || |
182 | 354k | (283k Changes[i].IsInsideToken283k && Changes[i].Tok->is(tok::comment)469 )) && |
183 | 354k | Changes[i - 1].Tok->is(tok::comment)71.2k && |
184 | | // FIXME: This is a dirty hack. The problem is that |
185 | | // BreakableLineCommentSection does comment reflow changes and here is |
186 | | // the aligning of trailing comments. Consider the case where we reflow |
187 | | // the second line up in this example: |
188 | | // |
189 | | // // line 1 |
190 | | // // line 2 |
191 | | // |
192 | | // That amounts to 2 changes by BreakableLineCommentSection: |
193 | | // - the first, delimited by (), for the whitespace between the tokens, |
194 | | // - and second, delimited by [], for the whitespace at the beginning |
195 | | // of the second token: |
196 | | // |
197 | | // // line 1( |
198 | | // )[// ]line 2 |
199 | | // |
200 | | // So in the end we have two changes like this: |
201 | | // |
202 | | // // line1()[ ]line 2 |
203 | | // |
204 | | // Note that the OriginalWhitespaceStart of the second change is the |
205 | | // same as the PreviousOriginalWhitespaceEnd of the first change. |
206 | | // In this case, the below check ensures that the second change doesn't |
207 | | // get treated as a trailing comment change here, since this might |
208 | | // trigger additional whitespace to be wrongly inserted before "line 2" |
209 | | // by the comment aligner here. |
210 | | // |
211 | | // For a proper solution we need a mechanism to say to WhitespaceManager |
212 | | // that a particular change breaks the current sequence of trailing |
213 | | // comments. |
214 | 354k | OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd6.45k ; |
215 | 354k | } |
216 | | // FIXME: The last token is currently not always an eof token; in those |
217 | | // cases, setting TokenLength of the last token to 0 is wrong. |
218 | 22.5k | Changes.back().TokenLength = 0; |
219 | 22.5k | Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment); |
220 | | |
221 | 22.5k | const WhitespaceManager::Change *LastBlockComment = nullptr; |
222 | 376k | for (auto &Change : Changes) { |
223 | | // Reset the IsTrailingComment flag for changes inside of trailing comments |
224 | | // so they don't get realigned later. Comment line breaks however still need |
225 | | // to be aligned. |
226 | 376k | if (Change.IsInsideToken && Change.NewlinesBefore == 01.74k ) |
227 | 469 | Change.IsTrailingComment = false; |
228 | 376k | Change.StartOfBlockComment = nullptr; |
229 | 376k | Change.IndentationOffset = 0; |
230 | 376k | if (Change.Tok->is(tok::comment)) { |
231 | 7.10k | if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken1.75k ) { |
232 | 6.38k | LastBlockComment = &Change; |
233 | 6.38k | } else if (714 (Change.StartOfBlockComment = LastBlockComment)714 ) { |
234 | 714 | Change.IndentationOffset = |
235 | 714 | Change.StartOfTokenColumn - |
236 | 714 | Change.StartOfBlockComment->StartOfTokenColumn; |
237 | 714 | } |
238 | 369k | } else { |
239 | 369k | LastBlockComment = nullptr; |
240 | 369k | } |
241 | 376k | } |
242 | | |
243 | | // Compute conditional nesting level |
244 | | // Level is increased for each conditional, unless this conditional continues |
245 | | // a chain of conditional, i.e. starts immediately after the colon of another |
246 | | // conditional. |
247 | 22.5k | SmallVector<bool, 16> ScopeStack; |
248 | 22.5k | int ConditionalsLevel = 0; |
249 | 376k | for (auto &Change : Changes) { |
250 | 404k | for (unsigned i = 0, e = Change.Tok->FakeLParens.size(); i != e; ++i28.0k ) { |
251 | 28.0k | bool isNestedConditional = |
252 | 28.0k | Change.Tok->FakeLParens[e - 1 - i] == prec::Conditional && |
253 | 28.0k | !(768 i == 0768 && Change.Tok->Previous764 && |
254 | 768 | Change.Tok->Previous->is(TT_ConditionalExpr)737 && |
255 | 768 | Change.Tok->Previous->is(tok::colon)209 ); |
256 | 28.0k | if (isNestedConditional) |
257 | 580 | ++ConditionalsLevel; |
258 | 28.0k | ScopeStack.push_back(isNestedConditional); |
259 | 28.0k | } |
260 | | |
261 | 376k | Change.ConditionalsLevel = ConditionalsLevel; |
262 | | |
263 | 402k | for (unsigned i = Change.Tok->FakeRParens; i > 0 && ScopeStack.size()26.0k ; --i25.9k ) |
264 | 25.9k | if (ScopeStack.pop_back_val()) |
265 | 565 | --ConditionalsLevel; |
266 | 376k | } |
267 | 22.5k | } |
268 | | |
269 | | // Align a single sequence of tokens, see AlignTokens below. |
270 | | // Column - The token for which Matches returns true is moved to this column. |
271 | | // RightJustify - Whether it is the token's right end or left end that gets |
272 | | // moved to that column. |
273 | | template <typename F> |
274 | | static void |
275 | | AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, |
276 | | unsigned Column, bool RightJustify, F &&Matches, |
277 | 2.17k | SmallVector<WhitespaceManager::Change, 16> &Changes) { |
278 | 2.17k | bool FoundMatchOnLine = false; |
279 | 2.17k | int Shift = 0; |
280 | | |
281 | | // ScopeStack keeps track of the current scope depth. It contains indices of |
282 | | // the first token on each scope. |
283 | | // We only run the "Matches" function on tokens from the outer-most scope. |
284 | | // However, we do need to pay special attention to one class of tokens |
285 | | // that are not in the outer-most scope, and that is function parameters |
286 | | // which are split across multiple lines, as illustrated by this example: |
287 | | // double a(int x); |
288 | | // int b(int y, |
289 | | // double z); |
290 | | // In the above example, we need to take special care to ensure that |
291 | | // 'double z' is indented along with it's owning function 'b'. |
292 | | // The same holds for calling a function: |
293 | | // double a = foo(x); |
294 | | // int b = bar(foo(y), |
295 | | // foor(z)); |
296 | | // Similar for broken string literals: |
297 | | // double x = 3.14; |
298 | | // auto s = "Hello" |
299 | | // "World"; |
300 | | // Special handling is required for 'nested' ternary operators. |
301 | 2.17k | SmallVector<unsigned, 16> ScopeStack; |
302 | | |
303 | 28.7k | for (unsigned i = Start; i != End; ++i26.5k ) { |
304 | 26.5k | if (ScopeStack.size() != 0 && |
305 | 26.5k | Changes[i].indentAndNestingLevel() < |
306 | 10.8k | Changes[ScopeStack.back()].indentAndNestingLevel()) { |
307 | 1.96k | ScopeStack.pop_back(); |
308 | 1.96k | } |
309 | | |
310 | | // Compare current token to previous non-comment token to ensure whether |
311 | | // it is in a deeper scope or not. |
312 | 26.5k | unsigned PreviousNonComment = i - 1; |
313 | 26.8k | while (PreviousNonComment > Start && |
314 | 26.8k | Changes[PreviousNonComment].Tok->is(tok::comment)22.5k ) { |
315 | 282 | --PreviousNonComment; |
316 | 282 | } |
317 | 26.5k | if (i != Start && Changes[i].indentAndNestingLevel() > |
318 | 24.4k | Changes[PreviousNonComment].indentAndNestingLevel()) { |
319 | 2.15k | ScopeStack.push_back(i); |
320 | 2.15k | } |
321 | | |
322 | 26.5k | bool InsideNestedScope = ScopeStack.size() != 0; |
323 | 26.5k | bool ContinuedStringLiteral = i > Start && |
324 | 26.5k | Changes[i].Tok->is(tok::string_literal)24.4k && |
325 | 26.5k | Changes[i - 1].Tok->is(tok::string_literal)357 ; |
326 | 26.5k | bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral15.5k ; |
327 | | |
328 | 26.5k | if (Changes[i].NewlinesBefore > 0 && !SkipMatchCheck3.10k ) { |
329 | 1.99k | Shift = 0; |
330 | 1.99k | FoundMatchOnLine = false; |
331 | 1.99k | } |
332 | | |
333 | | // If this is the first matching token to be aligned, remember by how many |
334 | | // spaces it has to be shifted, so the rest of the changes on the line are |
335 | | // shifted by the same amount |
336 | 26.5k | if (!FoundMatchOnLine && !SkipMatchCheck7.53k && Matches(Changes[i])7.09k ) { |
337 | 3.70k | FoundMatchOnLine = true; |
338 | 3.70k | Shift = Column - (RightJustify ? Changes[i].TokenLength758 : 02.94k ) - |
339 | 3.70k | Changes[i].StartOfTokenColumn; |
340 | 3.70k | Changes[i].Spaces += Shift; |
341 | | // FIXME: This is a workaround that should be removed when we fix |
342 | | // http://llvm.org/PR53699. An assertion later below verifies this. |
343 | 3.70k | if (Changes[i].NewlinesBefore == 0) { |
344 | 3.31k | Changes[i].Spaces = |
345 | 3.31k | std::max(Changes[i].Spaces, |
346 | 3.31k | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore)); |
347 | 3.31k | } |
348 | 3.70k | } |
349 | | |
350 | | // This is for function parameters that are split across multiple lines, |
351 | | // as mentioned in the ScopeStack comment. |
352 | 26.5k | if (InsideNestedScope && Changes[i].NewlinesBefore > 011.0k ) { |
353 | 1.08k | unsigned ScopeStart = ScopeStack.back(); |
354 | 1.08k | auto ShouldShiftBeAdded = [&] { |
355 | | // Function declaration |
356 | 1.08k | if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName)) |
357 | 0 | return true; |
358 | | |
359 | | // Lambda. |
360 | 1.08k | if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace)) |
361 | 93 | return false; |
362 | | |
363 | | // Continued function declaration |
364 | 989 | if (ScopeStart > Start + 1 && |
365 | 989 | Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)962 ) { |
366 | 30 | return true; |
367 | 30 | } |
368 | | |
369 | | // Continued function call |
370 | 959 | if (ScopeStart > Start + 1 && |
371 | 959 | Changes[ScopeStart - 2].Tok->is(tok::identifier)932 && |
372 | 959 | Changes[ScopeStart - 1].Tok->is(tok::l_paren)238 && |
373 | 959 | Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)126 ) { |
374 | 123 | if (Changes[i].Tok->MatchingParen && |
375 | 123 | Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)9 ) { |
376 | 6 | return false; |
377 | 6 | } |
378 | 117 | if (Changes[ScopeStart].NewlinesBefore > 0) |
379 | 39 | return false; |
380 | 78 | if (Changes[i].Tok->is(tok::l_brace) && |
381 | 78 | Changes[i].Tok->is(BK_BracedInit)3 ) { |
382 | 3 | return true; |
383 | 3 | } |
384 | 75 | return Style.BinPackArguments; |
385 | 78 | } |
386 | | |
387 | | // Ternary operator |
388 | 836 | if (Changes[i].Tok->is(TT_ConditionalExpr)) |
389 | 66 | return true; |
390 | | |
391 | | // Period Initializer .XXX = 1. |
392 | 770 | if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) |
393 | 36 | return true; |
394 | | |
395 | | // Continued ternary operator |
396 | 734 | if (Changes[i].Tok->Previous && |
397 | 734 | Changes[i].Tok->Previous->is(TT_ConditionalExpr)486 ) { |
398 | 48 | return true; |
399 | 48 | } |
400 | | |
401 | | // Continued direct-list-initialization using braced list. |
402 | 686 | if (ScopeStart > Start + 1 && |
403 | 686 | Changes[ScopeStart - 2].Tok->is(tok::identifier)683 && |
404 | 686 | Changes[ScopeStart - 1].Tok->is(tok::l_brace)109 && |
405 | 686 | Changes[i].Tok->is(tok::l_brace)99 && |
406 | 686 | Changes[i].Tok->is(BK_BracedInit)21 ) { |
407 | 21 | return true; |
408 | 21 | } |
409 | | |
410 | | // Continued braced list. |
411 | 665 | if (ScopeStart > Start + 1 && |
412 | 665 | Changes[ScopeStart - 2].Tok->isNot(tok::identifier)662 && |
413 | 665 | Changes[ScopeStart - 1].Tok->is(tok::l_brace)574 && |
414 | 665 | Changes[i].Tok->isNot(tok::r_brace)538 ) { |
415 | 536 | for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { |
416 | | // Lambda. |
417 | 536 | if (OuterScopeStart > Start && |
418 | 536 | Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) { |
419 | 3 | return false; |
420 | 3 | } |
421 | 536 | } |
422 | 488 | if (Changes[ScopeStart].NewlinesBefore > 0) |
423 | 458 | return false; |
424 | 30 | return true; |
425 | 488 | } |
426 | | |
427 | 174 | return false; |
428 | 665 | }; WhitespaceManager.cpp:void clang::format::AlignTokenSequence<clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&>(clang::format::FormatStyle const&, unsigned int, unsigned int, unsigned int, bool, clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&)::'lambda'()::operator()() const Line | Count | Source | 354 | 356 | auto ShouldShiftBeAdded = [&] { | 355 | | // Function declaration | 356 | 356 | if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName)) | 357 | 0 | return true; | 358 | | | 359 | | // Lambda. | 360 | 356 | if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace)) | 361 | 54 | return false; | 362 | | | 363 | | // Continued function declaration | 364 | 302 | if (ScopeStart > Start + 1 && | 365 | 302 | Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) { | 366 | 0 | return true; | 367 | 0 | } | 368 | | | 369 | | // Continued function call | 370 | 302 | if (ScopeStart > Start + 1 && | 371 | 302 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 372 | 302 | Changes[ScopeStart - 1].Tok->is(tok::l_paren)115 && | 373 | 302 | Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)54 ) { | 374 | 51 | if (Changes[i].Tok->MatchingParen && | 375 | 51 | Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)6 ) { | 376 | 3 | return false; | 377 | 3 | } | 378 | 48 | if (Changes[ScopeStart].NewlinesBefore > 0) | 379 | 15 | return false; | 380 | 33 | if (Changes[i].Tok->is(tok::l_brace) && | 381 | 33 | Changes[i].Tok->is(BK_BracedInit)3 ) { | 382 | 3 | return true; | 383 | 3 | } | 384 | 30 | return Style.BinPackArguments; | 385 | 33 | } | 386 | | | 387 | | // Ternary operator | 388 | 251 | if (Changes[i].Tok->is(TT_ConditionalExpr)) | 389 | 0 | return true; | 390 | | | 391 | | // Period Initializer .XXX = 1. | 392 | 251 | if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) | 393 | 12 | return true; | 394 | | | 395 | | // Continued ternary operator | 396 | 239 | if (Changes[i].Tok->Previous && | 397 | 239 | Changes[i].Tok->Previous->is(TT_ConditionalExpr)218 ) { | 398 | 0 | return true; | 399 | 0 | } | 400 | | | 401 | | // Continued direct-list-initialization using braced list. | 402 | 239 | if (ScopeStart > Start + 1 && | 403 | 239 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 404 | 239 | Changes[ScopeStart - 1].Tok->is(tok::l_brace)64 && | 405 | 239 | Changes[i].Tok->is(tok::l_brace)57 && | 406 | 239 | Changes[i].Tok->is(BK_BracedInit)9 ) { | 407 | 9 | return true; | 408 | 9 | } | 409 | | | 410 | | // Continued braced list. | 411 | 230 | if (ScopeStart > Start + 1 && | 412 | 230 | Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && | 413 | 230 | Changes[ScopeStart - 1].Tok->is(tok::l_brace)175 && | 414 | 230 | Changes[i].Tok->isNot(tok::r_brace)157 ) { | 415 | 156 | for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { | 416 | | // Lambda. | 417 | 156 | if (OuterScopeStart > Start && | 418 | 156 | Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) { | 419 | 3 | return false; | 420 | 3 | } | 421 | 156 | } | 422 | 132 | if (Changes[ScopeStart].NewlinesBefore > 0) | 423 | 117 | return false; | 424 | 15 | return true; | 425 | 132 | } | 426 | | | 427 | 95 | return false; | 428 | 230 | }; |
Unexecuted instantiation: WhitespaceManager.cpp:void clang::format::AlignTokenSequence<clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2&>(clang::format::FormatStyle const&, unsigned int, unsigned int, unsigned int, bool, clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&)::'lambda'()::operator()() const WhitespaceManager.cpp:void clang::format::AlignTokenSequence<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3&>(clang::format::FormatStyle const&, unsigned int, unsigned int, unsigned int, bool, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&)::'lambda'()::operator()() const Line | Count | Source | 354 | 577 | auto ShouldShiftBeAdded = [&] { | 355 | | // Function declaration | 356 | 577 | if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName)) | 357 | 0 | return true; | 358 | | | 359 | | // Lambda. | 360 | 577 | if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace)) | 361 | 36 | return false; | 362 | | | 363 | | // Continued function declaration | 364 | 541 | if (ScopeStart > Start + 1 && | 365 | 541 | Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) { | 366 | 30 | return true; | 367 | 30 | } | 368 | | | 369 | | // Continued function call | 370 | 511 | if (ScopeStart > Start + 1 && | 371 | 511 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 372 | 511 | Changes[ScopeStart - 1].Tok->is(tok::l_paren)96 && | 373 | 511 | Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)54 ) { | 374 | 54 | if (Changes[i].Tok->MatchingParen && | 375 | 54 | Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)3 ) { | 376 | 3 | return false; | 377 | 3 | } | 378 | 51 | if (Changes[ScopeStart].NewlinesBefore > 0) | 379 | 6 | return false; | 380 | 45 | if (Changes[i].Tok->is(tok::l_brace) && | 381 | 45 | Changes[i].Tok->is(BK_BracedInit)0 ) { | 382 | 0 | return true; | 383 | 0 | } | 384 | 45 | return Style.BinPackArguments; | 385 | 45 | } | 386 | | | 387 | | // Ternary operator | 388 | 457 | if (Changes[i].Tok->is(TT_ConditionalExpr)) | 389 | 0 | return true; | 390 | | | 391 | | // Period Initializer .XXX = 1. | 392 | 457 | if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) | 393 | 24 | return true; | 394 | | | 395 | | // Continued ternary operator | 396 | 433 | if (Changes[i].Tok->Previous && | 397 | 433 | Changes[i].Tok->Previous->is(TT_ConditionalExpr)208 ) { | 398 | 0 | return true; | 399 | 0 | } | 400 | | | 401 | | // Continued direct-list-initialization using braced list. | 402 | 433 | if (ScopeStart > Start + 1 && | 403 | 433 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 404 | 433 | Changes[ScopeStart - 1].Tok->is(tok::l_brace)42 && | 405 | 433 | Changes[i].Tok->is(tok::l_brace)42 && | 406 | 433 | Changes[i].Tok->is(BK_BracedInit)12 ) { | 407 | 12 | return true; | 408 | 12 | } | 409 | | | 410 | | // Continued braced list. | 411 | 421 | if (ScopeStart > Start + 1 && | 412 | 421 | Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && | 413 | 421 | Changes[ScopeStart - 1].Tok->is(tok::l_brace)391 && | 414 | 421 | Changes[i].Tok->isNot(tok::r_brace)373 ) { | 415 | 372 | for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { | 416 | | // Lambda. | 417 | 372 | if (OuterScopeStart > Start && | 418 | 372 | Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) { | 419 | 0 | return false; | 420 | 0 | } | 421 | 372 | } | 422 | 348 | if (Changes[ScopeStart].NewlinesBefore > 0) | 423 | 339 | return false; | 424 | 9 | return true; | 425 | 348 | } | 426 | | | 427 | 73 | return false; | 428 | 421 | }; |
WhitespaceManager.cpp:void clang::format::AlignTokenSequence<clang::format::WhitespaceManager::alignChainedConditionals()::$_4&>(clang::format::FormatStyle const&, unsigned int, unsigned int, unsigned int, bool, clang::format::WhitespaceManager::alignChainedConditionals()::$_4&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&)::'lambda'()::operator()() const Line | Count | Source | 354 | 87 | auto ShouldShiftBeAdded = [&] { | 355 | | // Function declaration | 356 | 87 | if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName)) | 357 | 0 | return true; | 358 | | | 359 | | // Lambda. | 360 | 87 | if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace)) | 361 | 3 | return false; | 362 | | | 363 | | // Continued function declaration | 364 | 84 | if (ScopeStart > Start + 1 && | 365 | 84 | Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)72 ) { | 366 | 0 | return true; | 367 | 0 | } | 368 | | | 369 | | // Continued function call | 370 | 84 | if (ScopeStart > Start + 1 && | 371 | 84 | Changes[ScopeStart - 2].Tok->is(tok::identifier)72 && | 372 | 84 | Changes[ScopeStart - 1].Tok->is(tok::l_paren)18 && | 373 | 84 | Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)9 ) { | 374 | 9 | if (Changes[i].Tok->MatchingParen && | 375 | 9 | Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)0 ) { | 376 | 0 | return false; | 377 | 0 | } | 378 | 9 | if (Changes[ScopeStart].NewlinesBefore > 0) | 379 | 9 | return false; | 380 | 0 | if (Changes[i].Tok->is(tok::l_brace) && | 381 | 0 | Changes[i].Tok->is(BK_BracedInit)) { | 382 | 0 | return true; | 383 | 0 | } | 384 | 0 | return Style.BinPackArguments; | 385 | 0 | } | 386 | | | 387 | | // Ternary operator | 388 | 75 | if (Changes[i].Tok->is(TT_ConditionalExpr)) | 389 | 66 | return true; | 390 | | | 391 | | // Period Initializer .XXX = 1. | 392 | 9 | if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) | 393 | 0 | return true; | 394 | | | 395 | | // Continued ternary operator | 396 | 9 | if (Changes[i].Tok->Previous && | 397 | 9 | Changes[i].Tok->Previous->is(TT_ConditionalExpr)) { | 398 | 0 | return true; | 399 | 0 | } | 400 | | | 401 | | // Continued direct-list-initialization using braced list. | 402 | 9 | if (ScopeStart > Start + 1 && | 403 | 9 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 404 | 9 | Changes[ScopeStart - 1].Tok->is(tok::l_brace)3 && | 405 | 9 | Changes[i].Tok->is(tok::l_brace)0 && | 406 | 9 | Changes[i].Tok->is(BK_BracedInit)0 ) { | 407 | 0 | return true; | 408 | 0 | } | 409 | | | 410 | | // Continued braced list. | 411 | 9 | if (ScopeStart > Start + 1 && | 412 | 9 | Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && | 413 | 9 | Changes[ScopeStart - 1].Tok->is(tok::l_brace)6 && | 414 | 9 | Changes[i].Tok->isNot(tok::r_brace)6 ) { | 415 | 6 | for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { | 416 | | // Lambda. | 417 | 6 | if (OuterScopeStart > Start && | 418 | 6 | Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) { | 419 | 0 | return false; | 420 | 0 | } | 421 | 6 | } | 422 | 6 | if (Changes[ScopeStart].NewlinesBefore > 0) | 423 | 0 | return false; | 424 | 6 | return true; | 425 | 6 | } | 426 | | | 427 | 3 | return false; | 428 | 9 | }; |
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>&)::'lambda'()::operator()() const Line | Count | Source | 354 | 62 | auto ShouldShiftBeAdded = [&] { | 355 | | // Function declaration | 356 | 62 | if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName)) | 357 | 0 | return true; | 358 | | | 359 | | // Lambda. | 360 | 62 | if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace)) | 361 | 0 | return false; | 362 | | | 363 | | // Continued function declaration | 364 | 62 | if (ScopeStart > Start + 1 && | 365 | 62 | Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)47 ) { | 366 | 0 | return true; | 367 | 0 | } | 368 | | | 369 | | // Continued function call | 370 | 62 | if (ScopeStart > Start + 1 && | 371 | 62 | Changes[ScopeStart - 2].Tok->is(tok::identifier)47 && | 372 | 62 | Changes[ScopeStart - 1].Tok->is(tok::l_paren)9 && | 373 | 62 | Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)9 ) { | 374 | 9 | if (Changes[i].Tok->MatchingParen && | 375 | 9 | Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)0 ) { | 376 | 0 | return false; | 377 | 0 | } | 378 | 9 | if (Changes[ScopeStart].NewlinesBefore > 0) | 379 | 9 | return false; | 380 | 0 | if (Changes[i].Tok->is(tok::l_brace) && | 381 | 0 | Changes[i].Tok->is(BK_BracedInit)) { | 382 | 0 | return true; | 383 | 0 | } | 384 | 0 | return Style.BinPackArguments; | 385 | 0 | } | 386 | | | 387 | | // Ternary operator | 388 | 53 | if (Changes[i].Tok->is(TT_ConditionalExpr)) | 389 | 0 | return true; | 390 | | | 391 | | // Period Initializer .XXX = 1. | 392 | 53 | if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) | 393 | 0 | return true; | 394 | | | 395 | | // Continued ternary operator | 396 | 53 | if (Changes[i].Tok->Previous && | 397 | 53 | Changes[i].Tok->Previous->is(TT_ConditionalExpr)51 ) { | 398 | 48 | return true; | 399 | 48 | } | 400 | | | 401 | | // Continued direct-list-initialization using braced list. | 402 | 5 | if (ScopeStart > Start + 1 && | 403 | 5 | Changes[ScopeStart - 2].Tok->is(tok::identifier)2 && | 404 | 5 | Changes[ScopeStart - 1].Tok->is(tok::l_brace)0 && | 405 | 5 | Changes[i].Tok->is(tok::l_brace)0 && | 406 | 5 | Changes[i].Tok->is(BK_BracedInit)0 ) { | 407 | 0 | return true; | 408 | 0 | } | 409 | | | 410 | | // Continued braced list. | 411 | 5 | if (ScopeStart > Start + 1 && | 412 | 5 | Changes[ScopeStart - 2].Tok->isNot(tok::identifier)2 && | 413 | 5 | Changes[ScopeStart - 1].Tok->is(tok::l_brace)2 && | 414 | 5 | Changes[i].Tok->isNot(tok::r_brace)2 ) { | 415 | 2 | for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { | 416 | | // Lambda. | 417 | 2 | if (OuterScopeStart > Start && | 418 | 2 | Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) { | 419 | 0 | return false; | 420 | 0 | } | 421 | 2 | } | 422 | 2 | if (Changes[ScopeStart].NewlinesBefore > 0) | 423 | 2 | return false; | 424 | 0 | return true; | 425 | 2 | } | 426 | | | 427 | 3 | return false; | 428 | 5 | }; |
|
429 | | |
430 | 1.08k | if (ShouldShiftBeAdded()) |
431 | 309 | Changes[i].Spaces += Shift; |
432 | 1.08k | } |
433 | | |
434 | 26.5k | if (ContinuedStringLiteral) |
435 | 45 | Changes[i].Spaces += Shift; |
436 | | |
437 | | // We should not remove required spaces unless we break the line before. |
438 | 26.5k | assert(Shift >= 0 || Changes[i].NewlinesBefore > 0 || |
439 | 26.5k | Changes[i].Spaces >= |
440 | 26.5k | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) || |
441 | 26.5k | Changes[i].Tok->is(tok::eof)); |
442 | | |
443 | 0 | Changes[i].StartOfTokenColumn += Shift; |
444 | 26.5k | if (i + 1 != Changes.size()) |
445 | 25.9k | Changes[i + 1].PreviousEndOfTokenColumn += Shift; |
446 | | |
447 | | // If PointerAlignment is PAS_Right, keep *s or &s next to the token |
448 | 26.5k | if (Style.PointerAlignment == FormatStyle::PAS_Right && |
449 | 26.5k | Changes[i].Spaces != 022.2k ) { |
450 | 12.4k | for (int Previous = i - 1; |
451 | 12.4k | Previous >= 0 && |
452 | 12.4k | Changes[Previous].Tok->getType() == TT_PointerOrReference; |
453 | 12.4k | --Previous77 ) { |
454 | 77 | Changes[Previous + 1].Spaces -= Shift; |
455 | 77 | Changes[Previous].Spaces += Shift; |
456 | 77 | Changes[Previous].StartOfTokenColumn += Shift; |
457 | 77 | } |
458 | 12.4k | } |
459 | 26.5k | } |
460 | 2.17k | } WhitespaceManager.cpp:void clang::format::AlignTokenSequence<clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&>(clang::format::FormatStyle const&, unsigned int, unsigned int, unsigned int, bool, clang::format::WhitespaceManager::alignConsecutiveAssignments()::$_1&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&) Line | Count | Source | 277 | 706 | SmallVector<WhitespaceManager::Change, 16> &Changes) { | 278 | 706 | bool FoundMatchOnLine = false; | 279 | 706 | int Shift = 0; | 280 | | | 281 | | // ScopeStack keeps track of the current scope depth. It contains indices of | 282 | | // the first token on each scope. | 283 | | // We only run the "Matches" function on tokens from the outer-most scope. | 284 | | // However, we do need to pay special attention to one class of tokens | 285 | | // that are not in the outer-most scope, and that is function parameters | 286 | | // which are split across multiple lines, as illustrated by this example: | 287 | | // double a(int x); | 288 | | // int b(int y, | 289 | | // double z); | 290 | | // In the above example, we need to take special care to ensure that | 291 | | // 'double z' is indented along with it's owning function 'b'. | 292 | | // The same holds for calling a function: | 293 | | // double a = foo(x); | 294 | | // int b = bar(foo(y), | 295 | | // foor(z)); | 296 | | // Similar for broken string literals: | 297 | | // double x = 3.14; | 298 | | // auto s = "Hello" | 299 | | // "World"; | 300 | | // Special handling is required for 'nested' ternary operators. | 301 | 706 | SmallVector<unsigned, 16> ScopeStack; | 302 | | | 303 | 10.3k | for (unsigned i = Start; i != End; ++i9.66k ) { | 304 | 9.66k | if (ScopeStack.size() != 0 && | 305 | 9.66k | Changes[i].indentAndNestingLevel() < | 306 | 3.77k | Changes[ScopeStack.back()].indentAndNestingLevel()) { | 307 | 764 | ScopeStack.pop_back(); | 308 | 764 | } | 309 | | | 310 | | // Compare current token to previous non-comment token to ensure whether | 311 | | // it is in a deeper scope or not. | 312 | 9.66k | unsigned PreviousNonComment = i - 1; | 313 | 9.82k | while (PreviousNonComment > Start && | 314 | 9.82k | Changes[PreviousNonComment].Tok->is(tok::comment)8.41k ) { | 315 | 166 | --PreviousNonComment; | 316 | 166 | } | 317 | 9.66k | if (i != Start && Changes[i].indentAndNestingLevel() > | 318 | 8.95k | Changes[PreviousNonComment].indentAndNestingLevel()) { | 319 | 821 | ScopeStack.push_back(i); | 320 | 821 | } | 321 | | | 322 | 9.66k | bool InsideNestedScope = ScopeStack.size() != 0; | 323 | 9.66k | bool ContinuedStringLiteral = i > Start && | 324 | 9.66k | Changes[i].Tok->is(tok::string_literal)8.95k && | 325 | 9.66k | Changes[i - 1].Tok->is(tok::string_literal)150 ; | 326 | 9.66k | bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral5.83k ; | 327 | | | 328 | 9.66k | if (Changes[i].NewlinesBefore > 0 && !SkipMatchCheck1.06k ) { | 329 | 699 | Shift = 0; | 330 | 699 | FoundMatchOnLine = false; | 331 | 699 | } | 332 | | | 333 | | // If this is the first matching token to be aligned, remember by how many | 334 | | // spaces it has to be shifted, so the rest of the changes on the line are | 335 | | // shifted by the same amount | 336 | 9.66k | if (!FoundMatchOnLine && !SkipMatchCheck3.12k && Matches(Changes[i])2.83k ) { | 337 | 1.20k | FoundMatchOnLine = true; | 338 | 1.20k | Shift = Column - (RightJustify ? Changes[i].TokenLength758 : 0444 ) - | 339 | 1.20k | Changes[i].StartOfTokenColumn; | 340 | 1.20k | Changes[i].Spaces += Shift; | 341 | | // FIXME: This is a workaround that should be removed when we fix | 342 | | // http://llvm.org/PR53699. An assertion later below verifies this. | 343 | 1.20k | if (Changes[i].NewlinesBefore == 0) { | 344 | 1.20k | Changes[i].Spaces = | 345 | 1.20k | std::max(Changes[i].Spaces, | 346 | 1.20k | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore)); | 347 | 1.20k | } | 348 | 1.20k | } | 349 | | | 350 | | // This is for function parameters that are split across multiple lines, | 351 | | // as mentioned in the ScopeStack comment. | 352 | 9.66k | if (InsideNestedScope && Changes[i].NewlinesBefore > 03.83k ) { | 353 | 356 | unsigned ScopeStart = ScopeStack.back(); | 354 | 356 | auto ShouldShiftBeAdded = [&] { | 355 | | // Function declaration | 356 | 356 | if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName)) | 357 | 356 | return true; | 358 | | | 359 | | // Lambda. | 360 | 356 | if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace)) | 361 | 356 | return false; | 362 | | | 363 | | // Continued function declaration | 364 | 356 | if (ScopeStart > Start + 1 && | 365 | 356 | Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) { | 366 | 356 | return true; | 367 | 356 | } | 368 | | | 369 | | // Continued function call | 370 | 356 | if (ScopeStart > Start + 1 && | 371 | 356 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 372 | 356 | Changes[ScopeStart - 1].Tok->is(tok::l_paren) && | 373 | 356 | Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) { | 374 | 356 | if (Changes[i].Tok->MatchingParen && | 375 | 356 | Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)) { | 376 | 356 | return false; | 377 | 356 | } | 378 | 356 | if (Changes[ScopeStart].NewlinesBefore > 0) | 379 | 356 | return false; | 380 | 356 | if (Changes[i].Tok->is(tok::l_brace) && | 381 | 356 | Changes[i].Tok->is(BK_BracedInit)) { | 382 | 356 | return true; | 383 | 356 | } | 384 | 356 | return Style.BinPackArguments; | 385 | 356 | } | 386 | | | 387 | | // Ternary operator | 388 | 356 | if (Changes[i].Tok->is(TT_ConditionalExpr)) | 389 | 356 | return true; | 390 | | | 391 | | // Period Initializer .XXX = 1. | 392 | 356 | if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) | 393 | 356 | return true; | 394 | | | 395 | | // Continued ternary operator | 396 | 356 | if (Changes[i].Tok->Previous && | 397 | 356 | Changes[i].Tok->Previous->is(TT_ConditionalExpr)) { | 398 | 356 | return true; | 399 | 356 | } | 400 | | | 401 | | // Continued direct-list-initialization using braced list. | 402 | 356 | if (ScopeStart > Start + 1 && | 403 | 356 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 404 | 356 | Changes[ScopeStart - 1].Tok->is(tok::l_brace) && | 405 | 356 | Changes[i].Tok->is(tok::l_brace) && | 406 | 356 | Changes[i].Tok->is(BK_BracedInit)) { | 407 | 356 | return true; | 408 | 356 | } | 409 | | | 410 | | // Continued braced list. | 411 | 356 | if (ScopeStart > Start + 1 && | 412 | 356 | Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && | 413 | 356 | Changes[ScopeStart - 1].Tok->is(tok::l_brace) && | 414 | 356 | Changes[i].Tok->isNot(tok::r_brace)) { | 415 | 356 | for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { | 416 | | // Lambda. | 417 | 356 | if (OuterScopeStart > Start && | 418 | 356 | Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) { | 419 | 356 | return false; | 420 | 356 | } | 421 | 356 | } | 422 | 356 | if (Changes[ScopeStart].NewlinesBefore > 0) | 423 | 356 | return false; | 424 | 356 | return true; | 425 | 356 | } | 426 | | | 427 | 356 | return false; | 428 | 356 | }; | 429 | | | 430 | 356 | if (ShouldShiftBeAdded()) | 431 | 69 | Changes[i].Spaces += Shift; | 432 | 356 | } | 433 | | | 434 | 9.66k | if (ContinuedStringLiteral) | 435 | 15 | Changes[i].Spaces += Shift; | 436 | | | 437 | | // We should not remove required spaces unless we break the line before. | 438 | 9.66k | assert(Shift >= 0 || Changes[i].NewlinesBefore > 0 || | 439 | 9.66k | Changes[i].Spaces >= | 440 | 9.66k | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) || | 441 | 9.66k | Changes[i].Tok->is(tok::eof)); | 442 | | | 443 | 0 | Changes[i].StartOfTokenColumn += Shift; | 444 | 9.66k | if (i + 1 != Changes.size()) | 445 | 9.35k | Changes[i + 1].PreviousEndOfTokenColumn += Shift; | 446 | | | 447 | | // If PointerAlignment is PAS_Right, keep *s or &s next to the token | 448 | 9.66k | if (Style.PointerAlignment == FormatStyle::PAS_Right && | 449 | 9.66k | Changes[i].Spaces != 09.18k ) { | 450 | 4.55k | for (int Previous = i - 1; | 451 | 4.55k | Previous >= 0 && | 452 | 4.55k | Changes[Previous].Tok->getType() == TT_PointerOrReference; | 453 | 4.55k | --Previous0 ) { | 454 | 0 | Changes[Previous + 1].Spaces -= Shift; | 455 | 0 | Changes[Previous].Spaces += Shift; | 456 | 0 | Changes[Previous].StartOfTokenColumn += Shift; | 457 | 0 | } | 458 | 4.55k | } | 459 | 9.66k | } | 460 | 706 | } |
WhitespaceManager.cpp:void clang::format::AlignTokenSequence<clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2&>(clang::format::FormatStyle const&, unsigned int, unsigned int, unsigned int, bool, clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&) Line | Count | Source | 277 | 36 | SmallVector<WhitespaceManager::Change, 16> &Changes) { | 278 | 36 | bool FoundMatchOnLine = false; | 279 | 36 | int Shift = 0; | 280 | | | 281 | | // ScopeStack keeps track of the current scope depth. It contains indices of | 282 | | // the first token on each scope. | 283 | | // We only run the "Matches" function on tokens from the outer-most scope. | 284 | | // However, we do need to pay special attention to one class of tokens | 285 | | // that are not in the outer-most scope, and that is function parameters | 286 | | // which are split across multiple lines, as illustrated by this example: | 287 | | // double a(int x); | 288 | | // int b(int y, | 289 | | // double z); | 290 | | // In the above example, we need to take special care to ensure that | 291 | | // 'double z' is indented along with it's owning function 'b'. | 292 | | // The same holds for calling a function: | 293 | | // double a = foo(x); | 294 | | // int b = bar(foo(y), | 295 | | // foor(z)); | 296 | | // Similar for broken string literals: | 297 | | // double x = 3.14; | 298 | | // auto s = "Hello" | 299 | | // "World"; | 300 | | // Special handling is required for 'nested' ternary operators. | 301 | 36 | SmallVector<unsigned, 16> ScopeStack; | 302 | | | 303 | 439 | for (unsigned i = Start; i != End; ++i403 ) { | 304 | 403 | if (ScopeStack.size() != 0 && | 305 | 403 | Changes[i].indentAndNestingLevel() < | 306 | 6 | Changes[ScopeStack.back()].indentAndNestingLevel()) { | 307 | 3 | ScopeStack.pop_back(); | 308 | 3 | } | 309 | | | 310 | | // Compare current token to previous non-comment token to ensure whether | 311 | | // it is in a deeper scope or not. | 312 | 403 | unsigned PreviousNonComment = i - 1; | 313 | 413 | while (PreviousNonComment > Start && | 314 | 413 | Changes[PreviousNonComment].Tok->is(tok::comment)341 ) { | 315 | 10 | --PreviousNonComment; | 316 | 10 | } | 317 | 403 | if (i != Start && Changes[i].indentAndNestingLevel() > | 318 | 367 | Changes[PreviousNonComment].indentAndNestingLevel()) { | 319 | 3 | ScopeStack.push_back(i); | 320 | 3 | } | 321 | | | 322 | 403 | bool InsideNestedScope = ScopeStack.size() != 0; | 323 | 403 | bool ContinuedStringLiteral = i > Start && | 324 | 403 | Changes[i].Tok->is(tok::string_literal)367 && | 325 | 403 | Changes[i - 1].Tok->is(tok::string_literal)0 ; | 326 | 403 | bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral397 ; | 327 | | | 328 | 403 | if (Changes[i].NewlinesBefore > 0 && !SkipMatchCheck43 ) { | 329 | 43 | Shift = 0; | 330 | 43 | FoundMatchOnLine = false; | 331 | 43 | } | 332 | | | 333 | | // If this is the first matching token to be aligned, remember by how many | 334 | | // spaces it has to be shifted, so the rest of the changes on the line are | 335 | | // shifted by the same amount | 336 | 403 | if (!FoundMatchOnLine && !SkipMatchCheck157 && Matches(Changes[i])157 ) { | 337 | 75 | FoundMatchOnLine = true; | 338 | 75 | Shift = Column - (RightJustify ? Changes[i].TokenLength0 : 0) - | 339 | 75 | Changes[i].StartOfTokenColumn; | 340 | 75 | Changes[i].Spaces += Shift; | 341 | | // FIXME: This is a workaround that should be removed when we fix | 342 | | // http://llvm.org/PR53699. An assertion later below verifies this. | 343 | 75 | if (Changes[i].NewlinesBefore == 0) { | 344 | 75 | Changes[i].Spaces = | 345 | 75 | std::max(Changes[i].Spaces, | 346 | 75 | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore)); | 347 | 75 | } | 348 | 75 | } | 349 | | | 350 | | // This is for function parameters that are split across multiple lines, | 351 | | // as mentioned in the ScopeStack comment. | 352 | 403 | if (InsideNestedScope && Changes[i].NewlinesBefore > 06 ) { | 353 | 0 | unsigned ScopeStart = ScopeStack.back(); | 354 | 0 | auto ShouldShiftBeAdded = [&] { | 355 | | // Function declaration | 356 | 0 | if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName)) | 357 | 0 | return true; | 358 | | | 359 | | // Lambda. | 360 | 0 | if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace)) | 361 | 0 | return false; | 362 | | | 363 | | // Continued function declaration | 364 | 0 | if (ScopeStart > Start + 1 && | 365 | 0 | Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) { | 366 | 0 | return true; | 367 | 0 | } | 368 | | | 369 | | // Continued function call | 370 | 0 | if (ScopeStart > Start + 1 && | 371 | 0 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 372 | 0 | Changes[ScopeStart - 1].Tok->is(tok::l_paren) && | 373 | 0 | Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) { | 374 | 0 | if (Changes[i].Tok->MatchingParen && | 375 | 0 | Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)) { | 376 | 0 | return false; | 377 | 0 | } | 378 | 0 | if (Changes[ScopeStart].NewlinesBefore > 0) | 379 | 0 | return false; | 380 | 0 | if (Changes[i].Tok->is(tok::l_brace) && | 381 | 0 | Changes[i].Tok->is(BK_BracedInit)) { | 382 | 0 | return true; | 383 | 0 | } | 384 | 0 | return Style.BinPackArguments; | 385 | 0 | } | 386 | | | 387 | | // Ternary operator | 388 | 0 | if (Changes[i].Tok->is(TT_ConditionalExpr)) | 389 | 0 | return true; | 390 | | | 391 | | // Period Initializer .XXX = 1. | 392 | 0 | if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) | 393 | 0 | return true; | 394 | | | 395 | | // Continued ternary operator | 396 | 0 | if (Changes[i].Tok->Previous && | 397 | 0 | Changes[i].Tok->Previous->is(TT_ConditionalExpr)) { | 398 | 0 | return true; | 399 | 0 | } | 400 | | | 401 | | // Continued direct-list-initialization using braced list. | 402 | 0 | if (ScopeStart > Start + 1 && | 403 | 0 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 404 | 0 | Changes[ScopeStart - 1].Tok->is(tok::l_brace) && | 405 | 0 | Changes[i].Tok->is(tok::l_brace) && | 406 | 0 | Changes[i].Tok->is(BK_BracedInit)) { | 407 | 0 | return true; | 408 | 0 | } | 409 | | | 410 | | // Continued braced list. | 411 | 0 | if (ScopeStart > Start + 1 && | 412 | 0 | Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && | 413 | 0 | Changes[ScopeStart - 1].Tok->is(tok::l_brace) && | 414 | 0 | Changes[i].Tok->isNot(tok::r_brace)) { | 415 | 0 | for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { | 416 | | // Lambda. | 417 | 0 | if (OuterScopeStart > Start && | 418 | 0 | Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) { | 419 | 0 | return false; | 420 | 0 | } | 421 | 0 | } | 422 | 0 | if (Changes[ScopeStart].NewlinesBefore > 0) | 423 | 0 | return false; | 424 | 0 | return true; | 425 | 0 | } | 426 | |
| 427 | 0 | return false; | 428 | 0 | }; | 429 | |
| 430 | 0 | if (ShouldShiftBeAdded()) | 431 | 0 | Changes[i].Spaces += Shift; | 432 | 0 | } | 433 | | | 434 | 403 | if (ContinuedStringLiteral) | 435 | 0 | Changes[i].Spaces += Shift; | 436 | | | 437 | | // We should not remove required spaces unless we break the line before. | 438 | 403 | assert(Shift >= 0 || Changes[i].NewlinesBefore > 0 || | 439 | 403 | Changes[i].Spaces >= | 440 | 403 | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) || | 441 | 403 | Changes[i].Tok->is(tok::eof)); | 442 | | | 443 | 0 | Changes[i].StartOfTokenColumn += Shift; | 444 | 403 | if (i + 1 != Changes.size()) | 445 | 367 | Changes[i + 1].PreviousEndOfTokenColumn += Shift; | 446 | | | 447 | | // If PointerAlignment is PAS_Right, keep *s or &s next to the token | 448 | 403 | if (Style.PointerAlignment == FormatStyle::PAS_Right && | 449 | 403 | Changes[i].Spaces != 0) { | 450 | 225 | for (int Previous = i - 1; | 451 | 225 | Previous >= 0 && | 452 | 225 | Changes[Previous].Tok->getType() == TT_PointerOrReference; | 453 | 225 | --Previous0 ) { | 454 | 0 | Changes[Previous + 1].Spaces -= Shift; | 455 | 0 | Changes[Previous].Spaces += Shift; | 456 | 0 | Changes[Previous].StartOfTokenColumn += Shift; | 457 | 0 | } | 458 | 225 | } | 459 | 403 | } | 460 | 36 | } |
WhitespaceManager.cpp:void clang::format::AlignTokenSequence<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3&>(clang::format::FormatStyle const&, unsigned int, unsigned int, unsigned int, bool, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&) Line | Count | Source | 277 | 830 | SmallVector<WhitespaceManager::Change, 16> &Changes) { | 278 | 830 | bool FoundMatchOnLine = false; | 279 | 830 | int Shift = 0; | 280 | | | 281 | | // ScopeStack keeps track of the current scope depth. It contains indices of | 282 | | // the first token on each scope. | 283 | | // We only run the "Matches" function on tokens from the outer-most scope. | 284 | | // However, we do need to pay special attention to one class of tokens | 285 | | // that are not in the outer-most scope, and that is function parameters | 286 | | // which are split across multiple lines, as illustrated by this example: | 287 | | // double a(int x); | 288 | | // int b(int y, | 289 | | // double z); | 290 | | // In the above example, we need to take special care to ensure that | 291 | | // 'double z' is indented along with it's owning function 'b'. | 292 | | // The same holds for calling a function: | 293 | | // double a = foo(x); | 294 | | // int b = bar(foo(y), | 295 | | // foor(z)); | 296 | | // Similar for broken string literals: | 297 | | // double x = 3.14; | 298 | | // auto s = "Hello" | 299 | | // "World"; | 300 | | // Special handling is required for 'nested' ternary operators. | 301 | 830 | SmallVector<unsigned, 16> ScopeStack; | 302 | | | 303 | 13.9k | for (unsigned i = Start; i != End; ++i13.0k ) { | 304 | 13.0k | if (ScopeStack.size() != 0 && | 305 | 13.0k | Changes[i].indentAndNestingLevel() < | 306 | 6.26k | Changes[ScopeStack.back()].indentAndNestingLevel()) { | 307 | 1.06k | ScopeStack.pop_back(); | 308 | 1.06k | } | 309 | | | 310 | | // Compare current token to previous non-comment token to ensure whether | 311 | | // it is in a deeper scope or not. | 312 | 13.0k | unsigned PreviousNonComment = i - 1; | 313 | 13.1k | while (PreviousNonComment > Start && | 314 | 13.1k | Changes[PreviousNonComment].Tok->is(tok::comment)11.5k ) { | 315 | 94 | --PreviousNonComment; | 316 | 94 | } | 317 | 13.0k | if (i != Start && Changes[i].indentAndNestingLevel() > | 318 | 12.2k | Changes[PreviousNonComment].indentAndNestingLevel()) { | 319 | 1.16k | ScopeStack.push_back(i); | 320 | 1.16k | } | 321 | | | 322 | 13.0k | bool InsideNestedScope = ScopeStack.size() != 0; | 323 | 13.0k | bool ContinuedStringLiteral = i > Start && | 324 | 13.0k | Changes[i].Tok->is(tok::string_literal)12.2k && | 325 | 13.0k | Changes[i - 1].Tok->is(tok::string_literal)177 ; | 326 | 13.0k | bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral6.71k ; | 327 | | | 328 | 13.0k | if (Changes[i].NewlinesBefore > 0 && !SkipMatchCheck1.27k ) { | 329 | 686 | Shift = 0; | 330 | 686 | FoundMatchOnLine = false; | 331 | 686 | } | 332 | | | 333 | | // If this is the first matching token to be aligned, remember by how many | 334 | | // spaces it has to be shifted, so the rest of the changes on the line are | 335 | | // shifted by the same amount | 336 | 13.0k | if (!FoundMatchOnLine && !SkipMatchCheck2.95k && Matches(Changes[i])2.81k ) { | 337 | 1.38k | FoundMatchOnLine = true; | 338 | 1.38k | Shift = Column - (RightJustify ? Changes[i].TokenLength0 : 0) - | 339 | 1.38k | Changes[i].StartOfTokenColumn; | 340 | 1.38k | Changes[i].Spaces += Shift; | 341 | | // FIXME: This is a workaround that should be removed when we fix | 342 | | // http://llvm.org/PR53699. An assertion later below verifies this. | 343 | 1.38k | if (Changes[i].NewlinesBefore == 0) { | 344 | 1.38k | Changes[i].Spaces = | 345 | 1.38k | std::max(Changes[i].Spaces, | 346 | 1.38k | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore)); | 347 | 1.38k | } | 348 | 1.38k | } | 349 | | | 350 | | // This is for function parameters that are split across multiple lines, | 351 | | // as mentioned in the ScopeStack comment. | 352 | 13.0k | if (InsideNestedScope && Changes[i].NewlinesBefore > 06.36k ) { | 353 | 577 | unsigned ScopeStart = ScopeStack.back(); | 354 | 577 | auto ShouldShiftBeAdded = [&] { | 355 | | // Function declaration | 356 | 577 | if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName)) | 357 | 577 | return true; | 358 | | | 359 | | // Lambda. | 360 | 577 | if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace)) | 361 | 577 | return false; | 362 | | | 363 | | // Continued function declaration | 364 | 577 | if (ScopeStart > Start + 1 && | 365 | 577 | Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) { | 366 | 577 | return true; | 367 | 577 | } | 368 | | | 369 | | // Continued function call | 370 | 577 | if (ScopeStart > Start + 1 && | 371 | 577 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 372 | 577 | Changes[ScopeStart - 1].Tok->is(tok::l_paren) && | 373 | 577 | Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) { | 374 | 577 | if (Changes[i].Tok->MatchingParen && | 375 | 577 | Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)) { | 376 | 577 | return false; | 377 | 577 | } | 378 | 577 | if (Changes[ScopeStart].NewlinesBefore > 0) | 379 | 577 | return false; | 380 | 577 | if (Changes[i].Tok->is(tok::l_brace) && | 381 | 577 | Changes[i].Tok->is(BK_BracedInit)) { | 382 | 577 | return true; | 383 | 577 | } | 384 | 577 | return Style.BinPackArguments; | 385 | 577 | } | 386 | | | 387 | | // Ternary operator | 388 | 577 | if (Changes[i].Tok->is(TT_ConditionalExpr)) | 389 | 577 | return true; | 390 | | | 391 | | // Period Initializer .XXX = 1. | 392 | 577 | if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) | 393 | 577 | return true; | 394 | | | 395 | | // Continued ternary operator | 396 | 577 | if (Changes[i].Tok->Previous && | 397 | 577 | Changes[i].Tok->Previous->is(TT_ConditionalExpr)) { | 398 | 577 | return true; | 399 | 577 | } | 400 | | | 401 | | // Continued direct-list-initialization using braced list. | 402 | 577 | if (ScopeStart > Start + 1 && | 403 | 577 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 404 | 577 | Changes[ScopeStart - 1].Tok->is(tok::l_brace) && | 405 | 577 | Changes[i].Tok->is(tok::l_brace) && | 406 | 577 | Changes[i].Tok->is(BK_BracedInit)) { | 407 | 577 | return true; | 408 | 577 | } | 409 | | | 410 | | // Continued braced list. | 411 | 577 | if (ScopeStart > Start + 1 && | 412 | 577 | Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && | 413 | 577 | Changes[ScopeStart - 1].Tok->is(tok::l_brace) && | 414 | 577 | Changes[i].Tok->isNot(tok::r_brace)) { | 415 | 577 | for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { | 416 | | // Lambda. | 417 | 577 | if (OuterScopeStart > Start && | 418 | 577 | Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) { | 419 | 577 | return false; | 420 | 577 | } | 421 | 577 | } | 422 | 577 | if (Changes[ScopeStart].NewlinesBefore > 0) | 423 | 577 | return false; | 424 | 577 | return true; | 425 | 577 | } | 426 | | | 427 | 577 | return false; | 428 | 577 | }; | 429 | | | 430 | 577 | if (ShouldShiftBeAdded()) | 431 | 120 | Changes[i].Spaces += Shift; | 432 | 577 | } | 433 | | | 434 | 13.0k | if (ContinuedStringLiteral) | 435 | 27 | Changes[i].Spaces += Shift; | 436 | | | 437 | | // We should not remove required spaces unless we break the line before. | 438 | 13.0k | assert(Shift >= 0 || Changes[i].NewlinesBefore > 0 || | 439 | 13.0k | Changes[i].Spaces >= | 440 | 13.0k | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) || | 441 | 13.0k | Changes[i].Tok->is(tok::eof)); | 442 | | | 443 | 0 | Changes[i].StartOfTokenColumn += Shift; | 444 | 13.0k | if (i + 1 != Changes.size()) | 445 | 12.7k | Changes[i + 1].PreviousEndOfTokenColumn += Shift; | 446 | | | 447 | | // If PointerAlignment is PAS_Right, keep *s or &s next to the token | 448 | 13.0k | if (Style.PointerAlignment == FormatStyle::PAS_Right && | 449 | 13.0k | Changes[i].Spaces != 09.43k ) { | 450 | 4.76k | for (int Previous = i - 1; | 451 | 4.84k | Previous >= 0 && | 452 | 4.84k | Changes[Previous].Tok->getType() == TT_PointerOrReference; | 453 | 4.76k | --Previous77 ) { | 454 | 77 | Changes[Previous + 1].Spaces -= Shift; | 455 | 77 | Changes[Previous].Spaces += Shift; | 456 | 77 | Changes[Previous].StartOfTokenColumn += Shift; | 457 | 77 | } | 458 | 4.76k | } | 459 | 13.0k | } | 460 | 830 | } |
WhitespaceManager.cpp:void clang::format::AlignTokenSequence<clang::format::WhitespaceManager::alignChainedConditionals()::$_4&>(clang::format::FormatStyle const&, unsigned int, unsigned int, unsigned int, bool, clang::format::WhitespaceManager::alignChainedConditionals()::$_4&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&) Line | Count | Source | 277 | 395 | SmallVector<WhitespaceManager::Change, 16> &Changes) { | 278 | 395 | bool FoundMatchOnLine = false; | 279 | 395 | int Shift = 0; | 280 | | | 281 | | // ScopeStack keeps track of the current scope depth. It contains indices of | 282 | | // the first token on each scope. | 283 | | // We only run the "Matches" function on tokens from the outer-most scope. | 284 | | // However, we do need to pay special attention to one class of tokens | 285 | | // that are not in the outer-most scope, and that is function parameters | 286 | | // which are split across multiple lines, as illustrated by this example: | 287 | | // double a(int x); | 288 | | // int b(int y, | 289 | | // double z); | 290 | | // In the above example, we need to take special care to ensure that | 291 | | // 'double z' is indented along with it's owning function 'b'. | 292 | | // The same holds for calling a function: | 293 | | // double a = foo(x); | 294 | | // int b = bar(foo(y), | 295 | | // foor(z)); | 296 | | // Similar for broken string literals: | 297 | | // double x = 3.14; | 298 | | // auto s = "Hello" | 299 | | // "World"; | 300 | | // Special handling is required for 'nested' ternary operators. | 301 | 395 | SmallVector<unsigned, 16> ScopeStack; | 302 | | | 303 | 2.43k | for (unsigned i = Start; i != End; ++i2.04k ) { | 304 | 2.04k | if (ScopeStack.size() != 0 && | 305 | 2.04k | Changes[i].indentAndNestingLevel() < | 306 | 427 | Changes[ScopeStack.back()].indentAndNestingLevel()) { | 307 | 73 | ScopeStack.pop_back(); | 308 | 73 | } | 309 | | | 310 | | // Compare current token to previous non-comment token to ensure whether | 311 | | // it is in a deeper scope or not. | 312 | 2.04k | unsigned PreviousNonComment = i - 1; | 313 | 2.05k | while (PreviousNonComment > Start && | 314 | 2.05k | Changes[PreviousNonComment].Tok->is(tok::comment)1.26k ) { | 315 | 9 | --PreviousNonComment; | 316 | 9 | } | 317 | 2.04k | if (i != Start && Changes[i].indentAndNestingLevel() > | 318 | 1.64k | Changes[PreviousNonComment].indentAndNestingLevel()) { | 319 | 94 | ScopeStack.push_back(i); | 320 | 94 | } | 321 | | | 322 | 2.04k | bool InsideNestedScope = ScopeStack.size() != 0; | 323 | 2.04k | bool ContinuedStringLiteral = i > Start && | 324 | 2.04k | Changes[i].Tok->is(tok::string_literal)1.64k && | 325 | 2.04k | Changes[i - 1].Tok->is(tok::string_literal)20 ; | 326 | 2.04k | bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral1.59k ; | 327 | | | 328 | 2.04k | if (Changes[i].NewlinesBefore > 0 && !SkipMatchCheck397 ) { | 329 | 307 | Shift = 0; | 330 | 307 | FoundMatchOnLine = false; | 331 | 307 | } | 332 | | | 333 | | // If this is the first matching token to be aligned, remember by how many | 334 | | // spaces it has to be shifted, so the rest of the changes on the line are | 335 | | // shifted by the same amount | 336 | 2.04k | if (!FoundMatchOnLine && !SkipMatchCheck809 && Matches(Changes[i])809 ) { | 337 | 632 | FoundMatchOnLine = true; | 338 | 632 | Shift = Column - (RightJustify ? Changes[i].TokenLength0 : 0) - | 339 | 632 | Changes[i].StartOfTokenColumn; | 340 | 632 | Changes[i].Spaces += Shift; | 341 | | // FIXME: This is a workaround that should be removed when we fix | 342 | | // http://llvm.org/PR53699. An assertion later below verifies this. | 343 | 632 | if (Changes[i].NewlinesBefore == 0) { | 344 | 415 | Changes[i].Spaces = | 345 | 415 | std::max(Changes[i].Spaces, | 346 | 415 | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore)); | 347 | 415 | } | 348 | 632 | } | 349 | | | 350 | | // This is for function parameters that are split across multiple lines, | 351 | | // as mentioned in the ScopeStack comment. | 352 | 2.04k | if (InsideNestedScope && Changes[i].NewlinesBefore > 0448 ) { | 353 | 87 | unsigned ScopeStart = ScopeStack.back(); | 354 | 87 | auto ShouldShiftBeAdded = [&] { | 355 | | // Function declaration | 356 | 87 | if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName)) | 357 | 87 | return true; | 358 | | | 359 | | // Lambda. | 360 | 87 | if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace)) | 361 | 87 | return false; | 362 | | | 363 | | // Continued function declaration | 364 | 87 | if (ScopeStart > Start + 1 && | 365 | 87 | Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) { | 366 | 87 | return true; | 367 | 87 | } | 368 | | | 369 | | // Continued function call | 370 | 87 | if (ScopeStart > Start + 1 && | 371 | 87 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 372 | 87 | Changes[ScopeStart - 1].Tok->is(tok::l_paren) && | 373 | 87 | Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) { | 374 | 87 | if (Changes[i].Tok->MatchingParen && | 375 | 87 | Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)) { | 376 | 87 | return false; | 377 | 87 | } | 378 | 87 | if (Changes[ScopeStart].NewlinesBefore > 0) | 379 | 87 | return false; | 380 | 87 | if (Changes[i].Tok->is(tok::l_brace) && | 381 | 87 | Changes[i].Tok->is(BK_BracedInit)) { | 382 | 87 | return true; | 383 | 87 | } | 384 | 87 | return Style.BinPackArguments; | 385 | 87 | } | 386 | | | 387 | | // Ternary operator | 388 | 87 | if (Changes[i].Tok->is(TT_ConditionalExpr)) | 389 | 87 | return true; | 390 | | | 391 | | // Period Initializer .XXX = 1. | 392 | 87 | if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) | 393 | 87 | return true; | 394 | | | 395 | | // Continued ternary operator | 396 | 87 | if (Changes[i].Tok->Previous && | 397 | 87 | Changes[i].Tok->Previous->is(TT_ConditionalExpr)) { | 398 | 87 | return true; | 399 | 87 | } | 400 | | | 401 | | // Continued direct-list-initialization using braced list. | 402 | 87 | if (ScopeStart > Start + 1 && | 403 | 87 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 404 | 87 | Changes[ScopeStart - 1].Tok->is(tok::l_brace) && | 405 | 87 | Changes[i].Tok->is(tok::l_brace) && | 406 | 87 | Changes[i].Tok->is(BK_BracedInit)) { | 407 | 87 | return true; | 408 | 87 | } | 409 | | | 410 | | // Continued braced list. | 411 | 87 | if (ScopeStart > Start + 1 && | 412 | 87 | Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && | 413 | 87 | Changes[ScopeStart - 1].Tok->is(tok::l_brace) && | 414 | 87 | Changes[i].Tok->isNot(tok::r_brace)) { | 415 | 87 | for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { | 416 | | // Lambda. | 417 | 87 | if (OuterScopeStart > Start && | 418 | 87 | Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) { | 419 | 87 | return false; | 420 | 87 | } | 421 | 87 | } | 422 | 87 | if (Changes[ScopeStart].NewlinesBefore > 0) | 423 | 87 | return false; | 424 | 87 | return true; | 425 | 87 | } | 426 | | | 427 | 87 | return false; | 428 | 87 | }; | 429 | | | 430 | 87 | if (ShouldShiftBeAdded()) | 431 | 72 | Changes[i].Spaces += Shift; | 432 | 87 | } | 433 | | | 434 | 2.04k | if (ContinuedStringLiteral) | 435 | 3 | Changes[i].Spaces += Shift; | 436 | | | 437 | | // We should not remove required spaces unless we break the line before. | 438 | 2.04k | assert(Shift >= 0 || Changes[i].NewlinesBefore > 0 || | 439 | 2.04k | Changes[i].Spaces >= | 440 | 2.04k | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) || | 441 | 2.04k | Changes[i].Tok->is(tok::eof)); | 442 | | | 443 | 0 | Changes[i].StartOfTokenColumn += Shift; | 444 | 2.04k | if (i + 1 != Changes.size()) | 445 | 2.04k | Changes[i + 1].PreviousEndOfTokenColumn += Shift; | 446 | | | 447 | | // If PointerAlignment is PAS_Right, keep *s or &s next to the token | 448 | 2.04k | if (Style.PointerAlignment == FormatStyle::PAS_Right && | 449 | 2.04k | Changes[i].Spaces != 01.95k ) { | 450 | 1.74k | for (int Previous = i - 1; | 451 | 1.74k | Previous >= 0 && | 452 | 1.74k | Changes[Previous].Tok->getType() == TT_PointerOrReference; | 453 | 1.74k | --Previous0 ) { | 454 | 0 | Changes[Previous + 1].Spaces -= Shift; | 455 | 0 | Changes[Previous].Spaces += Shift; | 456 | 0 | Changes[Previous].StartOfTokenColumn += Shift; | 457 | 0 | } | 458 | 1.74k | } | 459 | 2.04k | } | 460 | 395 | } |
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 | 277 | 205 | SmallVector<WhitespaceManager::Change, 16> &Changes) { | 278 | 205 | bool FoundMatchOnLine = false; | 279 | 205 | int Shift = 0; | 280 | | | 281 | | // ScopeStack keeps track of the current scope depth. It contains indices of | 282 | | // the first token on each scope. | 283 | | // We only run the "Matches" function on tokens from the outer-most scope. | 284 | | // However, we do need to pay special attention to one class of tokens | 285 | | // that are not in the outer-most scope, and that is function parameters | 286 | | // which are split across multiple lines, as illustrated by this example: | 287 | | // double a(int x); | 288 | | // int b(int y, | 289 | | // double z); | 290 | | // In the above example, we need to take special care to ensure that | 291 | | // 'double z' is indented along with it's owning function 'b'. | 292 | | // The same holds for calling a function: | 293 | | // double a = foo(x); | 294 | | // int b = bar(foo(y), | 295 | | // foor(z)); | 296 | | // Similar for broken string literals: | 297 | | // double x = 3.14; | 298 | | // auto s = "Hello" | 299 | | // "World"; | 300 | | // Special handling is required for 'nested' ternary operators. | 301 | 205 | SmallVector<unsigned, 16> ScopeStack; | 302 | | | 303 | 1.60k | for (unsigned i = Start; i != End; ++i1.40k ) { | 304 | 1.40k | if (ScopeStack.size() != 0 && | 305 | 1.40k | Changes[i].indentAndNestingLevel() < | 306 | 332 | Changes[ScopeStack.back()].indentAndNestingLevel()) { | 307 | 56 | ScopeStack.pop_back(); | 308 | 56 | } | 309 | | | 310 | | // Compare current token to previous non-comment token to ensure whether | 311 | | // it is in a deeper scope or not. | 312 | 1.40k | unsigned PreviousNonComment = i - 1; | 313 | 1.40k | while (PreviousNonComment > Start && | 314 | 1.40k | Changes[PreviousNonComment].Tok->is(tok::comment)1.02k ) { | 315 | 3 | --PreviousNonComment; | 316 | 3 | } | 317 | 1.40k | if (i != Start && Changes[i].indentAndNestingLevel() > | 318 | 1.19k | Changes[PreviousNonComment].indentAndNestingLevel()) { | 319 | 73 | ScopeStack.push_back(i); | 320 | 73 | } | 321 | | | 322 | 1.40k | bool InsideNestedScope = ScopeStack.size() != 0; | 323 | 1.40k | bool ContinuedStringLiteral = i > Start && | 324 | 1.40k | Changes[i].Tok->is(tok::string_literal)1.19k && | 325 | 1.40k | Changes[i - 1].Tok->is(tok::string_literal)10 ; | 326 | 1.40k | bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral1.05k ; | 327 | | | 328 | 1.40k | if (Changes[i].NewlinesBefore > 0 && !SkipMatchCheck318 ) { | 329 | 256 | Shift = 0; | 330 | 256 | FoundMatchOnLine = false; | 331 | 256 | } | 332 | | | 333 | | // If this is the first matching token to be aligned, remember by how many | 334 | | // spaces it has to be shifted, so the rest of the changes on the line are | 335 | | // shifted by the same amount | 336 | 1.40k | if (!FoundMatchOnLine && !SkipMatchCheck488 && Matches(Changes[i])488 ) { | 337 | 407 | FoundMatchOnLine = true; | 338 | 407 | Shift = Column - (RightJustify ? Changes[i].TokenLength0 : 0) - | 339 | 407 | Changes[i].StartOfTokenColumn; | 340 | 407 | Changes[i].Spaces += Shift; | 341 | | // FIXME: This is a workaround that should be removed when we fix | 342 | | // http://llvm.org/PR53699. An assertion later below verifies this. | 343 | 407 | if (Changes[i].NewlinesBefore == 0) { | 344 | 232 | Changes[i].Spaces = | 345 | 232 | std::max(Changes[i].Spaces, | 346 | 232 | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore)); | 347 | 232 | } | 348 | 407 | } | 349 | | | 350 | | // This is for function parameters that are split across multiple lines, | 351 | | // as mentioned in the ScopeStack comment. | 352 | 1.40k | if (InsideNestedScope && Changes[i].NewlinesBefore > 0349 ) { | 353 | 62 | unsigned ScopeStart = ScopeStack.back(); | 354 | 62 | auto ShouldShiftBeAdded = [&] { | 355 | | // Function declaration | 356 | 62 | if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName)) | 357 | 62 | return true; | 358 | | | 359 | | // Lambda. | 360 | 62 | if (Changes[ScopeStart - 1].Tok->is(TT_LambdaLBrace)) | 361 | 62 | return false; | 362 | | | 363 | | // Continued function declaration | 364 | 62 | if (ScopeStart > Start + 1 && | 365 | 62 | Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) { | 366 | 62 | return true; | 367 | 62 | } | 368 | | | 369 | | // Continued function call | 370 | 62 | if (ScopeStart > Start + 1 && | 371 | 62 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 372 | 62 | Changes[ScopeStart - 1].Tok->is(tok::l_paren) && | 373 | 62 | Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) { | 374 | 62 | if (Changes[i].Tok->MatchingParen && | 375 | 62 | Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)) { | 376 | 62 | return false; | 377 | 62 | } | 378 | 62 | if (Changes[ScopeStart].NewlinesBefore > 0) | 379 | 62 | return false; | 380 | 62 | if (Changes[i].Tok->is(tok::l_brace) && | 381 | 62 | Changes[i].Tok->is(BK_BracedInit)) { | 382 | 62 | return true; | 383 | 62 | } | 384 | 62 | return Style.BinPackArguments; | 385 | 62 | } | 386 | | | 387 | | // Ternary operator | 388 | 62 | if (Changes[i].Tok->is(TT_ConditionalExpr)) | 389 | 62 | return true; | 390 | | | 391 | | // Period Initializer .XXX = 1. | 392 | 62 | if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) | 393 | 62 | return true; | 394 | | | 395 | | // Continued ternary operator | 396 | 62 | if (Changes[i].Tok->Previous && | 397 | 62 | Changes[i].Tok->Previous->is(TT_ConditionalExpr)) { | 398 | 62 | return true; | 399 | 62 | } | 400 | | | 401 | | // Continued direct-list-initialization using braced list. | 402 | 62 | if (ScopeStart > Start + 1 && | 403 | 62 | Changes[ScopeStart - 2].Tok->is(tok::identifier) && | 404 | 62 | Changes[ScopeStart - 1].Tok->is(tok::l_brace) && | 405 | 62 | Changes[i].Tok->is(tok::l_brace) && | 406 | 62 | Changes[i].Tok->is(BK_BracedInit)) { | 407 | 62 | return true; | 408 | 62 | } | 409 | | | 410 | | // Continued braced list. | 411 | 62 | if (ScopeStart > Start + 1 && | 412 | 62 | Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && | 413 | 62 | Changes[ScopeStart - 1].Tok->is(tok::l_brace) && | 414 | 62 | Changes[i].Tok->isNot(tok::r_brace)) { | 415 | 62 | for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { | 416 | | // Lambda. | 417 | 62 | if (OuterScopeStart > Start && | 418 | 62 | Changes[OuterScopeStart - 1].Tok->is(TT_LambdaLBrace)) { | 419 | 62 | return false; | 420 | 62 | } | 421 | 62 | } | 422 | 62 | if (Changes[ScopeStart].NewlinesBefore > 0) | 423 | 62 | return false; | 424 | 62 | return true; | 425 | 62 | } | 426 | | | 427 | 62 | return false; | 428 | 62 | }; | 429 | | | 430 | 62 | if (ShouldShiftBeAdded()) | 431 | 48 | Changes[i].Spaces += Shift; | 432 | 62 | } | 433 | | | 434 | 1.40k | if (ContinuedStringLiteral) | 435 | 0 | Changes[i].Spaces += Shift; | 436 | | | 437 | | // We should not remove required spaces unless we break the line before. | 438 | 1.40k | assert(Shift >= 0 || Changes[i].NewlinesBefore > 0 || | 439 | 1.40k | Changes[i].Spaces >= | 440 | 1.40k | static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) || | 441 | 1.40k | Changes[i].Tok->is(tok::eof)); | 442 | | | 443 | 0 | Changes[i].StartOfTokenColumn += Shift; | 444 | 1.40k | if (i + 1 != Changes.size()) | 445 | 1.40k | Changes[i + 1].PreviousEndOfTokenColumn += Shift; | 446 | | | 447 | | // If PointerAlignment is PAS_Right, keep *s or &s next to the token | 448 | 1.40k | if (Style.PointerAlignment == FormatStyle::PAS_Right && | 449 | 1.40k | Changes[i].Spaces != 01.23k ) { | 450 | 1.12k | for (int Previous = i - 1; | 451 | 1.12k | Previous >= 0 && | 452 | 1.12k | Changes[Previous].Tok->getType() == TT_PointerOrReference; | 453 | 1.12k | --Previous0 ) { | 454 | 0 | Changes[Previous + 1].Spaces -= Shift; | 455 | 0 | Changes[Previous].Spaces += Shift; | 456 | 0 | Changes[Previous].StartOfTokenColumn += Shift; | 457 | 0 | } | 458 | 1.12k | } | 459 | 1.40k | } | 460 | 205 | } |
|
461 | | |
462 | | // Walk through a subset of the changes, starting at StartAt, and find |
463 | | // sequences of matching tokens to align. To do so, keep track of the lines and |
464 | | // whether or not a matching token was found on a line. If a matching token is |
465 | | // found, extend the current sequence. If the current line cannot be part of a |
466 | | // sequence, e.g. because there is an empty line before it or it contains only |
467 | | // non-matching tokens, finalize the previous sequence. |
468 | | // The value returned is the token on which we stopped, either because we |
469 | | // exhausted all items inside Changes, or because we hit a scope level higher |
470 | | // than our initial scope. |
471 | | // This function is recursive. Each invocation processes only the scope level |
472 | | // equal to the initial level, which is the level of Changes[StartAt]. |
473 | | // If we encounter a scope level greater than the initial level, then we call |
474 | | // ourselves recursively, thereby avoiding the pollution of the current state |
475 | | // with the alignment requirements of the nested sub-level. This recursive |
476 | | // behavior is necessary for aligning function prototypes that have one or more |
477 | | // arguments. |
478 | | // If this function encounters a scope level less than the initial level, |
479 | | // it returns the current position. |
480 | | // There is a non-obvious subtlety in the recursive behavior: Even though we |
481 | | // defer processing of nested levels to recursive invocations of this |
482 | | // function, when it comes time to align a sequence of tokens, we run the |
483 | | // alignment on the entire sequence, including the nested levels. |
484 | | // When doing so, most of the nested tokens are skipped, because their |
485 | | // alignment was already handled by the recursive invocations of this function. |
486 | | // However, the special exception is that we do NOT skip function parameters |
487 | | // that are split across multiple lines. See the test case in FormatTest.cpp |
488 | | // that mentions "split function parameter alignment" for an example of this. |
489 | | // When the parameter RightJustify is true, the operator will be |
490 | | // right-justified. It is used to align compound assignments like `+=` and `=`. |
491 | | // When RightJustify and ACS.PadOperators are true, operators in each block to |
492 | | // be aligned will be padded on the left to the same length before aligning. |
493 | | template <typename F> |
494 | | static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, |
495 | | SmallVector<WhitespaceManager::Change, 16> &Changes, |
496 | | unsigned StartAt, |
497 | | const FormatStyle::AlignConsecutiveStyle &ACS = {}, |
498 | 85.1k | bool RightJustify = false) { |
499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), |
500 | | // and text to its left and right. In the aligned text the width of each part |
501 | | // will be the maximum of that over the block that has been aligned. Maximum |
502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators |
503 | | // is false, the part from start of line to the right end of the anchor. |
504 | | // Otherwise, only the part to the left of the anchor. Including the space |
505 | | // that exists on its left from the start. Not including the padding added on |
506 | | // the left to right-justify the anchor. |
507 | 85.1k | unsigned WidthLeft = 0; |
508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators |
509 | | // is false. 0 otherwise. |
510 | 85.1k | unsigned WidthAnchor = 0; |
511 | | // Width to the right of the anchor. Plus width of the anchor when |
512 | | // RightJustify is false. |
513 | 85.1k | unsigned WidthRight = 0; |
514 | | |
515 | | // Line number of the start and the end of the current token sequence. |
516 | 85.1k | unsigned StartOfSequence = 0; |
517 | 85.1k | unsigned EndOfSequence = 0; |
518 | | |
519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and |
520 | | // abort when we hit any token in a higher scope than the starting one. |
521 | 85.1k | auto IndentAndNestingLevel = StartAt < Changes.size() |
522 | 85.1k | ? Changes[StartAt].indentAndNestingLevel() |
523 | 85.1k | : std::tuple<unsigned, unsigned, unsigned>()0 ; |
524 | | |
525 | | // Keep track of the number of commas before the matching tokens, we will only |
526 | | // align a sequence of matching tokens if they are preceded by the same number |
527 | | // of commas. |
528 | 85.1k | unsigned CommasBeforeLastMatch = 0; |
529 | 85.1k | unsigned CommasBeforeMatch = 0; |
530 | | |
531 | | // Whether a matching token has been found on the current line. |
532 | 85.1k | bool FoundMatchOnLine = false; |
533 | | |
534 | | // Whether the current line consists purely of comments. |
535 | 85.1k | bool LineIsComment = true; |
536 | | |
537 | | // Aligns a sequence of matching tokens, on the MinColumn column. |
538 | | // |
539 | | // Sequences start from the first matching token to align, and end at the |
540 | | // first token of the first line that doesn't need to be aligned. |
541 | | // |
542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line |
543 | | // containing any matching token to be aligned and located after such token. |
544 | 150k | auto AlignCurrentSequence = [&] { |
545 | 150k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence2.54k ) { |
546 | 2.17k | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, |
547 | 2.17k | WidthLeft + WidthAnchor, RightJustify, Matches, |
548 | 2.17k | Changes); |
549 | 2.17k | } |
550 | 150k | WidthLeft = 0; |
551 | 150k | WidthAnchor = 0; |
552 | 150k | WidthRight = 0; |
553 | 150k | StartOfSequence = 0; |
554 | 150k | EndOfSequence = 0; |
555 | 150k | }; 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, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool)::'lambda'()::operator()() const Line | Count | Source | 544 | 1.36k | auto AlignCurrentSequence = [&] { | 545 | 1.36k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence469 ) { | 546 | 463 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 463 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 463 | Changes); | 549 | 463 | } | 550 | 1.36k | WidthLeft = 0; | 551 | 1.36k | WidthAnchor = 0; | 552 | 1.36k | WidthRight = 0; | 553 | 1.36k | StartOfSequence = 0; | 554 | 1.36k | EndOfSequence = 0; | 555 | 1.36k | }; |
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, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool)::'lambda'()::operator()() const Line | Count | Source | 544 | 2.48k | auto AlignCurrentSequence = [&] { | 545 | 2.48k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence267 ) { | 546 | 243 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 243 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 243 | Changes); | 549 | 243 | } | 550 | 2.48k | WidthLeft = 0; | 551 | 2.48k | WidthAnchor = 0; | 552 | 2.48k | WidthRight = 0; | 553 | 2.48k | StartOfSequence = 0; | 554 | 2.48k | EndOfSequence = 0; | 555 | 2.48k | }; |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool)::'lambda'()::operator()() const Line | Count | Source | 544 | 36 | auto AlignCurrentSequence = [&] { | 545 | 36 | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 36 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 36 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 36 | Changes); | 549 | 36 | } | 550 | 36 | WidthLeft = 0; | 551 | 36 | WidthAnchor = 0; | 552 | 36 | WidthRight = 0; | 553 | 36 | StartOfSequence = 0; | 554 | 36 | EndOfSequence = 0; | 555 | 36 | }; |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2&>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool)::'lambda'()::operator()() const Line | Count | Source | 544 | 3 | auto AlignCurrentSequence = [&] { | 545 | 3 | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence0 ) { | 546 | 0 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 0 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 0 | Changes); | 549 | 0 | } | 550 | 3 | WidthLeft = 0; | 551 | 3 | WidthAnchor = 0; | 552 | 3 | WidthRight = 0; | 553 | 3 | StartOfSequence = 0; | 554 | 3 | EndOfSequence = 0; | 555 | 3 | }; |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool)::'lambda'()::operator()() const Line | Count | Source | 544 | 1.13k | auto AlignCurrentSequence = [&] { | 545 | 1.13k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence461 ) { | 546 | 461 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 461 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 461 | Changes); | 549 | 461 | } | 550 | 1.13k | WidthLeft = 0; | 551 | 1.13k | WidthAnchor = 0; | 552 | 1.13k | WidthRight = 0; | 553 | 1.13k | StartOfSequence = 0; | 554 | 1.13k | EndOfSequence = 0; | 555 | 1.13k | }; |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3&>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool)::'lambda'()::operator()() const Line | Count | Source | 544 | 2.61k | auto AlignCurrentSequence = [&] { | 545 | 2.61k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence555 ) { | 546 | 369 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 369 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 369 | Changes); | 549 | 369 | } | 550 | 2.61k | WidthLeft = 0; | 551 | 2.61k | WidthAnchor = 0; | 552 | 2.61k | WidthRight = 0; | 553 | 2.61k | StartOfSequence = 0; | 554 | 2.61k | EndOfSequence = 0; | 555 | 2.61k | }; |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignChainedConditionals()::$_4>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignChainedConditionals()::$_4&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool)::'lambda'()::operator()() const Line | Count | Source | 544 | 53.2k | auto AlignCurrentSequence = [&] { | 545 | 53.2k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence23 ) { | 546 | 16 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 16 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 16 | Changes); | 549 | 16 | } | 550 | 53.2k | WidthLeft = 0; | 551 | 53.2k | WidthAnchor = 0; | 552 | 53.2k | WidthRight = 0; | 553 | 53.2k | StartOfSequence = 0; | 554 | 53.2k | EndOfSequence = 0; | 555 | 53.2k | }; |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignChainedConditionals()::$_4&>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignChainedConditionals()::$_4&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool)::'lambda'()::operator()() const Line | Count | Source | 544 | 81.9k | auto AlignCurrentSequence = [&] { | 545 | 81.9k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence532 ) { | 546 | 379 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 379 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 379 | Changes); | 549 | 379 | } | 550 | 81.9k | WidthLeft = 0; | 551 | 81.9k | WidthAnchor = 0; | 552 | 81.9k | WidthRight = 0; | 553 | 81.9k | StartOfSequence = 0; | 554 | 81.9k | EndOfSequence = 0; | 555 | 81.9k | }; |
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)::'lambda'()::operator()() const Line | Count | Source | 544 | 3.19k | auto AlignCurrentSequence = [&] { | 545 | 3.19k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence11 ) { | 546 | 11 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 11 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 11 | Changes); | 549 | 11 | } | 550 | 3.19k | WidthLeft = 0; | 551 | 3.19k | WidthAnchor = 0; | 552 | 3.19k | WidthRight = 0; | 553 | 3.19k | StartOfSequence = 0; | 554 | 3.19k | EndOfSequence = 0; | 555 | 3.19k | }; |
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)::'lambda'()::operator()() const Line | Count | Source | 544 | 4.95k | auto AlignCurrentSequence = [&] { | 545 | 4.95k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence194 ) { | 546 | 194 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 194 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 194 | Changes); | 549 | 194 | } | 550 | 4.95k | WidthLeft = 0; | 551 | 4.95k | WidthAnchor = 0; | 552 | 4.95k | WidthRight = 0; | 553 | 4.95k | StartOfSequence = 0; | 554 | 4.95k | EndOfSequence = 0; | 555 | 4.95k | }; |
|
556 | | |
557 | 85.1k | unsigned i = StartAt; |
558 | 554k | for (unsigned e = Changes.size(); i != e; ++i469k ) { |
559 | 530k | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) |
560 | 61.2k | break; |
561 | | |
562 | 469k | if (Changes[i].NewlinesBefore != 0) { |
563 | 67.6k | CommasBeforeMatch = 0; |
564 | 67.6k | EndOfSequence = i; |
565 | | |
566 | | // Whether to break the alignment sequence because of an empty line. |
567 | 67.6k | bool EmptyLineBreak = |
568 | 67.6k | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines1.42k ; |
569 | | |
570 | | // Whether to break the alignment sequence because of a line without a |
571 | | // match. |
572 | 67.6k | bool NoMatchBreak = |
573 | 67.6k | !FoundMatchOnLine && !(65.3k LineIsComment65.3k && ACS.AcrossComments17.3k ); |
574 | | |
575 | 67.6k | if (EmptyLineBreak || NoMatchBreak66.2k ) |
576 | 65.3k | AlignCurrentSequence(); |
577 | | |
578 | | // A new line starts, re-initialize line status tracking bools. |
579 | | // Keep the match state if a string literal is continued on this line. |
580 | 67.6k | if (i == 0 || !Changes[i].Tok->is(tok::string_literal)67.0k || |
581 | 67.6k | !Changes[i - 1].Tok->is(tok::string_literal)1.07k ) { |
582 | 67.2k | FoundMatchOnLine = false; |
583 | 67.2k | } |
584 | 67.6k | LineIsComment = true; |
585 | 67.6k | } |
586 | | |
587 | 469k | if (!Changes[i].Tok->is(tok::comment)) |
588 | 460k | LineIsComment = false; |
589 | | |
590 | 469k | if (Changes[i].Tok->is(tok::comma)) { |
591 | 14.0k | ++CommasBeforeMatch; |
592 | 455k | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { |
593 | | // Call AlignTokens recursively, skipping over this scope block. |
594 | 61.2k | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); |
595 | 61.2k | i = StoppedAt - 1; |
596 | 61.2k | continue; |
597 | 61.2k | } |
598 | | |
599 | 407k | if (!Matches(Changes[i])) |
600 | 403k | continue; |
601 | | |
602 | | // If there is more than one matching token per line, or if the number of |
603 | | // preceding commas, do not match anymore, end the sequence. |
604 | 4.08k | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch3.69k ) |
605 | 449 | AlignCurrentSequence(); |
606 | | |
607 | 4.08k | CommasBeforeLastMatch = CommasBeforeMatch; |
608 | 4.08k | FoundMatchOnLine = true; |
609 | | |
610 | 4.08k | if (StartOfSequence == 0) |
611 | 2.53k | StartOfSequence = i; |
612 | | |
613 | 4.08k | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; |
614 | 4.08k | unsigned ChangeWidthAnchor = 0; |
615 | 4.08k | unsigned ChangeWidthRight = 0; |
616 | 4.08k | if (RightJustify) |
617 | 779 | if (ACS.PadOperators) |
618 | 746 | ChangeWidthAnchor = Changes[i].TokenLength; |
619 | 33 | else |
620 | 33 | ChangeWidthLeft += Changes[i].TokenLength; |
621 | 3.31k | else |
622 | 3.31k | ChangeWidthRight = Changes[i].TokenLength; |
623 | 21.2k | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 019.9k ; ++j17.1k ) { |
624 | 17.1k | ChangeWidthRight += Changes[j].Spaces; |
625 | | // Changes are generally 1:1 with the tokens, but a change could also be |
626 | | // inside of a token, in which case it's counted more than once: once for |
627 | | // the whitespace surrounding the token (!IsInsideToken) and once for |
628 | | // each whitespace change within it (IsInsideToken). |
629 | | // Therefore, changes inside of a token should only count the space. |
630 | 17.1k | if (!Changes[j].IsInsideToken) |
631 | 17.1k | ChangeWidthRight += Changes[j].TokenLength; |
632 | 17.1k | } |
633 | | |
634 | | // If we are restricted by the maximum column width, end the sequence. |
635 | 4.08k | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); |
636 | 4.08k | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); |
637 | 4.08k | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); |
638 | | // `ColumnLimit == 0` means there is no column limit. |
639 | 4.08k | if (Style.ColumnLimit != 0 && |
640 | 4.08k | Style.ColumnLimit < NewLeft + NewAnchor + NewRight4.07k ) { |
641 | 15 | AlignCurrentSequence(); |
642 | 15 | StartOfSequence = i; |
643 | 15 | WidthLeft = ChangeWidthLeft; |
644 | 15 | WidthAnchor = ChangeWidthAnchor; |
645 | 15 | WidthRight = ChangeWidthRight; |
646 | 4.07k | } else { |
647 | 4.07k | WidthLeft = NewLeft; |
648 | 4.07k | WidthAnchor = NewAnchor; |
649 | 4.07k | WidthRight = NewRight; |
650 | 4.07k | } |
651 | 4.08k | } |
652 | | |
653 | 85.1k | EndOfSequence = i; |
654 | 85.1k | AlignCurrentSequence(); |
655 | 85.1k | return i; |
656 | 85.1k | } 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, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool) Line | Count | Source | 498 | 594 | bool RightJustify = false) { | 499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), | 500 | | // and text to its left and right. In the aligned text the width of each part | 501 | | // will be the maximum of that over the block that has been aligned. Maximum | 502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators | 503 | | // is false, the part from start of line to the right end of the anchor. | 504 | | // Otherwise, only the part to the left of the anchor. Including the space | 505 | | // that exists on its left from the start. Not including the padding added on | 506 | | // the left to right-justify the anchor. | 507 | 594 | unsigned WidthLeft = 0; | 508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators | 509 | | // is false. 0 otherwise. | 510 | 594 | unsigned WidthAnchor = 0; | 511 | | // Width to the right of the anchor. Plus width of the anchor when | 512 | | // RightJustify is false. | 513 | 594 | unsigned WidthRight = 0; | 514 | | | 515 | | // Line number of the start and the end of the current token sequence. | 516 | 594 | unsigned StartOfSequence = 0; | 517 | 594 | unsigned EndOfSequence = 0; | 518 | | | 519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and | 520 | | // abort when we hit any token in a higher scope than the starting one. | 521 | 594 | auto IndentAndNestingLevel = StartAt < Changes.size() | 522 | 594 | ? Changes[StartAt].indentAndNestingLevel() | 523 | 594 | : std::tuple<unsigned, unsigned, unsigned>()0 ; | 524 | | | 525 | | // Keep track of the number of commas before the matching tokens, we will only | 526 | | // align a sequence of matching tokens if they are preceded by the same number | 527 | | // of commas. | 528 | 594 | unsigned CommasBeforeLastMatch = 0; | 529 | 594 | unsigned CommasBeforeMatch = 0; | 530 | | | 531 | | // Whether a matching token has been found on the current line. | 532 | 594 | bool FoundMatchOnLine = false; | 533 | | | 534 | | // Whether the current line consists purely of comments. | 535 | 594 | bool LineIsComment = true; | 536 | | | 537 | | // Aligns a sequence of matching tokens, on the MinColumn column. | 538 | | // | 539 | | // Sequences start from the first matching token to align, and end at the | 540 | | // first token of the first line that doesn't need to be aligned. | 541 | | // | 542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line | 543 | | // containing any matching token to be aligned and located after such token. | 544 | 594 | auto AlignCurrentSequence = [&] { | 545 | 594 | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 594 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 594 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 594 | Changes); | 549 | 594 | } | 550 | 594 | WidthLeft = 0; | 551 | 594 | WidthAnchor = 0; | 552 | 594 | WidthRight = 0; | 553 | 594 | StartOfSequence = 0; | 554 | 594 | EndOfSequence = 0; | 555 | 594 | }; | 556 | | | 557 | 594 | unsigned i = StartAt; | 558 | 8.29k | for (unsigned e = Changes.size(); i != e; ++i7.69k ) { | 559 | 7.69k | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) | 560 | 0 | break; | 561 | | | 562 | 7.69k | if (Changes[i].NewlinesBefore != 0) { | 563 | 1.29k | CommasBeforeMatch = 0; | 564 | 1.29k | EndOfSequence = i; | 565 | | | 566 | | // Whether to break the alignment sequence because of an empty line. | 567 | 1.29k | bool EmptyLineBreak = | 568 | 1.29k | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines35 ; | 569 | | | 570 | | // Whether to break the alignment sequence because of a line without a | 571 | | // match. | 572 | 1.29k | bool NoMatchBreak = | 573 | 1.29k | !FoundMatchOnLine && !(722 LineIsComment722 && ACS.AcrossComments56 ); | 574 | | | 575 | 1.29k | if (EmptyLineBreak || NoMatchBreak1.28k ) | 576 | 707 | AlignCurrentSequence(); | 577 | | | 578 | | // A new line starts, re-initialize line status tracking bools. | 579 | | // Keep the match state if a string literal is continued on this line. | 580 | 1.29k | if (i == 0 || !Changes[i].Tok->is(tok::string_literal) || | 581 | 1.29k | !Changes[i - 1].Tok->is(tok::string_literal)18 ) { | 582 | 1.29k | FoundMatchOnLine = false; | 583 | 1.29k | } | 584 | 1.29k | LineIsComment = true; | 585 | 1.29k | } | 586 | | | 587 | 7.69k | if (!Changes[i].Tok->is(tok::comment)) | 588 | 7.59k | LineIsComment = false; | 589 | | | 590 | 7.69k | if (Changes[i].Tok->is(tok::comma)) { | 591 | 30 | ++CommasBeforeMatch; | 592 | 7.66k | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { | 593 | | // Call AlignTokens recursively, skipping over this scope block. | 594 | 848 | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); | 595 | 848 | i = StoppedAt - 1; | 596 | 848 | continue; | 597 | 848 | } | 598 | | | 599 | 6.85k | if (!Matches(Changes[i])) | 600 | 6.07k | continue; | 601 | | | 602 | | // If there is more than one matching token per line, or if the number of | 603 | | // preceding commas, do not match anymore, end the sequence. | 604 | 779 | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch758 ) | 605 | 54 | AlignCurrentSequence(); | 606 | | | 607 | 779 | CommasBeforeLastMatch = CommasBeforeMatch; | 608 | 779 | FoundMatchOnLine = true; | 609 | | | 610 | 779 | if (StartOfSequence == 0) | 611 | 463 | StartOfSequence = i; | 612 | | | 613 | 779 | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; | 614 | 779 | unsigned ChangeWidthAnchor = 0; | 615 | 779 | unsigned ChangeWidthRight = 0; | 616 | 779 | if (RightJustify) | 617 | 779 | if (ACS.PadOperators) | 618 | 746 | ChangeWidthAnchor = Changes[i].TokenLength; | 619 | 33 | else | 620 | 33 | ChangeWidthLeft += Changes[i].TokenLength; | 621 | 0 | else | 622 | 0 | ChangeWidthRight = Changes[i].TokenLength; | 623 | 2.86k | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 02.69k ; ++j2.08k ) { | 624 | 2.08k | ChangeWidthRight += Changes[j].Spaces; | 625 | | // Changes are generally 1:1 with the tokens, but a change could also be | 626 | | // inside of a token, in which case it's counted more than once: once for | 627 | | // the whitespace surrounding the token (!IsInsideToken) and once for | 628 | | // each whitespace change within it (IsInsideToken). | 629 | | // Therefore, changes inside of a token should only count the space. | 630 | 2.08k | if (!Changes[j].IsInsideToken) | 631 | 2.08k | ChangeWidthRight += Changes[j].TokenLength; | 632 | 2.08k | } | 633 | | | 634 | | // If we are restricted by the maximum column width, end the sequence. | 635 | 779 | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); | 636 | 779 | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); | 637 | 779 | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); | 638 | | // `ColumnLimit == 0` means there is no column limit. | 639 | 779 | if (Style.ColumnLimit != 0 && | 640 | 779 | Style.ColumnLimit < NewLeft + NewAnchor + NewRight778 ) { | 641 | 6 | AlignCurrentSequence(); | 642 | 6 | StartOfSequence = i; | 643 | 6 | WidthLeft = ChangeWidthLeft; | 644 | 6 | WidthAnchor = ChangeWidthAnchor; | 645 | 6 | WidthRight = ChangeWidthRight; | 646 | 773 | } else { | 647 | 773 | WidthLeft = NewLeft; | 648 | 773 | WidthAnchor = NewAnchor; | 649 | 773 | WidthRight = NewRight; | 650 | 773 | } | 651 | 779 | } | 652 | | | 653 | 594 | EndOfSequence = i; | 654 | 594 | AlignCurrentSequence(); | 655 | 594 | return i; | 656 | 594 | } |
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, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool) Line | Count | Source | 498 | 1.67k | bool RightJustify = false) { | 499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), | 500 | | // and text to its left and right. In the aligned text the width of each part | 501 | | // will be the maximum of that over the block that has been aligned. Maximum | 502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators | 503 | | // is false, the part from start of line to the right end of the anchor. | 504 | | // Otherwise, only the part to the left of the anchor. Including the space | 505 | | // that exists on its left from the start. Not including the padding added on | 506 | | // the left to right-justify the anchor. | 507 | 1.67k | unsigned WidthLeft = 0; | 508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators | 509 | | // is false. 0 otherwise. | 510 | 1.67k | unsigned WidthAnchor = 0; | 511 | | // Width to the right of the anchor. Plus width of the anchor when | 512 | | // RightJustify is false. | 513 | 1.67k | unsigned WidthRight = 0; | 514 | | | 515 | | // Line number of the start and the end of the current token sequence. | 516 | 1.67k | unsigned StartOfSequence = 0; | 517 | 1.67k | unsigned EndOfSequence = 0; | 518 | | | 519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and | 520 | | // abort when we hit any token in a higher scope than the starting one. | 521 | 1.67k | auto IndentAndNestingLevel = StartAt < Changes.size() | 522 | 1.67k | ? Changes[StartAt].indentAndNestingLevel() | 523 | 1.67k | : std::tuple<unsigned, unsigned, unsigned>()0 ; | 524 | | | 525 | | // Keep track of the number of commas before the matching tokens, we will only | 526 | | // align a sequence of matching tokens if they are preceded by the same number | 527 | | // of commas. | 528 | 1.67k | unsigned CommasBeforeLastMatch = 0; | 529 | 1.67k | unsigned CommasBeforeMatch = 0; | 530 | | | 531 | | // Whether a matching token has been found on the current line. | 532 | 1.67k | bool FoundMatchOnLine = false; | 533 | | | 534 | | // Whether the current line consists purely of comments. | 535 | 1.67k | bool LineIsComment = true; | 536 | | | 537 | | // Aligns a sequence of matching tokens, on the MinColumn column. | 538 | | // | 539 | | // Sequences start from the first matching token to align, and end at the | 540 | | // first token of the first line that doesn't need to be aligned. | 541 | | // | 542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line | 543 | | // containing any matching token to be aligned and located after such token. | 544 | 1.67k | auto AlignCurrentSequence = [&] { | 545 | 1.67k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 1.67k | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 1.67k | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 1.67k | Changes); | 549 | 1.67k | } | 550 | 1.67k | WidthLeft = 0; | 551 | 1.67k | WidthAnchor = 0; | 552 | 1.67k | WidthRight = 0; | 553 | 1.67k | StartOfSequence = 0; | 554 | 1.67k | EndOfSequence = 0; | 555 | 1.67k | }; | 556 | | | 557 | 1.67k | unsigned i = StartAt; | 558 | 10.3k | for (unsigned e = Changes.size(); i != e; ++i8.65k ) { | 559 | 10.3k | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) | 560 | 1.65k | break; | 561 | | | 562 | 8.65k | if (Changes[i].NewlinesBefore != 0) { | 563 | 1.11k | CommasBeforeMatch = 0; | 564 | 1.11k | EndOfSequence = i; | 565 | | | 566 | | // Whether to break the alignment sequence because of an empty line. | 567 | 1.11k | bool EmptyLineBreak = | 568 | 1.11k | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines6 ; | 569 | | | 570 | | // Whether to break the alignment sequence because of a line without a | 571 | | // match. | 572 | 1.11k | bool NoMatchBreak = | 573 | 1.11k | !FoundMatchOnLine && !(801 LineIsComment801 && ACS.AcrossComments410 ); | 574 | | | 575 | 1.11k | if (EmptyLineBreak || NoMatchBreak1.10k ) | 576 | 774 | AlignCurrentSequence(); | 577 | | | 578 | | // A new line starts, re-initialize line status tracking bools. | 579 | | // Keep the match state if a string literal is continued on this line. | 580 | 1.11k | if (i == 0 || !Changes[i].Tok->is(tok::string_literal) || | 581 | 1.11k | !Changes[i - 1].Tok->is(tok::string_literal)79 ) { | 582 | 1.06k | FoundMatchOnLine = false; | 583 | 1.06k | } | 584 | 1.11k | LineIsComment = true; | 585 | 1.11k | } | 586 | | | 587 | 8.65k | if (!Changes[i].Tok->is(tok::comment)) | 588 | 8.54k | LineIsComment = false; | 589 | | | 590 | 8.65k | if (Changes[i].Tok->is(tok::comma)) { | 591 | 1.00k | ++CommasBeforeMatch; | 592 | 7.64k | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { | 593 | | // Call AlignTokens recursively, skipping over this scope block. | 594 | 823 | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); | 595 | 823 | i = StoppedAt - 1; | 596 | 823 | continue; | 597 | 823 | } | 598 | | | 599 | 7.83k | if (!Matches(Changes[i])) | 600 | 7.36k | continue; | 601 | | | 602 | | // If there is more than one matching token per line, or if the number of | 603 | | // preceding commas, do not match anymore, end the sequence. | 604 | 468 | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch444 ) | 605 | 42 | AlignCurrentSequence(); | 606 | | | 607 | 468 | CommasBeforeLastMatch = CommasBeforeMatch; | 608 | 468 | FoundMatchOnLine = true; | 609 | | | 610 | 468 | if (StartOfSequence == 0) | 611 | 267 | StartOfSequence = i; | 612 | | | 613 | 468 | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; | 614 | 468 | unsigned ChangeWidthAnchor = 0; | 615 | 468 | unsigned ChangeWidthRight = 0; | 616 | 468 | if (RightJustify) | 617 | 0 | if (ACS.PadOperators) | 618 | 0 | ChangeWidthAnchor = Changes[i].TokenLength; | 619 | 0 | else | 620 | 0 | ChangeWidthLeft += Changes[i].TokenLength; | 621 | 468 | else | 622 | 468 | ChangeWidthRight = Changes[i].TokenLength; | 623 | 2.27k | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 02.25k ; ++j1.80k ) { | 624 | 1.80k | ChangeWidthRight += Changes[j].Spaces; | 625 | | // Changes are generally 1:1 with the tokens, but a change could also be | 626 | | // inside of a token, in which case it's counted more than once: once for | 627 | | // the whitespace surrounding the token (!IsInsideToken) and once for | 628 | | // each whitespace change within it (IsInsideToken). | 629 | | // Therefore, changes inside of a token should only count the space. | 630 | 1.80k | if (!Changes[j].IsInsideToken) | 631 | 1.80k | ChangeWidthRight += Changes[j].TokenLength; | 632 | 1.80k | } | 633 | | | 634 | | // If we are restricted by the maximum column width, end the sequence. | 635 | 468 | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); | 636 | 468 | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); | 637 | 468 | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); | 638 | | // `ColumnLimit == 0` means there is no column limit. | 639 | 468 | if (Style.ColumnLimit != 0 && | 640 | 468 | Style.ColumnLimit < NewLeft + NewAnchor + NewRight) { | 641 | 0 | AlignCurrentSequence(); | 642 | 0 | StartOfSequence = i; | 643 | 0 | WidthLeft = ChangeWidthLeft; | 644 | 0 | WidthAnchor = ChangeWidthAnchor; | 645 | 0 | WidthRight = ChangeWidthRight; | 646 | 468 | } else { | 647 | 468 | WidthLeft = NewLeft; | 648 | 468 | WidthAnchor = NewAnchor; | 649 | 468 | WidthRight = NewRight; | 650 | 468 | } | 651 | 468 | } | 652 | | | 653 | 1.67k | EndOfSequence = i; | 654 | 1.67k | AlignCurrentSequence(); | 655 | 1.67k | return i; | 656 | 1.67k | } |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool) Line | Count | Source | 498 | 36 | bool RightJustify = false) { | 499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), | 500 | | // and text to its left and right. In the aligned text the width of each part | 501 | | // will be the maximum of that over the block that has been aligned. Maximum | 502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators | 503 | | // is false, the part from start of line to the right end of the anchor. | 504 | | // Otherwise, only the part to the left of the anchor. Including the space | 505 | | // that exists on its left from the start. Not including the padding added on | 506 | | // the left to right-justify the anchor. | 507 | 36 | unsigned WidthLeft = 0; | 508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators | 509 | | // is false. 0 otherwise. | 510 | 36 | unsigned WidthAnchor = 0; | 511 | | // Width to the right of the anchor. Plus width of the anchor when | 512 | | // RightJustify is false. | 513 | 36 | unsigned WidthRight = 0; | 514 | | | 515 | | // Line number of the start and the end of the current token sequence. | 516 | 36 | unsigned StartOfSequence = 0; | 517 | 36 | unsigned EndOfSequence = 0; | 518 | | | 519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and | 520 | | // abort when we hit any token in a higher scope than the starting one. | 521 | 36 | auto IndentAndNestingLevel = StartAt < Changes.size() | 522 | 36 | ? Changes[StartAt].indentAndNestingLevel() | 523 | 36 | : std::tuple<unsigned, unsigned, unsigned>()0 ; | 524 | | | 525 | | // Keep track of the number of commas before the matching tokens, we will only | 526 | | // align a sequence of matching tokens if they are preceded by the same number | 527 | | // of commas. | 528 | 36 | unsigned CommasBeforeLastMatch = 0; | 529 | 36 | unsigned CommasBeforeMatch = 0; | 530 | | | 531 | | // Whether a matching token has been found on the current line. | 532 | 36 | bool FoundMatchOnLine = false; | 533 | | | 534 | | // Whether the current line consists purely of comments. | 535 | 36 | bool LineIsComment = true; | 536 | | | 537 | | // Aligns a sequence of matching tokens, on the MinColumn column. | 538 | | // | 539 | | // Sequences start from the first matching token to align, and end at the | 540 | | // first token of the first line that doesn't need to be aligned. | 541 | | // | 542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line | 543 | | // containing any matching token to be aligned and located after such token. | 544 | 36 | auto AlignCurrentSequence = [&] { | 545 | 36 | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 36 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 36 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 36 | Changes); | 549 | 36 | } | 550 | 36 | WidthLeft = 0; | 551 | 36 | WidthAnchor = 0; | 552 | 36 | WidthRight = 0; | 553 | 36 | StartOfSequence = 0; | 554 | 36 | EndOfSequence = 0; | 555 | 36 | }; | 556 | | | 557 | 36 | unsigned i = StartAt; | 558 | 538 | for (unsigned e = Changes.size(); i != e; ++i502 ) { | 559 | 502 | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) | 560 | 0 | break; | 561 | | | 562 | 502 | if (Changes[i].NewlinesBefore != 0) { | 563 | 43 | CommasBeforeMatch = 0; | 564 | 43 | EndOfSequence = i; | 565 | | | 566 | | // Whether to break the alignment sequence because of an empty line. | 567 | 43 | bool EmptyLineBreak = | 568 | 43 | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines5 ; | 569 | | | 570 | | // Whether to break the alignment sequence because of a line without a | 571 | | // match. | 572 | 43 | bool NoMatchBreak = | 573 | 43 | !FoundMatchOnLine && !(4 LineIsComment4 && ACS.AcrossComments4 ); | 574 | | | 575 | 43 | if (EmptyLineBreak || NoMatchBreak) | 576 | 0 | AlignCurrentSequence(); | 577 | | | 578 | | // A new line starts, re-initialize line status tracking bools. | 579 | | // Keep the match state if a string literal is continued on this line. | 580 | 43 | if (i == 0 || !Changes[i].Tok->is(tok::string_literal) || | 581 | 43 | !Changes[i - 1].Tok->is(tok::string_literal)0 ) { | 582 | 43 | FoundMatchOnLine = false; | 583 | 43 | } | 584 | 43 | LineIsComment = true; | 585 | 43 | } | 586 | | | 587 | 502 | if (!Changes[i].Tok->is(tok::comment)) | 588 | 492 | LineIsComment = false; | 589 | | | 590 | 502 | if (Changes[i].Tok->is(tok::comma)) { | 591 | 0 | ++CommasBeforeMatch; | 592 | 502 | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { | 593 | | // Call AlignTokens recursively, skipping over this scope block. | 594 | 3 | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); | 595 | 3 | i = StoppedAt - 1; | 596 | 3 | continue; | 597 | 3 | } | 598 | | | 599 | 499 | if (!Matches(Changes[i])) | 600 | 424 | continue; | 601 | | | 602 | | // If there is more than one matching token per line, or if the number of | 603 | | // preceding commas, do not match anymore, end the sequence. | 604 | 75 | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch) | 605 | 0 | AlignCurrentSequence(); | 606 | | | 607 | 75 | CommasBeforeLastMatch = CommasBeforeMatch; | 608 | 75 | FoundMatchOnLine = true; | 609 | | | 610 | 75 | if (StartOfSequence == 0) | 611 | 36 | StartOfSequence = i; | 612 | | | 613 | 75 | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; | 614 | 75 | unsigned ChangeWidthAnchor = 0; | 615 | 75 | unsigned ChangeWidthRight = 0; | 616 | 75 | if (RightJustify) | 617 | 0 | if (ACS.PadOperators) | 618 | 0 | ChangeWidthAnchor = Changes[i].TokenLength; | 619 | 0 | else | 620 | 0 | ChangeWidthLeft += Changes[i].TokenLength; | 621 | 75 | else | 622 | 75 | ChangeWidthRight = Changes[i].TokenLength; | 623 | 321 | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 0285 ; ++j246 ) { | 624 | 246 | ChangeWidthRight += Changes[j].Spaces; | 625 | | // Changes are generally 1:1 with the tokens, but a change could also be | 626 | | // inside of a token, in which case it's counted more than once: once for | 627 | | // the whitespace surrounding the token (!IsInsideToken) and once for | 628 | | // each whitespace change within it (IsInsideToken). | 629 | | // Therefore, changes inside of a token should only count the space. | 630 | 246 | if (!Changes[j].IsInsideToken) | 631 | 246 | ChangeWidthRight += Changes[j].TokenLength; | 632 | 246 | } | 633 | | | 634 | | // If we are restricted by the maximum column width, end the sequence. | 635 | 75 | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); | 636 | 75 | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); | 637 | 75 | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); | 638 | | // `ColumnLimit == 0` means there is no column limit. | 639 | 75 | if (Style.ColumnLimit != 0 && | 640 | 75 | Style.ColumnLimit < NewLeft + NewAnchor + NewRight) { | 641 | 0 | AlignCurrentSequence(); | 642 | 0 | StartOfSequence = i; | 643 | 0 | WidthLeft = ChangeWidthLeft; | 644 | 0 | WidthAnchor = ChangeWidthAnchor; | 645 | 0 | WidthRight = ChangeWidthRight; | 646 | 75 | } else { | 647 | 75 | WidthLeft = NewLeft; | 648 | 75 | WidthAnchor = NewAnchor; | 649 | 75 | WidthRight = NewRight; | 650 | 75 | } | 651 | 75 | } | 652 | | | 653 | 36 | EndOfSequence = i; | 654 | 36 | AlignCurrentSequence(); | 655 | 36 | return i; | 656 | 36 | } |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2&>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveBitFields()::$_2&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool) Line | Count | Source | 498 | 3 | bool RightJustify = false) { | 499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), | 500 | | // and text to its left and right. In the aligned text the width of each part | 501 | | // will be the maximum of that over the block that has been aligned. Maximum | 502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators | 503 | | // is false, the part from start of line to the right end of the anchor. | 504 | | // Otherwise, only the part to the left of the anchor. Including the space | 505 | | // that exists on its left from the start. Not including the padding added on | 506 | | // the left to right-justify the anchor. | 507 | 3 | unsigned WidthLeft = 0; | 508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators | 509 | | // is false. 0 otherwise. | 510 | 3 | unsigned WidthAnchor = 0; | 511 | | // Width to the right of the anchor. Plus width of the anchor when | 512 | | // RightJustify is false. | 513 | 3 | unsigned WidthRight = 0; | 514 | | | 515 | | // Line number of the start and the end of the current token sequence. | 516 | 3 | unsigned StartOfSequence = 0; | 517 | 3 | unsigned EndOfSequence = 0; | 518 | | | 519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and | 520 | | // abort when we hit any token in a higher scope than the starting one. | 521 | 3 | auto IndentAndNestingLevel = StartAt < Changes.size() | 522 | 3 | ? Changes[StartAt].indentAndNestingLevel() | 523 | 3 | : std::tuple<unsigned, unsigned, unsigned>()0 ; | 524 | | | 525 | | // Keep track of the number of commas before the matching tokens, we will only | 526 | | // align a sequence of matching tokens if they are preceded by the same number | 527 | | // of commas. | 528 | 3 | unsigned CommasBeforeLastMatch = 0; | 529 | 3 | unsigned CommasBeforeMatch = 0; | 530 | | | 531 | | // Whether a matching token has been found on the current line. | 532 | 3 | bool FoundMatchOnLine = false; | 533 | | | 534 | | // Whether the current line consists purely of comments. | 535 | 3 | bool LineIsComment = true; | 536 | | | 537 | | // Aligns a sequence of matching tokens, on the MinColumn column. | 538 | | // | 539 | | // Sequences start from the first matching token to align, and end at the | 540 | | // first token of the first line that doesn't need to be aligned. | 541 | | // | 542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line | 543 | | // containing any matching token to be aligned and located after such token. | 544 | 3 | auto AlignCurrentSequence = [&] { | 545 | 3 | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 3 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 3 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 3 | Changes); | 549 | 3 | } | 550 | 3 | WidthLeft = 0; | 551 | 3 | WidthAnchor = 0; | 552 | 3 | WidthRight = 0; | 553 | 3 | StartOfSequence = 0; | 554 | 3 | EndOfSequence = 0; | 555 | 3 | }; | 556 | | | 557 | 3 | unsigned i = StartAt; | 558 | 9 | for (unsigned e = Changes.size(); i != e; ++i6 ) { | 559 | 9 | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) | 560 | 3 | break; | 561 | | | 562 | 6 | if (Changes[i].NewlinesBefore != 0) { | 563 | 0 | CommasBeforeMatch = 0; | 564 | 0 | EndOfSequence = i; | 565 | | | 566 | | // Whether to break the alignment sequence because of an empty line. | 567 | 0 | bool EmptyLineBreak = | 568 | 0 | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines; | 569 | | | 570 | | // Whether to break the alignment sequence because of a line without a | 571 | | // match. | 572 | 0 | bool NoMatchBreak = | 573 | 0 | !FoundMatchOnLine && !(LineIsComment && ACS.AcrossComments); | 574 | |
| 575 | 0 | if (EmptyLineBreak || NoMatchBreak) | 576 | 0 | AlignCurrentSequence(); | 577 | | | 578 | | // A new line starts, re-initialize line status tracking bools. | 579 | | // Keep the match state if a string literal is continued on this line. | 580 | 0 | if (i == 0 || !Changes[i].Tok->is(tok::string_literal) || | 581 | 0 | !Changes[i - 1].Tok->is(tok::string_literal)) { | 582 | 0 | FoundMatchOnLine = false; | 583 | 0 | } | 584 | 0 | LineIsComment = true; | 585 | 0 | } | 586 | | | 587 | 6 | if (!Changes[i].Tok->is(tok::comment)) | 588 | 6 | LineIsComment = false; | 589 | | | 590 | 6 | if (Changes[i].Tok->is(tok::comma)) { | 591 | 0 | ++CommasBeforeMatch; | 592 | 6 | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { | 593 | | // Call AlignTokens recursively, skipping over this scope block. | 594 | 0 | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); | 595 | 0 | i = StoppedAt - 1; | 596 | 0 | continue; | 597 | 0 | } | 598 | | | 599 | 6 | if (!Matches(Changes[i])) | 600 | 6 | continue; | 601 | | | 602 | | // If there is more than one matching token per line, or if the number of | 603 | | // preceding commas, do not match anymore, end the sequence. | 604 | 0 | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch) | 605 | 0 | AlignCurrentSequence(); | 606 | |
| 607 | 0 | CommasBeforeLastMatch = CommasBeforeMatch; | 608 | 0 | FoundMatchOnLine = true; | 609 | |
| 610 | 0 | if (StartOfSequence == 0) | 611 | 0 | StartOfSequence = i; | 612 | |
| 613 | 0 | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; | 614 | 0 | unsigned ChangeWidthAnchor = 0; | 615 | 0 | unsigned ChangeWidthRight = 0; | 616 | 0 | if (RightJustify) | 617 | 0 | if (ACS.PadOperators) | 618 | 0 | ChangeWidthAnchor = Changes[i].TokenLength; | 619 | 0 | else | 620 | 0 | ChangeWidthLeft += Changes[i].TokenLength; | 621 | 0 | else | 622 | 0 | ChangeWidthRight = Changes[i].TokenLength; | 623 | 0 | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 0; ++j) { | 624 | 0 | ChangeWidthRight += Changes[j].Spaces; | 625 | | // Changes are generally 1:1 with the tokens, but a change could also be | 626 | | // inside of a token, in which case it's counted more than once: once for | 627 | | // the whitespace surrounding the token (!IsInsideToken) and once for | 628 | | // each whitespace change within it (IsInsideToken). | 629 | | // Therefore, changes inside of a token should only count the space. | 630 | 0 | if (!Changes[j].IsInsideToken) | 631 | 0 | ChangeWidthRight += Changes[j].TokenLength; | 632 | 0 | } | 633 | | | 634 | | // If we are restricted by the maximum column width, end the sequence. | 635 | 0 | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); | 636 | 0 | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); | 637 | 0 | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); | 638 | | // `ColumnLimit == 0` means there is no column limit. | 639 | 0 | if (Style.ColumnLimit != 0 && | 640 | 0 | Style.ColumnLimit < NewLeft + NewAnchor + NewRight) { | 641 | 0 | AlignCurrentSequence(); | 642 | 0 | StartOfSequence = i; | 643 | 0 | WidthLeft = ChangeWidthLeft; | 644 | 0 | WidthAnchor = ChangeWidthAnchor; | 645 | 0 | WidthRight = ChangeWidthRight; | 646 | 0 | } else { | 647 | 0 | WidthLeft = NewLeft; | 648 | 0 | WidthAnchor = NewAnchor; | 649 | 0 | WidthRight = NewRight; | 650 | 0 | } | 651 | 0 | } | 652 | | | 653 | 3 | EndOfSequence = i; | 654 | 3 | AlignCurrentSequence(); | 655 | 3 | return i; | 656 | 3 | } |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool) Line | Count | Source | 498 | 676 | bool RightJustify = false) { | 499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), | 500 | | // and text to its left and right. In the aligned text the width of each part | 501 | | // will be the maximum of that over the block that has been aligned. Maximum | 502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators | 503 | | // is false, the part from start of line to the right end of the anchor. | 504 | | // Otherwise, only the part to the left of the anchor. Including the space | 505 | | // that exists on its left from the start. Not including the padding added on | 506 | | // the left to right-justify the anchor. | 507 | 676 | unsigned WidthLeft = 0; | 508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators | 509 | | // is false. 0 otherwise. | 510 | 676 | unsigned WidthAnchor = 0; | 511 | | // Width to the right of the anchor. Plus width of the anchor when | 512 | | // RightJustify is false. | 513 | 676 | unsigned WidthRight = 0; | 514 | | | 515 | | // Line number of the start and the end of the current token sequence. | 516 | 676 | unsigned StartOfSequence = 0; | 517 | 676 | unsigned EndOfSequence = 0; | 518 | | | 519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and | 520 | | // abort when we hit any token in a higher scope than the starting one. | 521 | 676 | auto IndentAndNestingLevel = StartAt < Changes.size() | 522 | 676 | ? Changes[StartAt].indentAndNestingLevel() | 523 | 676 | : std::tuple<unsigned, unsigned, unsigned>()0 ; | 524 | | | 525 | | // Keep track of the number of commas before the matching tokens, we will only | 526 | | // align a sequence of matching tokens if they are preceded by the same number | 527 | | // of commas. | 528 | 676 | unsigned CommasBeforeLastMatch = 0; | 529 | 676 | unsigned CommasBeforeMatch = 0; | 530 | | | 531 | | // Whether a matching token has been found on the current line. | 532 | 676 | bool FoundMatchOnLine = false; | 533 | | | 534 | | // Whether the current line consists purely of comments. | 535 | 676 | bool LineIsComment = true; | 536 | | | 537 | | // Aligns a sequence of matching tokens, on the MinColumn column. | 538 | | // | 539 | | // Sequences start from the first matching token to align, and end at the | 540 | | // first token of the first line that doesn't need to be aligned. | 541 | | // | 542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line | 543 | | // containing any matching token to be aligned and located after such token. | 544 | 676 | auto AlignCurrentSequence = [&] { | 545 | 676 | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 676 | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 676 | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 676 | Changes); | 549 | 676 | } | 550 | 676 | WidthLeft = 0; | 551 | 676 | WidthAnchor = 0; | 552 | 676 | WidthRight = 0; | 553 | 676 | StartOfSequence = 0; | 554 | 676 | EndOfSequence = 0; | 555 | 676 | }; | 556 | | | 557 | 676 | unsigned i = StartAt; | 558 | 8.08k | for (unsigned e = Changes.size(); i != e; ++i7.40k ) { | 559 | 7.40k | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) | 560 | 0 | break; | 561 | | | 562 | 7.40k | if (Changes[i].NewlinesBefore != 0) { | 563 | 1.04k | CommasBeforeMatch = 0; | 564 | 1.04k | EndOfSequence = i; | 565 | | | 566 | | // Whether to break the alignment sequence because of an empty line. | 567 | 1.04k | bool EmptyLineBreak = | 568 | 1.04k | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines17 ; | 569 | | | 570 | | // Whether to break the alignment sequence because of a line without a | 571 | | // match. | 572 | 1.04k | bool NoMatchBreak = | 573 | 1.04k | !FoundMatchOnLine && !(450 LineIsComment450 && ACS.AcrossComments30 ); | 574 | | | 575 | 1.04k | if (EmptyLineBreak || NoMatchBreak1.02k ) | 576 | 449 | AlignCurrentSequence(); | 577 | | | 578 | | // A new line starts, re-initialize line status tracking bools. | 579 | | // Keep the match state if a string literal is continued on this line. | 580 | 1.04k | if (i == 0 || !Changes[i].Tok->is(tok::string_literal) || | 581 | 1.04k | !Changes[i - 1].Tok->is(tok::string_literal)18 ) { | 582 | 1.04k | FoundMatchOnLine = false; | 583 | 1.04k | } | 584 | 1.04k | LineIsComment = true; | 585 | 1.04k | } | 586 | | | 587 | 7.40k | if (!Changes[i].Tok->is(tok::comment)) | 588 | 7.34k | LineIsComment = false; | 589 | | | 590 | 7.40k | if (Changes[i].Tok->is(tok::comma)) { | 591 | 24 | ++CommasBeforeMatch; | 592 | 7.38k | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { | 593 | | // Call AlignTokens recursively, skipping over this scope block. | 594 | 904 | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); | 595 | 904 | i = StoppedAt - 1; | 596 | 904 | continue; | 597 | 904 | } | 598 | | | 599 | 6.50k | if (!Matches(Changes[i])) | 600 | 5.67k | continue; | 601 | | | 602 | | // If there is more than one matching token per line, or if the number of | 603 | | // preceding commas, do not match anymore, end the sequence. | 604 | 826 | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch) | 605 | 0 | AlignCurrentSequence(); | 606 | | | 607 | 826 | CommasBeforeLastMatch = CommasBeforeMatch; | 608 | 826 | FoundMatchOnLine = true; | 609 | | | 610 | 826 | if (StartOfSequence == 0) | 611 | 455 | StartOfSequence = i; | 612 | | | 613 | 826 | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; | 614 | 826 | unsigned ChangeWidthAnchor = 0; | 615 | 826 | unsigned ChangeWidthRight = 0; | 616 | 826 | if (RightJustify) | 617 | 0 | if (ACS.PadOperators) | 618 | 0 | ChangeWidthAnchor = Changes[i].TokenLength; | 619 | 0 | else | 620 | 0 | ChangeWidthLeft += Changes[i].TokenLength; | 621 | 826 | else | 622 | 826 | ChangeWidthRight = Changes[i].TokenLength; | 623 | 4.20k | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 03.97k ; ++j3.37k ) { | 624 | 3.37k | ChangeWidthRight += Changes[j].Spaces; | 625 | | // Changes are generally 1:1 with the tokens, but a change could also be | 626 | | // inside of a token, in which case it's counted more than once: once for | 627 | | // the whitespace surrounding the token (!IsInsideToken) and once for | 628 | | // each whitespace change within it (IsInsideToken). | 629 | | // Therefore, changes inside of a token should only count the space. | 630 | 3.37k | if (!Changes[j].IsInsideToken) | 631 | 3.37k | ChangeWidthRight += Changes[j].TokenLength; | 632 | 3.37k | } | 633 | | | 634 | | // If we are restricted by the maximum column width, end the sequence. | 635 | 826 | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); | 636 | 826 | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); | 637 | 826 | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); | 638 | | // `ColumnLimit == 0` means there is no column limit. | 639 | 826 | if (Style.ColumnLimit != 0 && | 640 | 826 | Style.ColumnLimit < NewLeft + NewAnchor + NewRight821 ) { | 641 | 6 | AlignCurrentSequence(); | 642 | 6 | StartOfSequence = i; | 643 | 6 | WidthLeft = ChangeWidthLeft; | 644 | 6 | WidthAnchor = ChangeWidthAnchor; | 645 | 6 | WidthRight = ChangeWidthRight; | 646 | 820 | } else { | 647 | 820 | WidthLeft = NewLeft; | 648 | 820 | WidthAnchor = NewAnchor; | 649 | 820 | WidthRight = NewRight; | 650 | 820 | } | 651 | 826 | } | 652 | | | 653 | 676 | EndOfSequence = i; | 654 | 676 | AlignCurrentSequence(); | 655 | 676 | return i; | 656 | 676 | } |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3&>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignConsecutiveDeclarations()::$_3&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool) Line | Count | Source | 498 | 1.74k | bool RightJustify = false) { | 499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), | 500 | | // and text to its left and right. In the aligned text the width of each part | 501 | | // will be the maximum of that over the block that has been aligned. Maximum | 502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators | 503 | | // is false, the part from start of line to the right end of the anchor. | 504 | | // Otherwise, only the part to the left of the anchor. Including the space | 505 | | // that exists on its left from the start. Not including the padding added on | 506 | | // the left to right-justify the anchor. | 507 | 1.74k | unsigned WidthLeft = 0; | 508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators | 509 | | // is false. 0 otherwise. | 510 | 1.74k | unsigned WidthAnchor = 0; | 511 | | // Width to the right of the anchor. Plus width of the anchor when | 512 | | // RightJustify is false. | 513 | 1.74k | unsigned WidthRight = 0; | 514 | | | 515 | | // Line number of the start and the end of the current token sequence. | 516 | 1.74k | unsigned StartOfSequence = 0; | 517 | 1.74k | unsigned EndOfSequence = 0; | 518 | | | 519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and | 520 | | // abort when we hit any token in a higher scope than the starting one. | 521 | 1.74k | auto IndentAndNestingLevel = StartAt < Changes.size() | 522 | 1.74k | ? Changes[StartAt].indentAndNestingLevel() | 523 | 1.74k | : std::tuple<unsigned, unsigned, unsigned>()0 ; | 524 | | | 525 | | // Keep track of the number of commas before the matching tokens, we will only | 526 | | // align a sequence of matching tokens if they are preceded by the same number | 527 | | // of commas. | 528 | 1.74k | unsigned CommasBeforeLastMatch = 0; | 529 | 1.74k | unsigned CommasBeforeMatch = 0; | 530 | | | 531 | | // Whether a matching token has been found on the current line. | 532 | 1.74k | bool FoundMatchOnLine = false; | 533 | | | 534 | | // Whether the current line consists purely of comments. | 535 | 1.74k | bool LineIsComment = true; | 536 | | | 537 | | // Aligns a sequence of matching tokens, on the MinColumn column. | 538 | | // | 539 | | // Sequences start from the first matching token to align, and end at the | 540 | | // first token of the first line that doesn't need to be aligned. | 541 | | // | 542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line | 543 | | // containing any matching token to be aligned and located after such token. | 544 | 1.74k | auto AlignCurrentSequence = [&] { | 545 | 1.74k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 1.74k | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 1.74k | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 1.74k | Changes); | 549 | 1.74k | } | 550 | 1.74k | WidthLeft = 0; | 551 | 1.74k | WidthAnchor = 0; | 552 | 1.74k | WidthRight = 0; | 553 | 1.74k | StartOfSequence = 0; | 554 | 1.74k | EndOfSequence = 0; | 555 | 1.74k | }; | 556 | | | 557 | 1.74k | unsigned i = StartAt; | 558 | 12.0k | for (unsigned e = Changes.size(); i != e; ++i10.2k ) { | 559 | 12.0k | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) | 560 | 1.74k | break; | 561 | | | 562 | 10.2k | if (Changes[i].NewlinesBefore != 0) { | 563 | 951 | CommasBeforeMatch = 0; | 564 | 951 | EndOfSequence = i; | 565 | | | 566 | | // Whether to break the alignment sequence because of an empty line. | 567 | 951 | bool EmptyLineBreak = | 568 | 951 | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines6 ; | 569 | | | 570 | | // Whether to break the alignment sequence because of a line without a | 571 | | // match. | 572 | 951 | bool NoMatchBreak = | 573 | 951 | !FoundMatchOnLine && !(667 LineIsComment667 && ACS.AcrossComments353 ); | 574 | | | 575 | 951 | if (EmptyLineBreak || NoMatchBreak945 ) | 576 | 673 | AlignCurrentSequence(); | 577 | | | 578 | | // A new line starts, re-initialize line status tracking bools. | 579 | | // Keep the match state if a string literal is continued on this line. | 580 | 951 | if (i == 0 || !Changes[i].Tok->is(tok::string_literal) || | 581 | 951 | !Changes[i - 1].Tok->is(tok::string_literal)79 ) { | 582 | 905 | FoundMatchOnLine = false; | 583 | 905 | } | 584 | 951 | LineIsComment = true; | 585 | 951 | } | 586 | | | 587 | 10.2k | if (!Changes[i].Tok->is(tok::comment)) | 588 | 10.1k | LineIsComment = false; | 589 | | | 590 | 10.2k | if (Changes[i].Tok->is(tok::comma)) { | 591 | 1.30k | ++CommasBeforeMatch; | 592 | 8.96k | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { | 593 | | // Call AlignTokens recursively, skipping over this scope block. | 594 | 844 | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); | 595 | 844 | i = StoppedAt - 1; | 596 | 844 | continue; | 597 | 844 | } | 598 | | | 599 | 9.42k | if (!Matches(Changes[i])) | 600 | 8.68k | continue; | 601 | | | 602 | | // If there is more than one matching token per line, or if the number of | 603 | | // preceding commas, do not match anymore, end the sequence. | 604 | 741 | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch555 ) | 605 | 189 | AlignCurrentSequence(); | 606 | | | 607 | 741 | CommasBeforeLastMatch = CommasBeforeMatch; | 608 | 741 | FoundMatchOnLine = true; | 609 | | | 610 | 741 | if (StartOfSequence == 0) | 611 | 555 | StartOfSequence = i; | 612 | | | 613 | 741 | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; | 614 | 741 | unsigned ChangeWidthAnchor = 0; | 615 | 741 | unsigned ChangeWidthRight = 0; | 616 | 741 | if (RightJustify) | 617 | 0 | if (ACS.PadOperators) | 618 | 0 | ChangeWidthAnchor = Changes[i].TokenLength; | 619 | 0 | else | 620 | 0 | ChangeWidthLeft += Changes[i].TokenLength; | 621 | 741 | else | 622 | 741 | ChangeWidthRight = Changes[i].TokenLength; | 623 | 6.32k | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 05.97k ; ++j5.58k ) { | 624 | 5.58k | ChangeWidthRight += Changes[j].Spaces; | 625 | | // Changes are generally 1:1 with the tokens, but a change could also be | 626 | | // inside of a token, in which case it's counted more than once: once for | 627 | | // the whitespace surrounding the token (!IsInsideToken) and once for | 628 | | // each whitespace change within it (IsInsideToken). | 629 | | // Therefore, changes inside of a token should only count the space. | 630 | 5.58k | if (!Changes[j].IsInsideToken) | 631 | 5.58k | ChangeWidthRight += Changes[j].TokenLength; | 632 | 5.58k | } | 633 | | | 634 | | // If we are restricted by the maximum column width, end the sequence. | 635 | 741 | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); | 636 | 741 | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); | 637 | 741 | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); | 638 | | // `ColumnLimit == 0` means there is no column limit. | 639 | 741 | if (Style.ColumnLimit != 0 && | 640 | 741 | Style.ColumnLimit < NewLeft + NewAnchor + NewRight734 ) { | 641 | 0 | AlignCurrentSequence(); | 642 | 0 | StartOfSequence = i; | 643 | 0 | WidthLeft = ChangeWidthLeft; | 644 | 0 | WidthAnchor = ChangeWidthAnchor; | 645 | 0 | WidthRight = ChangeWidthRight; | 646 | 741 | } else { | 647 | 741 | WidthLeft = NewLeft; | 648 | 741 | WidthAnchor = NewAnchor; | 649 | 741 | WidthRight = NewRight; | 650 | 741 | } | 651 | 741 | } | 652 | | | 653 | 1.74k | EndOfSequence = i; | 654 | 1.74k | AlignCurrentSequence(); | 655 | 1.74k | return i; | 656 | 1.74k | } |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignChainedConditionals()::$_4>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignChainedConditionals()::$_4&&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool) Line | Count | Source | 498 | 20.9k | bool RightJustify = false) { | 499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), | 500 | | // and text to its left and right. In the aligned text the width of each part | 501 | | // will be the maximum of that over the block that has been aligned. Maximum | 502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators | 503 | | // is false, the part from start of line to the right end of the anchor. | 504 | | // Otherwise, only the part to the left of the anchor. Including the space | 505 | | // that exists on its left from the start. Not including the padding added on | 506 | | // the left to right-justify the anchor. | 507 | 20.9k | unsigned WidthLeft = 0; | 508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators | 509 | | // is false. 0 otherwise. | 510 | 20.9k | unsigned WidthAnchor = 0; | 511 | | // Width to the right of the anchor. Plus width of the anchor when | 512 | | // RightJustify is false. | 513 | 20.9k | unsigned WidthRight = 0; | 514 | | | 515 | | // Line number of the start and the end of the current token sequence. | 516 | 20.9k | unsigned StartOfSequence = 0; | 517 | 20.9k | unsigned EndOfSequence = 0; | 518 | | | 519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and | 520 | | // abort when we hit any token in a higher scope than the starting one. | 521 | 20.9k | auto IndentAndNestingLevel = StartAt < Changes.size() | 522 | 20.9k | ? Changes[StartAt].indentAndNestingLevel() | 523 | 20.9k | : std::tuple<unsigned, unsigned, unsigned>()0 ; | 524 | | | 525 | | // Keep track of the number of commas before the matching tokens, we will only | 526 | | // align a sequence of matching tokens if they are preceded by the same number | 527 | | // of commas. | 528 | 20.9k | unsigned CommasBeforeLastMatch = 0; | 529 | 20.9k | unsigned CommasBeforeMatch = 0; | 530 | | | 531 | | // Whether a matching token has been found on the current line. | 532 | 20.9k | bool FoundMatchOnLine = false; | 533 | | | 534 | | // Whether the current line consists purely of comments. | 535 | 20.9k | bool LineIsComment = true; | 536 | | | 537 | | // Aligns a sequence of matching tokens, on the MinColumn column. | 538 | | // | 539 | | // Sequences start from the first matching token to align, and end at the | 540 | | // first token of the first line that doesn't need to be aligned. | 541 | | // | 542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line | 543 | | // containing any matching token to be aligned and located after such token. | 544 | 20.9k | auto AlignCurrentSequence = [&] { | 545 | 20.9k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 20.9k | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 20.9k | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 20.9k | Changes); | 549 | 20.9k | } | 550 | 20.9k | WidthLeft = 0; | 551 | 20.9k | WidthAnchor = 0; | 552 | 20.9k | WidthRight = 0; | 553 | 20.9k | StartOfSequence = 0; | 554 | 20.9k | EndOfSequence = 0; | 555 | 20.9k | }; | 556 | | | 557 | 20.9k | unsigned i = StartAt; | 558 | 226k | for (unsigned e = Changes.size(); i != e; ++i205k ) { | 559 | 205k | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) | 560 | 24 | break; | 561 | | | 562 | 205k | if (Changes[i].NewlinesBefore != 0) { | 563 | 32.2k | CommasBeforeMatch = 0; | 564 | 32.2k | EndOfSequence = i; | 565 | | | 566 | | // Whether to break the alignment sequence because of an empty line. | 567 | 32.2k | bool EmptyLineBreak = | 568 | 32.2k | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines1.05k ; | 569 | | | 570 | | // Whether to break the alignment sequence because of a line without a | 571 | | // match. | 572 | 32.2k | bool NoMatchBreak = | 573 | 32.2k | !FoundMatchOnLine && !(32.2k LineIsComment32.2k && ACS.AcrossComments3.00k ); | 574 | | | 575 | 32.2k | if (EmptyLineBreak || NoMatchBreak31.2k ) | 576 | 32.2k | AlignCurrentSequence(); | 577 | | | 578 | | // A new line starts, re-initialize line status tracking bools. | 579 | | // Keep the match state if a string literal is continued on this line. | 580 | 32.2k | if (i == 0 || !Changes[i].Tok->is(tok::string_literal)31.6k || | 581 | 32.2k | !Changes[i - 1].Tok->is(tok::string_literal)229 ) { | 582 | 32.1k | FoundMatchOnLine = false; | 583 | 32.1k | } | 584 | 32.2k | LineIsComment = true; | 585 | 32.2k | } | 586 | | | 587 | 205k | if (!Changes[i].Tok->is(tok::comment)) | 588 | 200k | LineIsComment = false; | 589 | | | 590 | 205k | if (Changes[i].Tok->is(tok::comma)) { | 591 | 1.01k | ++CommasBeforeMatch; | 592 | 204k | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { | 593 | | // Call AlignTokens recursively, skipping over this scope block. | 594 | 33.0k | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); | 595 | 33.0k | i = StoppedAt - 1; | 596 | 33.0k | continue; | 597 | 33.0k | } | 598 | | | 599 | 172k | if (!Matches(Changes[i])) | 600 | 172k | continue; | 601 | | | 602 | | // If there is more than one matching token per line, or if the number of | 603 | | // preceding commas, do not match anymore, end the sequence. | 604 | 24 | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch17 ) | 605 | 7 | AlignCurrentSequence(); | 606 | | | 607 | 24 | CommasBeforeLastMatch = CommasBeforeMatch; | 608 | 24 | FoundMatchOnLine = true; | 609 | | | 610 | 24 | if (StartOfSequence == 0) | 611 | 24 | StartOfSequence = i; | 612 | | | 613 | 24 | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; | 614 | 24 | unsigned ChangeWidthAnchor = 0; | 615 | 24 | unsigned ChangeWidthRight = 0; | 616 | 24 | if (RightJustify) | 617 | 0 | if (ACS.PadOperators) | 618 | 0 | ChangeWidthAnchor = Changes[i].TokenLength; | 619 | 0 | else | 620 | 0 | ChangeWidthLeft += Changes[i].TokenLength; | 621 | 24 | else | 622 | 24 | ChangeWidthRight = Changes[i].TokenLength; | 623 | 158 | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 0137 ; ++j134 ) { | 624 | 134 | ChangeWidthRight += Changes[j].Spaces; | 625 | | // Changes are generally 1:1 with the tokens, but a change could also be | 626 | | // inside of a token, in which case it's counted more than once: once for | 627 | | // the whitespace surrounding the token (!IsInsideToken) and once for | 628 | | // each whitespace change within it (IsInsideToken). | 629 | | // Therefore, changes inside of a token should only count the space. | 630 | 134 | if (!Changes[j].IsInsideToken) | 631 | 134 | ChangeWidthRight += Changes[j].TokenLength; | 632 | 134 | } | 633 | | | 634 | | // If we are restricted by the maximum column width, end the sequence. | 635 | 24 | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); | 636 | 24 | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); | 637 | 24 | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); | 638 | | // `ColumnLimit == 0` means there is no column limit. | 639 | 24 | if (Style.ColumnLimit != 0 && | 640 | 24 | Style.ColumnLimit < NewLeft + NewAnchor + NewRight) { | 641 | 0 | AlignCurrentSequence(); | 642 | 0 | StartOfSequence = i; | 643 | 0 | WidthLeft = ChangeWidthLeft; | 644 | 0 | WidthAnchor = ChangeWidthAnchor; | 645 | 0 | WidthRight = ChangeWidthRight; | 646 | 24 | } else { | 647 | 24 | WidthLeft = NewLeft; | 648 | 24 | WidthAnchor = NewAnchor; | 649 | 24 | WidthRight = NewRight; | 650 | 24 | } | 651 | 24 | } | 652 | | | 653 | 20.9k | EndOfSequence = i; | 654 | 20.9k | AlignCurrentSequence(); | 655 | 20.9k | return i; | 656 | 20.9k | } |
WhitespaceManager.cpp:unsigned int clang::format::AlignTokens<clang::format::WhitespaceManager::alignChainedConditionals()::$_4&>(clang::format::FormatStyle const&, clang::format::WhitespaceManager::alignChainedConditionals()::$_4&, llvm::SmallVector<clang::format::WhitespaceManager::Change, 16u>&, unsigned int, clang::format::FormatStyle::AlignConsecutiveStyle const&, bool) Line | Count | Source | 498 | 54.8k | bool RightJustify = false) { | 499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), | 500 | | // and text to its left and right. In the aligned text the width of each part | 501 | | // will be the maximum of that over the block that has been aligned. Maximum | 502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators | 503 | | // is false, the part from start of line to the right end of the anchor. | 504 | | // Otherwise, only the part to the left of the anchor. Including the space | 505 | | // that exists on its left from the start. Not including the padding added on | 506 | | // the left to right-justify the anchor. | 507 | 54.8k | unsigned WidthLeft = 0; | 508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators | 509 | | // is false. 0 otherwise. | 510 | 54.8k | unsigned WidthAnchor = 0; | 511 | | // Width to the right of the anchor. Plus width of the anchor when | 512 | | // RightJustify is false. | 513 | 54.8k | unsigned WidthRight = 0; | 514 | | | 515 | | // Line number of the start and the end of the current token sequence. | 516 | 54.8k | unsigned StartOfSequence = 0; | 517 | 54.8k | unsigned EndOfSequence = 0; | 518 | | | 519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and | 520 | | // abort when we hit any token in a higher scope than the starting one. | 521 | 54.8k | auto IndentAndNestingLevel = StartAt < Changes.size() | 522 | 54.8k | ? Changes[StartAt].indentAndNestingLevel() | 523 | 54.8k | : std::tuple<unsigned, unsigned, unsigned>()0 ; | 524 | | | 525 | | // Keep track of the number of commas before the matching tokens, we will only | 526 | | // align a sequence of matching tokens if they are preceded by the same number | 527 | | // of commas. | 528 | 54.8k | unsigned CommasBeforeLastMatch = 0; | 529 | 54.8k | unsigned CommasBeforeMatch = 0; | 530 | | | 531 | | // Whether a matching token has been found on the current line. | 532 | 54.8k | bool FoundMatchOnLine = false; | 533 | | | 534 | | // Whether the current line consists purely of comments. | 535 | 54.8k | bool LineIsComment = true; | 536 | | | 537 | | // Aligns a sequence of matching tokens, on the MinColumn column. | 538 | | // | 539 | | // Sequences start from the first matching token to align, and end at the | 540 | | // first token of the first line that doesn't need to be aligned. | 541 | | // | 542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line | 543 | | // containing any matching token to be aligned and located after such token. | 544 | 54.8k | auto AlignCurrentSequence = [&] { | 545 | 54.8k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 54.8k | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 54.8k | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 54.8k | Changes); | 549 | 54.8k | } | 550 | 54.8k | WidthLeft = 0; | 551 | 54.8k | WidthAnchor = 0; | 552 | 54.8k | WidthRight = 0; | 553 | 54.8k | StartOfSequence = 0; | 554 | 54.8k | EndOfSequence = 0; | 555 | 54.8k | }; | 556 | | | 557 | 54.8k | unsigned i = StartAt; | 558 | 260k | for (unsigned e = Changes.size(); i != e; ++i205k ) { | 559 | 260k | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) | 560 | 54.7k | break; | 561 | | | 562 | 205k | if (Changes[i].NewlinesBefore != 0) { | 563 | 27.2k | CommasBeforeMatch = 0; | 564 | 27.2k | EndOfSequence = i; | 565 | | | 566 | | // Whether to break the alignment sequence because of an empty line. | 567 | 27.2k | bool EmptyLineBreak = | 568 | 27.2k | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines268 ; | 569 | | | 570 | | // Whether to break the alignment sequence because of a line without a | 571 | | // match. | 572 | 27.2k | bool NoMatchBreak = | 573 | 27.2k | !FoundMatchOnLine && !(26.9k LineIsComment26.9k && ACS.AcrossComments12.3k ); | 574 | | | 575 | 27.2k | if (EmptyLineBreak || NoMatchBreak26.9k ) | 576 | 26.9k | AlignCurrentSequence(); | 577 | | | 578 | | // A new line starts, re-initialize line status tracking bools. | 579 | | // Keep the match state if a string literal is continued on this line. | 580 | 27.2k | if (i == 0 || !Changes[i].Tok->is(tok::string_literal) || | 581 | 27.2k | !Changes[i - 1].Tok->is(tok::string_literal)583 ) { | 582 | 27.0k | FoundMatchOnLine = false; | 583 | 27.0k | } | 584 | 27.2k | LineIsComment = true; | 585 | 27.2k | } | 586 | | | 587 | 205k | if (!Changes[i].Tok->is(tok::comment)) | 588 | 203k | LineIsComment = false; | 589 | | | 590 | 205k | if (Changes[i].Tok->is(tok::comma)) { | 591 | 10.0k | ++CommasBeforeMatch; | 592 | 195k | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { | 593 | | // Call AlignTokens recursively, skipping over this scope block. | 594 | 21.7k | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); | 595 | 21.7k | i = StoppedAt - 1; | 596 | 21.7k | continue; | 597 | 21.7k | } | 598 | | | 599 | 184k | if (!Matches(Changes[i])) | 600 | 183k | continue; | 601 | | | 602 | | // If there is more than one matching token per line, or if the number of | 603 | | // preceding commas, do not match anymore, end the sequence. | 604 | 769 | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch616 ) | 605 | 157 | AlignCurrentSequence(); | 606 | | | 607 | 769 | CommasBeforeLastMatch = CommasBeforeMatch; | 608 | 769 | FoundMatchOnLine = true; | 609 | | | 610 | 769 | if (StartOfSequence == 0) | 611 | 532 | StartOfSequence = i; | 612 | | | 613 | 769 | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; | 614 | 769 | unsigned ChangeWidthAnchor = 0; | 615 | 769 | unsigned ChangeWidthRight = 0; | 616 | 769 | if (RightJustify) | 617 | 0 | if (ACS.PadOperators) | 618 | 0 | ChangeWidthAnchor = Changes[i].TokenLength; | 619 | 0 | else | 620 | 0 | ChangeWidthLeft += Changes[i].TokenLength; | 621 | 769 | else | 622 | 769 | ChangeWidthRight = Changes[i].TokenLength; | 623 | 3.55k | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 03.21k ; ++j2.78k ) { | 624 | 2.78k | ChangeWidthRight += Changes[j].Spaces; | 625 | | // Changes are generally 1:1 with the tokens, but a change could also be | 626 | | // inside of a token, in which case it's counted more than once: once for | 627 | | // the whitespace surrounding the token (!IsInsideToken) and once for | 628 | | // each whitespace change within it (IsInsideToken). | 629 | | // Therefore, changes inside of a token should only count the space. | 630 | 2.78k | if (!Changes[j].IsInsideToken) | 631 | 2.78k | ChangeWidthRight += Changes[j].TokenLength; | 632 | 2.78k | } | 633 | | | 634 | | // If we are restricted by the maximum column width, end the sequence. | 635 | 769 | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); | 636 | 769 | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); | 637 | 769 | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); | 638 | | // `ColumnLimit == 0` means there is no column limit. | 639 | 769 | if (Style.ColumnLimit != 0 && | 640 | 769 | Style.ColumnLimit < NewLeft + NewAnchor + NewRight) { | 641 | 0 | AlignCurrentSequence(); | 642 | 0 | StartOfSequence = i; | 643 | 0 | WidthLeft = ChangeWidthLeft; | 644 | 0 | WidthAnchor = ChangeWidthAnchor; | 645 | 0 | WidthRight = ChangeWidthRight; | 646 | 769 | } else { | 647 | 769 | WidthLeft = NewLeft; | 648 | 769 | WidthAnchor = NewAnchor; | 649 | 769 | WidthRight = NewRight; | 650 | 769 | } | 651 | 769 | } | 652 | | | 653 | 54.8k | EndOfSequence = i; | 654 | 54.8k | AlignCurrentSequence(); | 655 | 54.8k | return i; | 656 | 54.8k | } |
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 | 498 | 1.60k | bool RightJustify = false) { | 499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), | 500 | | // and text to its left and right. In the aligned text the width of each part | 501 | | // will be the maximum of that over the block that has been aligned. Maximum | 502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators | 503 | | // is false, the part from start of line to the right end of the anchor. | 504 | | // Otherwise, only the part to the left of the anchor. Including the space | 505 | | // that exists on its left from the start. Not including the padding added on | 506 | | // the left to right-justify the anchor. | 507 | 1.60k | unsigned WidthLeft = 0; | 508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators | 509 | | // is false. 0 otherwise. | 510 | 1.60k | unsigned WidthAnchor = 0; | 511 | | // Width to the right of the anchor. Plus width of the anchor when | 512 | | // RightJustify is false. | 513 | 1.60k | unsigned WidthRight = 0; | 514 | | | 515 | | // Line number of the start and the end of the current token sequence. | 516 | 1.60k | unsigned StartOfSequence = 0; | 517 | 1.60k | unsigned EndOfSequence = 0; | 518 | | | 519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and | 520 | | // abort when we hit any token in a higher scope than the starting one. | 521 | 1.60k | auto IndentAndNestingLevel = StartAt < Changes.size() | 522 | 1.60k | ? Changes[StartAt].indentAndNestingLevel() | 523 | 1.60k | : std::tuple<unsigned, unsigned, unsigned>()0 ; | 524 | | | 525 | | // Keep track of the number of commas before the matching tokens, we will only | 526 | | // align a sequence of matching tokens if they are preceded by the same number | 527 | | // of commas. | 528 | 1.60k | unsigned CommasBeforeLastMatch = 0; | 529 | 1.60k | unsigned CommasBeforeMatch = 0; | 530 | | | 531 | | // Whether a matching token has been found on the current line. | 532 | 1.60k | bool FoundMatchOnLine = false; | 533 | | | 534 | | // Whether the current line consists purely of comments. | 535 | 1.60k | bool LineIsComment = true; | 536 | | | 537 | | // Aligns a sequence of matching tokens, on the MinColumn column. | 538 | | // | 539 | | // Sequences start from the first matching token to align, and end at the | 540 | | // first token of the first line that doesn't need to be aligned. | 541 | | // | 542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line | 543 | | // containing any matching token to be aligned and located after such token. | 544 | 1.60k | auto AlignCurrentSequence = [&] { | 545 | 1.60k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 1.60k | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 1.60k | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 1.60k | Changes); | 549 | 1.60k | } | 550 | 1.60k | WidthLeft = 0; | 551 | 1.60k | WidthAnchor = 0; | 552 | 1.60k | WidthRight = 0; | 553 | 1.60k | StartOfSequence = 0; | 554 | 1.60k | EndOfSequence = 0; | 555 | 1.60k | }; | 556 | | | 557 | 1.60k | unsigned i = StartAt; | 558 | 13.9k | for (unsigned e = Changes.size(); i != e; ++i12.2k ) { | 559 | 12.3k | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) | 560 | 11 | break; | 561 | | | 562 | 12.2k | if (Changes[i].NewlinesBefore != 0) { | 563 | 1.59k | CommasBeforeMatch = 0; | 564 | 1.59k | EndOfSequence = i; | 565 | | | 566 | | // Whether to break the alignment sequence because of an empty line. | 567 | 1.59k | bool EmptyLineBreak = | 568 | 1.59k | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines34 ; | 569 | | | 570 | | // Whether to break the alignment sequence because of a line without a | 571 | | // match. | 572 | 1.59k | bool NoMatchBreak = | 573 | 1.59k | !FoundMatchOnLine && !(1.59k LineIsComment1.59k && ACS.AcrossComments176 ); | 574 | | | 575 | 1.59k | if (EmptyLineBreak || NoMatchBreak1.55k ) | 576 | 1.59k | AlignCurrentSequence(); | 577 | | | 578 | | // A new line starts, re-initialize line status tracking bools. | 579 | | // Keep the match state if a string literal is continued on this line. | 580 | 1.59k | if (i == 0 || !Changes[i].Tok->is(tok::string_literal) || | 581 | 1.59k | !Changes[i - 1].Tok->is(tok::string_literal)38 ) { | 582 | 1.59k | FoundMatchOnLine = false; | 583 | 1.59k | } | 584 | 1.59k | LineIsComment = true; | 585 | 1.59k | } | 586 | | | 587 | 12.2k | if (!Changes[i].Tok->is(tok::comment)) | 588 | 12.0k | LineIsComment = false; | 589 | | | 590 | 12.2k | if (Changes[i].Tok->is(tok::comma)) { | 591 | 8 | ++CommasBeforeMatch; | 592 | 12.2k | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { | 593 | | // Call AlignTokens recursively, skipping over this scope block. | 594 | 1.75k | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); | 595 | 1.75k | i = StoppedAt - 1; | 596 | 1.75k | continue; | 597 | 1.75k | } | 598 | | | 599 | 10.5k | if (!Matches(Changes[i])) | 600 | 10.5k | continue; | 601 | | | 602 | | // If there is more than one matching token per line, or if the number of | 603 | | // preceding commas, do not match anymore, end the sequence. | 604 | 11 | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch) | 605 | 0 | AlignCurrentSequence(); | 606 | | | 607 | 11 | CommasBeforeLastMatch = CommasBeforeMatch; | 608 | 11 | FoundMatchOnLine = true; | 609 | | | 610 | 11 | if (StartOfSequence == 0) | 611 | 11 | StartOfSequence = i; | 612 | | | 613 | 11 | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; | 614 | 11 | unsigned ChangeWidthAnchor = 0; | 615 | 11 | unsigned ChangeWidthRight = 0; | 616 | 11 | if (RightJustify) | 617 | 0 | if (ACS.PadOperators) | 618 | 0 | ChangeWidthAnchor = Changes[i].TokenLength; | 619 | 0 | else | 620 | 0 | ChangeWidthLeft += Changes[i].TokenLength; | 621 | 11 | else | 622 | 11 | ChangeWidthRight = Changes[i].TokenLength; | 623 | 36 | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 028 ; ++j25 ) { | 624 | 25 | ChangeWidthRight += Changes[j].Spaces; | 625 | | // Changes are generally 1:1 with the tokens, but a change could also be | 626 | | // inside of a token, in which case it's counted more than once: once for | 627 | | // the whitespace surrounding the token (!IsInsideToken) and once for | 628 | | // each whitespace change within it (IsInsideToken). | 629 | | // Therefore, changes inside of a token should only count the space. | 630 | 25 | if (!Changes[j].IsInsideToken) | 631 | 25 | ChangeWidthRight += Changes[j].TokenLength; | 632 | 25 | } | 633 | | | 634 | | // If we are restricted by the maximum column width, end the sequence. | 635 | 11 | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); | 636 | 11 | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); | 637 | 11 | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); | 638 | | // `ColumnLimit == 0` means there is no column limit. | 639 | 11 | if (Style.ColumnLimit != 0 && | 640 | 11 | Style.ColumnLimit < NewLeft + NewAnchor + NewRight) { | 641 | 0 | AlignCurrentSequence(); | 642 | 0 | StartOfSequence = i; | 643 | 0 | WidthLeft = ChangeWidthLeft; | 644 | 0 | WidthAnchor = ChangeWidthAnchor; | 645 | 0 | WidthRight = ChangeWidthRight; | 646 | 11 | } else { | 647 | 11 | WidthLeft = NewLeft; | 648 | 11 | WidthAnchor = NewAnchor; | 649 | 11 | WidthRight = NewRight; | 650 | 11 | } | 651 | 11 | } | 652 | | | 653 | 1.60k | EndOfSequence = i; | 654 | 1.60k | AlignCurrentSequence(); | 655 | 1.60k | return i; | 656 | 1.60k | } |
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 | 498 | 3.05k | bool RightJustify = false) { | 499 | | // We arrange each line in 3 parts. The operator to be aligned (the anchor), | 500 | | // and text to its left and right. In the aligned text the width of each part | 501 | | // will be the maximum of that over the block that has been aligned. Maximum | 502 | | // widths of each part so far. When RightJustify is true and ACS.PadOperators | 503 | | // is false, the part from start of line to the right end of the anchor. | 504 | | // Otherwise, only the part to the left of the anchor. Including the space | 505 | | // that exists on its left from the start. Not including the padding added on | 506 | | // the left to right-justify the anchor. | 507 | 3.05k | unsigned WidthLeft = 0; | 508 | | // The operator to be aligned when RightJustify is true and ACS.PadOperators | 509 | | // is false. 0 otherwise. | 510 | 3.05k | unsigned WidthAnchor = 0; | 511 | | // Width to the right of the anchor. Plus width of the anchor when | 512 | | // RightJustify is false. | 513 | 3.05k | unsigned WidthRight = 0; | 514 | | | 515 | | // Line number of the start and the end of the current token sequence. | 516 | 3.05k | unsigned StartOfSequence = 0; | 517 | 3.05k | unsigned EndOfSequence = 0; | 518 | | | 519 | | // Measure the scope level (i.e. depth of (), [], {}) of the first token, and | 520 | | // abort when we hit any token in a higher scope than the starting one. | 521 | 3.05k | auto IndentAndNestingLevel = StartAt < Changes.size() | 522 | 3.05k | ? Changes[StartAt].indentAndNestingLevel() | 523 | 3.05k | : std::tuple<unsigned, unsigned, unsigned>()0 ; | 524 | | | 525 | | // Keep track of the number of commas before the matching tokens, we will only | 526 | | // align a sequence of matching tokens if they are preceded by the same number | 527 | | // of commas. | 528 | 3.05k | unsigned CommasBeforeLastMatch = 0; | 529 | 3.05k | unsigned CommasBeforeMatch = 0; | 530 | | | 531 | | // Whether a matching token has been found on the current line. | 532 | 3.05k | bool FoundMatchOnLine = false; | 533 | | | 534 | | // Whether the current line consists purely of comments. | 535 | 3.05k | bool LineIsComment = true; | 536 | | | 537 | | // Aligns a sequence of matching tokens, on the MinColumn column. | 538 | | // | 539 | | // Sequences start from the first matching token to align, and end at the | 540 | | // first token of the first line that doesn't need to be aligned. | 541 | | // | 542 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line | 543 | | // containing any matching token to be aligned and located after such token. | 544 | 3.05k | auto AlignCurrentSequence = [&] { | 545 | 3.05k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { | 546 | 3.05k | AlignTokenSequence(Style, StartOfSequence, EndOfSequence, | 547 | 3.05k | WidthLeft + WidthAnchor, RightJustify, Matches, | 548 | 3.05k | Changes); | 549 | 3.05k | } | 550 | 3.05k | WidthLeft = 0; | 551 | 3.05k | WidthAnchor = 0; | 552 | 3.05k | WidthRight = 0; | 553 | 3.05k | StartOfSequence = 0; | 554 | 3.05k | EndOfSequence = 0; | 555 | 3.05k | }; | 556 | | | 557 | 3.05k | unsigned i = StartAt; | 558 | 14.0k | for (unsigned e = Changes.size(); i != e; ++i10.9k ) { | 559 | 14.0k | if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) | 560 | 3.04k | break; | 561 | | | 562 | 10.9k | if (Changes[i].NewlinesBefore != 0) { | 563 | 2.11k | CommasBeforeMatch = 0; | 564 | 2.11k | EndOfSequence = i; | 565 | | | 566 | | // Whether to break the alignment sequence because of an empty line. | 567 | 2.11k | bool EmptyLineBreak = | 568 | 2.11k | (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines3 ; | 569 | | | 570 | | // Whether to break the alignment sequence because of a line without a | 571 | | // match. | 572 | 2.11k | bool NoMatchBreak = | 573 | 2.11k | !FoundMatchOnLine && !(1.90k LineIsComment1.90k && ACS.AcrossComments1.04k ); | 574 | | | 575 | 2.11k | if (EmptyLineBreak || NoMatchBreak2.11k ) | 576 | 1.90k | AlignCurrentSequence(); | 577 | | | 578 | | // A new line starts, re-initialize line status tracking bools. | 579 | | // Keep the match state if a string literal is continued on this line. | 580 | 2.11k | if (i == 0 || !Changes[i].Tok->is(tok::string_literal) || | 581 | 2.11k | !Changes[i - 1].Tok->is(tok::string_literal)28 ) { | 582 | 2.11k | FoundMatchOnLine = false; | 583 | 2.11k | } | 584 | 2.11k | LineIsComment = true; | 585 | 2.11k | } | 586 | | | 587 | 10.9k | if (!Changes[i].Tok->is(tok::comment)) | 588 | 10.8k | LineIsComment = false; | 589 | | | 590 | 10.9k | if (Changes[i].Tok->is(tok::comma)) { | 591 | 613 | ++CommasBeforeMatch; | 592 | 10.3k | } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { | 593 | | // Call AlignTokens recursively, skipping over this scope block. | 594 | 1.29k | unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS); | 595 | 1.29k | i = StoppedAt - 1; | 596 | 1.29k | continue; | 597 | 1.29k | } | 598 | | | 599 | 9.69k | if (!Matches(Changes[i])) | 600 | 9.29k | continue; | 601 | | | 602 | | // If there is more than one matching token per line, or if the number of | 603 | | // preceding commas, do not match anymore, end the sequence. | 604 | 396 | if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch) | 605 | 0 | AlignCurrentSequence(); | 606 | | | 607 | 396 | CommasBeforeLastMatch = CommasBeforeMatch; | 608 | 396 | FoundMatchOnLine = true; | 609 | | | 610 | 396 | if (StartOfSequence == 0) | 611 | 191 | StartOfSequence = i; | 612 | | | 613 | 396 | unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; | 614 | 396 | unsigned ChangeWidthAnchor = 0; | 615 | 396 | unsigned ChangeWidthRight = 0; | 616 | 396 | if (RightJustify) | 617 | 0 | if (ACS.PadOperators) | 618 | 0 | ChangeWidthAnchor = Changes[i].TokenLength; | 619 | 0 | else | 620 | 0 | ChangeWidthLeft += Changes[i].TokenLength; | 621 | 396 | else | 622 | 396 | ChangeWidthRight = Changes[i].TokenLength; | 623 | 1.50k | for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 01.39k ; ++j1.10k ) { | 624 | 1.10k | ChangeWidthRight += Changes[j].Spaces; | 625 | | // Changes are generally 1:1 with the tokens, but a change could also be | 626 | | // inside of a token, in which case it's counted more than once: once for | 627 | | // the whitespace surrounding the token (!IsInsideToken) and once for | 628 | | // each whitespace change within it (IsInsideToken). | 629 | | // Therefore, changes inside of a token should only count the space. | 630 | 1.10k | if (!Changes[j].IsInsideToken) | 631 | 1.10k | ChangeWidthRight += Changes[j].TokenLength; | 632 | 1.10k | } | 633 | | | 634 | | // If we are restricted by the maximum column width, end the sequence. | 635 | 396 | unsigned NewLeft = std::max(ChangeWidthLeft, WidthLeft); | 636 | 396 | unsigned NewAnchor = std::max(ChangeWidthAnchor, WidthAnchor); | 637 | 396 | unsigned NewRight = std::max(ChangeWidthRight, WidthRight); | 638 | | // `ColumnLimit == 0` means there is no column limit. | 639 | 396 | if (Style.ColumnLimit != 0 && | 640 | 396 | Style.ColumnLimit < NewLeft + NewAnchor + NewRight) { | 641 | 3 | AlignCurrentSequence(); | 642 | 3 | StartOfSequence = i; | 643 | 3 | WidthLeft = ChangeWidthLeft; | 644 | 3 | WidthAnchor = ChangeWidthAnchor; | 645 | 3 | WidthRight = ChangeWidthRight; | 646 | 393 | } else { | 647 | 393 | WidthLeft = NewLeft; | 648 | 393 | WidthAnchor = NewAnchor; | 649 | 393 | WidthRight = NewRight; | 650 | 393 | } | 651 | 396 | } | 652 | | | 653 | 3.05k | EndOfSequence = i; | 654 | 3.05k | AlignCurrentSequence(); | 655 | 3.05k | return i; | 656 | 3.05k | } |
|
657 | | |
658 | | // Aligns a sequence of matching tokens, on the MinColumn column. |
659 | | // |
660 | | // Sequences start from the first matching token to align, and end at the |
661 | | // first token of the first line that doesn't need to be aligned. |
662 | | // |
663 | | // We need to adjust the StartOfTokenColumn of each Change that is on a line |
664 | | // containing any matching token to be aligned and located after such token. |
665 | | static void AlignMacroSequence( |
666 | | unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn, |
667 | | unsigned &MaxColumn, bool &FoundMatchOnLine, |
668 | | std::function<bool(const WhitespaceManager::Change &C)> AlignMacrosMatches, |
669 | 1.83k | SmallVector<WhitespaceManager::Change, 16> &Changes) { |
670 | 1.83k | if (StartOfSequence > 0 && StartOfSequence < EndOfSequence33 ) { |
671 | | |
672 | 33 | FoundMatchOnLine = false; |
673 | 33 | int Shift = 0; |
674 | | |
675 | 657 | for (unsigned I = StartOfSequence; I != EndOfSequence; ++I624 ) { |
676 | 624 | if (Changes[I].NewlinesBefore > 0) { |
677 | 78 | Shift = 0; |
678 | 78 | FoundMatchOnLine = false; |
679 | 78 | } |
680 | | |
681 | | // If this is the first matching token to be aligned, remember by how many |
682 | | // spaces it has to be shifted, so the rest of the changes on the line are |
683 | | // shifted by the same amount |
684 | 624 | if (!FoundMatchOnLine && AlignMacrosMatches(Changes[I])417 ) { |
685 | 96 | FoundMatchOnLine = true; |
686 | 96 | Shift = MinColumn - Changes[I].StartOfTokenColumn; |
687 | 96 | Changes[I].Spaces += Shift; |
688 | 96 | } |
689 | | |
690 | 624 | assert(Shift >= 0); |
691 | 0 | Changes[I].StartOfTokenColumn += Shift; |
692 | 624 | if (I + 1 != Changes.size()) |
693 | 596 | Changes[I + 1].PreviousEndOfTokenColumn += Shift; |
694 | 624 | } |
695 | 33 | } |
696 | | |
697 | 1.83k | MinColumn = 0; |
698 | 1.83k | MaxColumn = UINT_MAX; |
699 | 1.83k | StartOfSequence = 0; |
700 | 1.83k | EndOfSequence = 0; |
701 | 1.83k | } |
702 | | |
703 | 22.5k | void WhitespaceManager::alignConsecutiveMacros() { |
704 | 22.5k | if (!Style.AlignConsecutiveMacros.Enabled) |
705 | 22.1k | return; |
706 | | |
707 | 10.6k | auto AlignMacrosMatches = [](const Change &C) 433 { |
708 | 10.6k | const FormatToken *Current = C.Tok; |
709 | 10.6k | unsigned SpacesRequiredBefore = 1; |
710 | | |
711 | 10.6k | if (Current->SpacesRequiredBefore == 0 || !Current->Previous7.35k ) |
712 | 5.47k | return false; |
713 | | |
714 | 5.21k | Current = Current->Previous; |
715 | | |
716 | | // If token is a ")", skip over the parameter list, to the |
717 | | // token that precedes the "(" |
718 | 5.21k | if (Current->is(tok::r_paren) && Current->MatchingParen225 ) { |
719 | 225 | Current = Current->MatchingParen->Previous; |
720 | 225 | SpacesRequiredBefore = 0; |
721 | 225 | } |
722 | | |
723 | 5.21k | if (!Current || !Current->is(tok::identifier)) |
724 | 3.46k | return false; |
725 | | |
726 | 1.74k | if (!Current->Previous || !Current->Previous->is(tok::pp_define)1.56k ) |
727 | 1.55k | return false; |
728 | | |
729 | | // For a macro function, 0 spaces are required between the |
730 | | // identifier and the lparen that opens the parameter list. |
731 | | // For a simple macro, 1 space is required between the |
732 | | // identifier and the first token of the defined value. |
733 | 192 | return Current->Next->SpacesRequiredBefore == SpacesRequiredBefore; |
734 | 1.74k | }; |
735 | | |
736 | 433 | unsigned MinColumn = 0; |
737 | 433 | unsigned MaxColumn = UINT_MAX; |
738 | | |
739 | | // Start and end of the token sequence we're processing. |
740 | 433 | unsigned StartOfSequence = 0; |
741 | 433 | unsigned EndOfSequence = 0; |
742 | | |
743 | | // Whether a matching token has been found on the current line. |
744 | 433 | bool FoundMatchOnLine = false; |
745 | | |
746 | | // Whether the current line consists only of comments |
747 | 433 | bool LineIsComment = true; |
748 | | |
749 | 433 | unsigned I = 0; |
750 | 10.7k | for (unsigned E = Changes.size(); I != E; ++I10.2k ) { |
751 | 10.2k | if (Changes[I].NewlinesBefore != 0) { |
752 | 1.48k | EndOfSequence = I; |
753 | | |
754 | | // Whether to break the alignment sequence because of an empty line. |
755 | 1.48k | bool EmptyLineBreak = (Changes[I].NewlinesBefore > 1) && |
756 | 1.48k | !Style.AlignConsecutiveMacros.AcrossEmptyLines40 ; |
757 | | |
758 | | // Whether to break the alignment sequence because of a line without a |
759 | | // match. |
760 | 1.48k | bool NoMatchBreak = |
761 | 1.48k | !FoundMatchOnLine && |
762 | 1.48k | !(1.41k LineIsComment1.41k && Style.AlignConsecutiveMacros.AcrossComments39 ); |
763 | | |
764 | 1.48k | if (EmptyLineBreak || NoMatchBreak1.44k ) { |
765 | 1.40k | AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn, |
766 | 1.40k | FoundMatchOnLine, AlignMacrosMatches, Changes); |
767 | 1.40k | } |
768 | | |
769 | | // A new line starts, re-initialize line status tracking bools. |
770 | 1.48k | FoundMatchOnLine = false; |
771 | 1.48k | LineIsComment = true; |
772 | 1.48k | } |
773 | | |
774 | 10.2k | if (!Changes[I].Tok->is(tok::comment)) |
775 | 10.1k | LineIsComment = false; |
776 | | |
777 | 10.2k | if (!AlignMacrosMatches(Changes[I])) |
778 | 10.1k | continue; |
779 | | |
780 | 96 | FoundMatchOnLine = true; |
781 | | |
782 | 96 | if (StartOfSequence == 0) |
783 | 33 | StartOfSequence = I; |
784 | | |
785 | 96 | unsigned ChangeMinColumn = Changes[I].StartOfTokenColumn; |
786 | 96 | int LineLengthAfter = -Changes[I].Spaces; |
787 | 399 | for (unsigned j = I; j != E && Changes[j].NewlinesBefore == 0371 ; ++j303 ) |
788 | 303 | LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength; |
789 | 96 | unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter; |
790 | | |
791 | 96 | MinColumn = std::max(MinColumn, ChangeMinColumn); |
792 | 96 | MaxColumn = std::min(MaxColumn, ChangeMaxColumn); |
793 | 96 | } |
794 | | |
795 | 433 | EndOfSequence = I; |
796 | 433 | AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn, |
797 | 433 | FoundMatchOnLine, AlignMacrosMatches, Changes); |
798 | 433 | } |
799 | | |
800 | 22.5k | void WhitespaceManager::alignConsecutiveAssignments() { |
801 | 22.5k | if (!Style.AlignConsecutiveAssignments.Enabled) |
802 | 21.9k | return; |
803 | | |
804 | 594 | AlignTokens( |
805 | 594 | Style, |
806 | 17.5k | [&](const Change &C) { |
807 | | // Do not align on equal signs that are first on a line. |
808 | 17.5k | if (C.NewlinesBefore > 0) |
809 | 2.71k | return false; |
810 | | |
811 | | // Do not align on equal signs that are last on a line. |
812 | 14.7k | if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 014.3k ) |
813 | 1.92k | return false; |
814 | | |
815 | | // Do not align operator= overloads. |
816 | 12.8k | FormatToken *Previous = C.Tok->getPreviousNonComment(); |
817 | 12.8k | if (Previous && Previous->is(tok::kw_operator)11.8k ) |
818 | 126 | return false; |
819 | | |
820 | 12.7k | return Style.AlignConsecutiveAssignments.AlignCompound |
821 | 12.7k | ? C.Tok->getPrecedence() == prec::Assignment371 |
822 | 12.7k | : C.Tok->is(tok::equal)12.3k ; |
823 | 12.8k | }, |
824 | 594 | Changes, /*StartAt=*/0, Style.AlignConsecutiveAssignments, |
825 | 594 | /*RightJustify=*/true); |
826 | 594 | } |
827 | | |
828 | 22.5k | void WhitespaceManager::alignConsecutiveBitFields() { |
829 | 22.5k | if (!Style.AlignConsecutiveBitFields.Enabled) |
830 | 22.5k | return; |
831 | | |
832 | 36 | AlignTokens( |
833 | 36 | Style, |
834 | 662 | [&](Change const &C) { |
835 | | // Do not align on ':' that is first on a line. |
836 | 662 | if (C.NewlinesBefore > 0) |
837 | 86 | return false; |
838 | | |
839 | | // Do not align on ':' that is last on a line. |
840 | 576 | if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0540 ) |
841 | 39 | return false; |
842 | | |
843 | 537 | return C.Tok->is(TT_BitFieldColon); |
844 | 576 | }, |
845 | 36 | Changes, /*StartAt=*/0, Style.AlignConsecutiveBitFields); |
846 | 36 | } |
847 | | |
848 | 22.5k | void WhitespaceManager::alignConsecutiveDeclarations() { |
849 | 22.5k | if (!Style.AlignConsecutiveDeclarations.Enabled) |
850 | 21.8k | return; |
851 | | |
852 | 676 | AlignTokens( |
853 | 676 | Style, |
854 | 18.7k | [](Change const &C) { |
855 | | // tok::kw_operator is necessary for aligning operator overload |
856 | | // definitions. |
857 | 18.7k | if (C.Tok->isOneOf(TT_FunctionDeclarationName, tok::kw_operator)) |
858 | 346 | return true; |
859 | 18.3k | if (C.Tok->isNot(TT_StartOfName)) |
860 | 15.7k | return false; |
861 | 2.65k | if (C.Tok->Previous && |
862 | 2.65k | C.Tok->Previous->is(TT_StatementAttributeLikeMacro)) |
863 | 5 | return false; |
864 | | // Check if there is a subsequent name that starts the same declaration. |
865 | 2.64k | for (FormatToken *Next = C.Tok->Next; 2.64k Next; Next = Next->Next2 ) { |
866 | 2.64k | if (Next->is(tok::comment)) |
867 | 2 | continue; |
868 | 2.64k | if (Next->is(TT_PointerOrReference)) |
869 | 36 | return false; |
870 | 2.61k | if (!Next->Tok.getIdentifierInfo()) |
871 | 2.60k | break; |
872 | 2 | if (Next->isOneOf(TT_StartOfName, TT_FunctionDeclarationName, |
873 | 2 | tok::kw_operator)) { |
874 | 2 | return false; |
875 | 2 | } |
876 | 2 | } |
877 | 2.60k | return true; |
878 | 2.64k | }, |
879 | 676 | Changes, /*StartAt=*/0, Style.AlignConsecutiveDeclarations); |
880 | 676 | } |
881 | | |
882 | 22.5k | void WhitespaceManager::alignChainedConditionals() { |
883 | 22.5k | if (Style.BreakBeforeTernaryOperators) { |
884 | 20.9k | AlignTokens( |
885 | 20.9k | Style, |
886 | 357k | [](Change const &C) { |
887 | | // Align question operators and last colon |
888 | 357k | return C.Tok->is(TT_ConditionalExpr) && |
889 | 357k | (1.69k (1.69k C.Tok->is(tok::question)1.69k && !C.NewlinesBefore751 ) || |
890 | 1.69k | (1.02k C.Tok->is(tok::colon)1.02k && C.Tok->Next944 && |
891 | 1.02k | (944 C.Tok->Next->FakeLParens.size() == 0944 || |
892 | 944 | C.Tok->Next->FakeLParens.back() != prec::Conditional254 ))); |
893 | 357k | }, |
894 | 20.9k | Changes, /*StartAt=*/0); |
895 | 20.9k | } else { |
896 | 40.4k | static auto AlignWrappedOperand = [](Change const &C) { |
897 | 40.4k | FormatToken *Previous = C.Tok->getPreviousNonComment(); |
898 | 40.4k | return C.NewlinesBefore && Previous5.68k && Previous->is(TT_ConditionalExpr)2.96k && |
899 | 40.4k | (895 Previous->is(tok::colon)895 && |
900 | 895 | (777 C.Tok->FakeLParens.size() == 0777 || |
901 | 777 | C.Tok->FakeLParens.back() != prec::Conditional279 )); |
902 | 40.4k | }; |
903 | | // Ensure we keep alignment of wrapped operands with non-wrapped operands |
904 | | // Since we actually align the operators, the wrapped operands need the |
905 | | // extra offset to be properly aligned. |
906 | 1.60k | for (Change &C : Changes) |
907 | 20.2k | if (AlignWrappedOperand(C)) |
908 | 175 | C.StartOfTokenColumn -= 2; |
909 | 1.60k | AlignTokens( |
910 | 1.60k | Style, |
911 | 20.7k | [this](Change const &C) { |
912 | | // Align question operators if next operand is not wrapped, as |
913 | | // well as wrapped operands after question operator or last |
914 | | // colon in conditional sequence |
915 | 20.7k | return (C.Tok->is(TT_ConditionalExpr) && C.Tok->is(tok::question)810 && |
916 | 20.7k | &C != &Changes.back()521 && (&C + 1)->NewlinesBefore == 0521 && |
917 | 20.7k | !(&C + 1)->IsTrailingComment476 ) || |
918 | 20.7k | AlignWrappedOperand(C)20.2k ; |
919 | 20.7k | }, |
920 | 1.60k | Changes, /*StartAt=*/0); |
921 | 1.60k | } |
922 | 22.5k | } |
923 | | |
924 | 22.5k | void WhitespaceManager::alignTrailingComments() { |
925 | 22.5k | unsigned MinColumn = 0; |
926 | 22.5k | unsigned MaxColumn = UINT_MAX; |
927 | 22.5k | unsigned StartOfSequence = 0; |
928 | 22.5k | bool BreakBeforeNext = false; |
929 | 22.5k | unsigned Newlines = 0; |
930 | 399k | for (unsigned i = 0, e = Changes.size(); i != e; ++i376k ) { |
931 | 376k | if (Changes[i].StartOfBlockComment) |
932 | 714 | continue; |
933 | 376k | Newlines += Changes[i].NewlinesBefore; |
934 | 376k | if (!Changes[i].IsTrailingComment) |
935 | 371k | continue; |
936 | | |
937 | 5.14k | unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn; |
938 | 5.14k | unsigned ChangeMaxColumn; |
939 | | |
940 | 5.14k | if (Style.ColumnLimit == 0) |
941 | 243 | ChangeMaxColumn = UINT_MAX; |
942 | 4.89k | else if (Style.ColumnLimit >= Changes[i].TokenLength) |
943 | 4.83k | ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength; |
944 | 60 | else |
945 | 60 | ChangeMaxColumn = ChangeMinColumn; |
946 | | |
947 | | // If we don't create a replacement for this change, we have to consider |
948 | | // it to be immovable. |
949 | 5.14k | if (!Changes[i].CreateReplacement) |
950 | 470 | ChangeMaxColumn = ChangeMinColumn; |
951 | | |
952 | 5.14k | if (i + 1 != e && Changes[i + 1].ContinuesPPDirective5.12k ) |
953 | 68 | ChangeMaxColumn -= 2; |
954 | | // If this comment follows an } in column 0, it probably documents the |
955 | | // closing of a namespace and we don't want to align it. |
956 | 5.14k | bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 04.61k && |
957 | 5.14k | Changes[i - 1].Tok->is(tok::r_brace)2.37k && |
958 | 5.14k | Changes[i - 1].StartOfTokenColumn == 01.04k ; |
959 | 5.14k | bool WasAlignedWithStartOfNextLine = false; |
960 | 5.14k | if (Changes[i].NewlinesBefore == 1) { // A comment on its own line. |
961 | 1.97k | unsigned CommentColumn = SourceMgr.getSpellingColumnNumber( |
962 | 1.97k | Changes[i].OriginalWhitespaceRange.getEnd()); |
963 | 9.90k | for (unsigned j = i + 1; j != e; ++j7.93k ) { |
964 | 9.89k | if (Changes[j].Tok->is(tok::comment)) |
965 | 7.93k | continue; |
966 | | |
967 | 1.96k | unsigned NextColumn = SourceMgr.getSpellingColumnNumber( |
968 | 1.96k | Changes[j].OriginalWhitespaceRange.getEnd()); |
969 | | // The start of the next token was previously aligned with the |
970 | | // start of this comment. |
971 | 1.96k | WasAlignedWithStartOfNextLine = |
972 | 1.96k | CommentColumn == NextColumn || |
973 | 1.96k | CommentColumn == NextColumn + Style.IndentWidth833 ; |
974 | 1.96k | break; |
975 | 9.89k | } |
976 | 1.97k | } |
977 | 5.14k | if (!Style.AlignTrailingComments || FollowsRBraceInColumn05.04k ) { |
978 | 586 | alignTrailingComments(StartOfSequence, i, MinColumn); |
979 | 586 | MinColumn = ChangeMinColumn; |
980 | 586 | MaxColumn = ChangeMinColumn; |
981 | 586 | StartOfSequence = i; |
982 | 4.55k | } else if (BreakBeforeNext || Newlines > 13.17k || |
983 | 4.55k | (2.21k ChangeMinColumn > MaxColumn2.21k || ChangeMaxColumn < MinColumn2.20k ) || |
984 | | // Break the comment sequence if the previous line did not end |
985 | | // in a trailing comment. |
986 | 4.55k | (2.19k Changes[i].NewlinesBefore == 12.19k && i > 0552 && |
987 | 2.19k | !Changes[i - 1].IsTrailingComment523 ) || |
988 | 4.55k | WasAlignedWithStartOfNextLine1.79k ) { |
989 | 2.83k | alignTrailingComments(StartOfSequence, i, MinColumn); |
990 | 2.83k | MinColumn = ChangeMinColumn; |
991 | 2.83k | MaxColumn = ChangeMaxColumn; |
992 | 2.83k | StartOfSequence = i; |
993 | 2.83k | } else { |
994 | 1.72k | MinColumn = std::max(MinColumn, ChangeMinColumn); |
995 | 1.72k | MaxColumn = std::min(MaxColumn, ChangeMaxColumn); |
996 | 1.72k | } |
997 | 5.14k | BreakBeforeNext = (i == 0) || (Changes[i].NewlinesBefore > 1)4.61k || |
998 | | // Never start a sequence with a comment at the beginning |
999 | | // of the line. |
1000 | 5.14k | (4.31k Changes[i].NewlinesBefore == 14.31k && StartOfSequence == i1.94k ); |
1001 | 5.14k | Newlines = 0; |
1002 | 5.14k | } |
1003 | 22.5k | alignTrailingComments(StartOfSequence, Changes.size(), MinColumn); |
1004 | 22.5k | } |
1005 | | |
1006 | | void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End, |
1007 | 25.9k | unsigned Column) { |
1008 | 402k | for (unsigned i = Start; i != End; ++i376k ) { |
1009 | 376k | int Shift = 0; |
1010 | 376k | if (Changes[i].IsTrailingComment) |
1011 | 5.79k | Shift = Column - Changes[i].StartOfTokenColumn; |
1012 | 376k | if (Changes[i].StartOfBlockComment) { |
1013 | 714 | Shift = Changes[i].IndentationOffset + |
1014 | 714 | Changes[i].StartOfBlockComment->StartOfTokenColumn - |
1015 | 714 | Changes[i].StartOfTokenColumn; |
1016 | 714 | } |
1017 | 376k | if (Shift < 0) |
1018 | 0 | continue; |
1019 | 376k | Changes[i].Spaces += Shift; |
1020 | 376k | if (i + 1 != Changes.size()) |
1021 | 354k | Changes[i + 1].PreviousEndOfTokenColumn += Shift; |
1022 | 376k | Changes[i].StartOfTokenColumn += Shift; |
1023 | 376k | } |
1024 | 25.9k | } |
1025 | | |
1026 | 22.5k | void WhitespaceManager::alignEscapedNewlines() { |
1027 | 22.5k | if (Style.AlignEscapedNewlines == FormatStyle::ENAS_DontAlign) |
1028 | 10 | return; |
1029 | | |
1030 | 22.5k | bool AlignLeft = Style.AlignEscapedNewlines == FormatStyle::ENAS_Left; |
1031 | 22.5k | unsigned MaxEndOfLine = AlignLeft ? 04.16k : Style.ColumnLimit18.3k ; |
1032 | 22.5k | unsigned StartOfMacro = 0; |
1033 | 376k | for (unsigned i = 1, e = Changes.size(); i < e; ++i354k ) { |
1034 | 354k | Change &C = Changes[i]; |
1035 | 354k | if (C.NewlinesBefore > 0) { |
1036 | 50.2k | if (C.ContinuesPPDirective) { |
1037 | 670 | MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine); |
1038 | 49.5k | } else { |
1039 | 49.5k | alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine); |
1040 | 49.5k | MaxEndOfLine = AlignLeft ? 09.06k : Style.ColumnLimit40.4k ; |
1041 | 49.5k | StartOfMacro = i; |
1042 | 49.5k | } |
1043 | 50.2k | } |
1044 | 354k | } |
1045 | 22.5k | alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine); |
1046 | 22.5k | } |
1047 | | |
1048 | | void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End, |
1049 | 72.0k | unsigned Column) { |
1050 | 376k | for (unsigned i = Start; i < End; ++i304k ) { |
1051 | 304k | Change &C = Changes[i]; |
1052 | 304k | if (C.NewlinesBefore > 0) { |
1053 | 670 | assert(C.ContinuesPPDirective); |
1054 | 670 | if (C.PreviousEndOfTokenColumn + 1 > Column) |
1055 | 0 | C.EscapedNewlineColumn = 0; |
1056 | 670 | else |
1057 | 670 | C.EscapedNewlineColumn = Column; |
1058 | 670 | } |
1059 | 304k | } |
1060 | 72.0k | } |
1061 | | |
1062 | 22.5k | void WhitespaceManager::alignArrayInitializers() { |
1063 | 22.5k | if (Style.AlignArrayOfStructures == FormatStyle::AIAS_None) |
1064 | 22.3k | return; |
1065 | | |
1066 | 151 | for (unsigned ChangeIndex = 1U, ChangeEnd = Changes.size(); |
1067 | 1.21k | ChangeIndex < ChangeEnd; ++ChangeIndex1.06k ) { |
1068 | 1.06k | auto &C = Changes[ChangeIndex]; |
1069 | 1.06k | if (C.Tok->IsArrayInitializer) { |
1070 | 157 | bool FoundComplete = false; |
1071 | 4.10k | for (unsigned InsideIndex = ChangeIndex + 1; InsideIndex < ChangeEnd; |
1072 | 4.10k | ++InsideIndex3.94k ) { |
1073 | 4.10k | if (Changes[InsideIndex].Tok == C.Tok->MatchingParen) { |
1074 | 157 | alignArrayInitializers(ChangeIndex, InsideIndex + 1); |
1075 | 157 | ChangeIndex = InsideIndex + 1; |
1076 | 157 | FoundComplete = true; |
1077 | 157 | break; |
1078 | 157 | } |
1079 | 4.10k | } |
1080 | 157 | if (!FoundComplete) |
1081 | 0 | ChangeIndex = ChangeEnd; |
1082 | 157 | } |
1083 | 1.06k | } |
1084 | 151 | } |
1085 | | |
1086 | 157 | void WhitespaceManager::alignArrayInitializers(unsigned Start, unsigned End) { |
1087 | | |
1088 | 157 | if (Style.AlignArrayOfStructures == FormatStyle::AIAS_Right) |
1089 | 85 | alignArrayInitializersRightJustified(getCells(Start, End)); |
1090 | 72 | else if (Style.AlignArrayOfStructures == FormatStyle::AIAS_Left) |
1091 | 72 | alignArrayInitializersLeftJustified(getCells(Start, End)); |
1092 | 157 | } |
1093 | | |
1094 | | void WhitespaceManager::alignArrayInitializersRightJustified( |
1095 | 85 | CellDescriptions &&CellDescs) { |
1096 | 85 | if (!CellDescs.isRectangular()) |
1097 | 18 | return; |
1098 | | |
1099 | 67 | auto &Cells = CellDescs.Cells; |
1100 | | // Now go through and fixup the spaces. |
1101 | 67 | auto *CellIter = Cells.begin(); |
1102 | 329 | for (auto i = 0U; i < CellDescs.CellCounts[0]; ++i, ++CellIter262 ) { |
1103 | 262 | unsigned NetWidth = 0U; |
1104 | 262 | if (isSplitCell(*CellIter)) |
1105 | 19 | NetWidth = getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces); |
1106 | 262 | auto CellWidth = getMaximumCellWidth(CellIter, NetWidth); |
1107 | | |
1108 | 262 | if (Changes[CellIter->Index].Tok->is(tok::r_brace)) { |
1109 | | // So in here we want to see if there is a brace that falls |
1110 | | // on a line that was split. If so on that line we make sure that |
1111 | | // the spaces in front of the brace are enough. |
1112 | 64 | const auto *Next = CellIter; |
1113 | 177 | do { |
1114 | 177 | const FormatToken *Previous = Changes[Next->Index].Tok->Previous; |
1115 | 177 | if (Previous && Previous->isNot(TT_LineComment)) { |
1116 | 174 | Changes[Next->Index].Spaces = 0; |
1117 | 174 | Changes[Next->Index].NewlinesBefore = 0; |
1118 | 174 | } |
1119 | 177 | Next = Next->NextColumnElement; |
1120 | 177 | } while (Next); |
1121 | | // Unless the array is empty, we need the position of all the |
1122 | | // immediately adjacent cells |
1123 | 64 | if (CellIter != Cells.begin()) { |
1124 | 64 | auto ThisNetWidth = |
1125 | 64 | getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces); |
1126 | 64 | auto MaxNetWidth = getMaximumNetWidth( |
1127 | 64 | Cells.begin(), CellIter, CellDescs.InitialSpaces, |
1128 | 64 | CellDescs.CellCounts[0], CellDescs.CellCounts.size()); |
1129 | 64 | if (ThisNetWidth < MaxNetWidth) |
1130 | 1 | Changes[CellIter->Index].Spaces = (MaxNetWidth - ThisNetWidth); |
1131 | 64 | auto RowCount = 1U; |
1132 | 64 | auto Offset = std::distance(Cells.begin(), CellIter); |
1133 | 177 | for (const auto *Next = CellIter->NextColumnElement; Next != nullptr; |
1134 | 113 | Next = Next->NextColumnElement) { |
1135 | 113 | auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]); |
1136 | 113 | auto *End = Start + Offset; |
1137 | 113 | ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces); |
1138 | 113 | if (ThisNetWidth < MaxNetWidth) |
1139 | 1 | Changes[Next->Index].Spaces = (MaxNetWidth - ThisNetWidth); |
1140 | 113 | ++RowCount; |
1141 | 113 | } |
1142 | 64 | } |
1143 | 198 | } else { |
1144 | 198 | auto ThisWidth = |
1145 | 198 | calculateCellWidth(CellIter->Index, CellIter->EndIndex, true) + |
1146 | 198 | NetWidth; |
1147 | 198 | if (Changes[CellIter->Index].NewlinesBefore == 0) { |
1148 | 179 | Changes[CellIter->Index].Spaces = (CellWidth - (ThisWidth + NetWidth)); |
1149 | 179 | Changes[CellIter->Index].Spaces += (i > 0) ? 1119 : 060 ; |
1150 | 179 | } |
1151 | 198 | alignToStartOfCell(CellIter->Index, CellIter->EndIndex); |
1152 | 558 | for (const auto *Next = CellIter->NextColumnElement; Next != nullptr; |
1153 | 360 | Next = Next->NextColumnElement) { |
1154 | 360 | ThisWidth = |
1155 | 360 | calculateCellWidth(Next->Index, Next->EndIndex, true) + NetWidth; |
1156 | 360 | if (Changes[Next->Index].NewlinesBefore == 0) { |
1157 | 358 | Changes[Next->Index].Spaces = (CellWidth - ThisWidth); |
1158 | 358 | Changes[Next->Index].Spaces += (i > 0) ? 1245 : 0113 ; |
1159 | 358 | } |
1160 | 360 | alignToStartOfCell(Next->Index, Next->EndIndex); |
1161 | 360 | } |
1162 | 198 | } |
1163 | 262 | } |
1164 | 67 | } |
1165 | | |
1166 | | void WhitespaceManager::alignArrayInitializersLeftJustified( |
1167 | 72 | CellDescriptions &&CellDescs) { |
1168 | | |
1169 | 72 | if (!CellDescs.isRectangular()) |
1170 | 18 | return; |
1171 | | |
1172 | 54 | auto &Cells = CellDescs.Cells; |
1173 | | // Now go through and fixup the spaces. |
1174 | 54 | auto *CellIter = Cells.begin(); |
1175 | | // The first cell needs to be against the left brace. |
1176 | 54 | if (Changes[CellIter->Index].NewlinesBefore == 0) |
1177 | 47 | Changes[CellIter->Index].Spaces = 0; |
1178 | 7 | else |
1179 | 7 | Changes[CellIter->Index].Spaces = CellDescs.InitialSpaces; |
1180 | 54 | ++CellIter; |
1181 | 207 | for (auto i = 1U; i < CellDescs.CellCounts[0]; i++, ++CellIter153 ) { |
1182 | 153 | auto MaxNetWidth = getMaximumNetWidth( |
1183 | 153 | Cells.begin(), CellIter, CellDescs.InitialSpaces, |
1184 | 153 | CellDescs.CellCounts[0], CellDescs.CellCounts.size()); |
1185 | 153 | auto ThisNetWidth = |
1186 | 153 | getNetWidth(Cells.begin(), CellIter, CellDescs.InitialSpaces); |
1187 | 153 | if (Changes[CellIter->Index].NewlinesBefore == 0) { |
1188 | 145 | Changes[CellIter->Index].Spaces = |
1189 | 145 | MaxNetWidth - ThisNetWidth + |
1190 | 145 | (Changes[CellIter->Index].Tok->isNot(tok::r_brace) ? 197 : 048 ); |
1191 | 145 | } |
1192 | 153 | auto RowCount = 1U; |
1193 | 153 | auto Offset = std::distance(Cells.begin(), CellIter); |
1194 | 435 | for (const auto *Next = CellIter->NextColumnElement; Next != nullptr; |
1195 | 282 | Next = Next->NextColumnElement) { |
1196 | 282 | if (RowCount > CellDescs.CellCounts.size()) |
1197 | 0 | break; |
1198 | 282 | auto *Start = (Cells.begin() + RowCount * CellDescs.CellCounts[0]); |
1199 | 282 | auto *End = Start + Offset; |
1200 | 282 | auto ThisNetWidth = getNetWidth(Start, End, CellDescs.InitialSpaces); |
1201 | 282 | if (Changes[Next->Index].NewlinesBefore == 0) { |
1202 | 280 | Changes[Next->Index].Spaces = |
1203 | 280 | MaxNetWidth - ThisNetWidth + |
1204 | 280 | (Changes[Next->Index].Tok->isNot(tok::r_brace) ? 1190 : 090 ); |
1205 | 280 | } |
1206 | 282 | ++RowCount; |
1207 | 282 | } |
1208 | 153 | } |
1209 | 54 | } |
1210 | | |
1211 | 262 | bool WhitespaceManager::isSplitCell(const CellDescription &Cell) { |
1212 | 262 | if (Cell.HasSplit) |
1213 | 19 | return true; |
1214 | 702 | for (const auto *Next = Cell.NextColumnElement; 243 Next != nullptr; |
1215 | 459 | Next = Next->NextColumnElement) { |
1216 | 459 | if (Next->HasSplit) |
1217 | 0 | return true; |
1218 | 459 | } |
1219 | 243 | return false; |
1220 | 243 | } |
1221 | | |
1222 | | WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start, |
1223 | 157 | unsigned End) { |
1224 | | |
1225 | 157 | unsigned Depth = 0; |
1226 | 157 | unsigned Cell = 0; |
1227 | 157 | SmallVector<unsigned> CellCounts; |
1228 | 157 | unsigned InitialSpaces = 0; |
1229 | 157 | unsigned InitialTokenLength = 0; |
1230 | 157 | unsigned EndSpaces = 0; |
1231 | 157 | SmallVector<CellDescription> Cells; |
1232 | 157 | const FormatToken *MatchingParen = nullptr; |
1233 | 4.39k | for (unsigned i = Start; i < End; ++i4.23k ) { |
1234 | 4.23k | auto &C = Changes[i]; |
1235 | 4.23k | if (C.Tok->is(tok::l_brace)) |
1236 | 667 | ++Depth; |
1237 | 3.56k | else if (C.Tok->is(tok::r_brace)) |
1238 | 667 | --Depth; |
1239 | 4.23k | if (Depth == 2) { |
1240 | 2.76k | if (C.Tok->is(tok::l_brace)) { |
1241 | 432 | Cell = 0; |
1242 | 432 | MatchingParen = C.Tok->MatchingParen; |
1243 | 432 | if (InitialSpaces == 0) { |
1244 | 157 | InitialSpaces = C.Spaces + C.TokenLength; |
1245 | 157 | InitialTokenLength = C.TokenLength; |
1246 | 157 | auto j = i - 1; |
1247 | 157 | for (; Changes[j].NewlinesBefore == 0 && j > Start146 ; --j0 ) { |
1248 | 0 | InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength; |
1249 | 0 | InitialTokenLength += Changes[j].TokenLength; |
1250 | 0 | } |
1251 | 157 | if (C.NewlinesBefore == 0) { |
1252 | 11 | InitialSpaces += Changes[j].Spaces + Changes[j].TokenLength; |
1253 | 11 | InitialTokenLength += Changes[j].TokenLength; |
1254 | 11 | } |
1255 | 157 | } |
1256 | 2.33k | } else if (C.Tok->is(tok::comma)) { |
1257 | 894 | if (!Cells.empty()) |
1258 | 894 | Cells.back().EndIndex = i; |
1259 | 894 | if (C.Tok->getNextNonComment()->isNot(tok::r_brace)) // dangling comma |
1260 | 885 | ++Cell; |
1261 | 894 | } |
1262 | 2.76k | } else if (1.46k Depth == 11.46k ) { |
1263 | 1.00k | if (C.Tok == MatchingParen) { |
1264 | 432 | if (!Cells.empty()) |
1265 | 420 | Cells.back().EndIndex = i; |
1266 | 432 | Cells.push_back(CellDescription{i, ++Cell, i + 1, false, nullptr}); |
1267 | 432 | CellCounts.push_back(C.Tok->Previous->isNot(tok::comma) ? Cell + 1429 |
1268 | 432 | : Cell3 ); |
1269 | | // Go to the next non-comment and ensure there is a break in front |
1270 | 432 | const auto *NextNonComment = C.Tok->getNextNonComment(); |
1271 | 735 | while (NextNonComment->is(tok::comma)) |
1272 | 303 | NextNonComment = NextNonComment->getNextNonComment(); |
1273 | 432 | auto j = i; |
1274 | 1.25k | while (Changes[j].Tok != NextNonComment && j < End819 ) |
1275 | 819 | ++j; |
1276 | 432 | if (j < End && Changes[j].NewlinesBefore == 0 && |
1277 | 432 | Changes[j].Tok->isNot(tok::r_brace)243 ) { |
1278 | 138 | Changes[j].NewlinesBefore = 1; |
1279 | | // Account for the added token lengths |
1280 | 138 | Changes[j].Spaces = InitialSpaces - InitialTokenLength; |
1281 | 138 | } |
1282 | 571 | } else if (C.Tok->is(tok::comment)) { |
1283 | | // Trailing comments stay at a space past the last token |
1284 | 54 | C.Spaces = Changes[i - 1].Tok->is(tok::comma) ? 130 : 224 ; |
1285 | 517 | } else if (C.Tok->is(tok::l_brace)) { |
1286 | | // We need to make sure that the ending braces is aligned to the |
1287 | | // start of our initializer |
1288 | 157 | auto j = i - 1; |
1289 | 863 | for (; j > 0 && !Changes[j].Tok->ArrayInitializerLineStart718 ; --j706 ) |
1290 | 706 | ; // Nothing the loop does the work |
1291 | 157 | EndSpaces = Changes[j].Spaces; |
1292 | 157 | } |
1293 | 1.00k | } else if (463 Depth == 0463 && C.Tok->is(tok::r_brace)157 ) { |
1294 | 157 | C.NewlinesBefore = 1; |
1295 | 157 | C.Spaces = EndSpaces; |
1296 | 157 | } |
1297 | 4.23k | if (C.Tok->StartsColumn) { |
1298 | | // This gets us past tokens that have been split over multiple |
1299 | | // lines |
1300 | 1.32k | bool HasSplit = false; |
1301 | 1.32k | if (Changes[i].NewlinesBefore > 0) { |
1302 | | // So if we split a line previously and the tail line + this token is |
1303 | | // less then the column limit we remove the split here and just put |
1304 | | // the column start at a space past the comma |
1305 | | // |
1306 | | // FIXME This if branch covers the cases where the column is not |
1307 | | // the first column. This leads to weird pathologies like the formatting |
1308 | | // auto foo = Items{ |
1309 | | // Section{ |
1310 | | // 0, bar(), |
1311 | | // } |
1312 | | // }; |
1313 | | // Well if it doesn't lead to that it's indicative that the line |
1314 | | // breaking should be revisited. Unfortunately alot of other options |
1315 | | // interact with this |
1316 | 45 | auto j = i - 1; |
1317 | 45 | if ((j - 1) > Start && Changes[j].Tok->is(tok::comma)36 && |
1318 | 45 | Changes[j - 1].NewlinesBefore > 031 ) { |
1319 | 4 | --j; |
1320 | 4 | auto LineLimit = Changes[j].Spaces + Changes[j].TokenLength; |
1321 | 4 | if (LineLimit < Style.ColumnLimit) { |
1322 | 4 | Changes[i].NewlinesBefore = 0; |
1323 | 4 | Changes[i].Spaces = 1; |
1324 | 4 | } |
1325 | 4 | } |
1326 | 45 | } |
1327 | 1.39k | while (Changes[i].NewlinesBefore > 0 && Changes[i].Tok == C.Tok76 ) { |
1328 | 70 | Changes[i].Spaces = InitialSpaces; |
1329 | 70 | ++i; |
1330 | 70 | HasSplit = true; |
1331 | 70 | } |
1332 | 1.32k | if (Changes[i].Tok != C.Tok) |
1333 | 41 | --i; |
1334 | 1.32k | Cells.push_back(CellDescription{i, Cell, i, HasSplit, nullptr}); |
1335 | 1.32k | } |
1336 | 4.23k | } |
1337 | | |
1338 | 157 | return linkCells({Cells, CellCounts, InitialSpaces}); |
1339 | 157 | } |
1340 | | |
1341 | | unsigned WhitespaceManager::calculateCellWidth(unsigned Start, unsigned End, |
1342 | 4.16k | bool WithSpaces) const { |
1343 | 4.16k | unsigned CellWidth = 0; |
1344 | 10.1k | for (auto i = Start; i < End; i++6.00k ) { |
1345 | 6.00k | if (Changes[i].NewlinesBefore > 0) |
1346 | 162 | CellWidth = 0; |
1347 | 6.00k | CellWidth += Changes[i].TokenLength; |
1348 | 6.00k | CellWidth += (WithSpaces ? Changes[i].Spaces : 00 ); |
1349 | 6.00k | } |
1350 | 4.16k | return CellWidth; |
1351 | 4.16k | } |
1352 | | |
1353 | 558 | void WhitespaceManager::alignToStartOfCell(unsigned Start, unsigned End) { |
1354 | 558 | if ((End - Start) <= 1) |
1355 | 452 | return; |
1356 | | // If the line is broken anywhere in there make sure everything |
1357 | | // is aligned to the parent |
1358 | 371 | for (auto i = Start + 1; 106 i < End; i++265 ) |
1359 | 265 | if (Changes[i].NewlinesBefore > 0) |
1360 | 6 | Changes[i].Spaces = Changes[Start].Spaces; |
1361 | 106 | } |
1362 | | |
1363 | | WhitespaceManager::CellDescriptions |
1364 | 157 | WhitespaceManager::linkCells(CellDescriptions &&CellDesc) { |
1365 | 157 | auto &Cells = CellDesc.Cells; |
1366 | 1.91k | for (auto *CellIter = Cells.begin(); CellIter != Cells.end(); ++CellIter1.75k ) { |
1367 | 1.75k | if (CellIter->NextColumnElement == nullptr && |
1368 | 1.75k | ((CellIter + 1) != Cells.end())) { |
1369 | 6.26k | for (auto *NextIter = CellIter + 1; NextIter != Cells.end(); ++NextIter4.66k ) { |
1370 | 5.75k | if (NextIter->Cell == CellIter->Cell) { |
1371 | 1.09k | CellIter->NextColumnElement = &(*NextIter); |
1372 | 1.09k | break; |
1373 | 1.09k | } |
1374 | 5.75k | } |
1375 | 1.60k | } |
1376 | 1.75k | } |
1377 | 157 | return std::move(CellDesc); |
1378 | 157 | } |
1379 | | |
1380 | 22.5k | void WhitespaceManager::generateChanges() { |
1381 | 399k | for (unsigned i = 0, e = Changes.size(); i != e; ++i376k ) { |
1382 | 376k | const Change &C = Changes[i]; |
1383 | 376k | if (i > 0 && Changes[i - 1].OriginalWhitespaceRange.getBegin() == |
1384 | 354k | C.OriginalWhitespaceRange.getBegin()) { |
1385 | | // Do not generate two replacements for the same location. |
1386 | 0 | continue; |
1387 | 0 | } |
1388 | 376k | if (C.CreateReplacement) { |
1389 | 352k | std::string ReplacementText = C.PreviousLinePostfix; |
1390 | 352k | if (C.ContinuesPPDirective) { |
1391 | 651 | appendEscapedNewlineText(ReplacementText, C.NewlinesBefore, |
1392 | 651 | C.PreviousEndOfTokenColumn, |
1393 | 651 | C.EscapedNewlineColumn); |
1394 | 352k | } else { |
1395 | 352k | appendNewlineText(ReplacementText, C.NewlinesBefore); |
1396 | 352k | } |
1397 | | // FIXME: This assert should hold if we computed the column correctly. |
1398 | | // assert((int)C.StartOfTokenColumn >= C.Spaces); |
1399 | 352k | appendIndentText( |
1400 | 352k | ReplacementText, C.Tok->IndentLevel, std::max(0, C.Spaces), |
1401 | 352k | std::max((int)C.StartOfTokenColumn, C.Spaces) - std::max(0, C.Spaces), |
1402 | 352k | C.IsAligned); |
1403 | 352k | ReplacementText.append(C.CurrentLinePrefix); |
1404 | 352k | storeReplacement(C.OriginalWhitespaceRange, ReplacementText); |
1405 | 352k | } |
1406 | 376k | } |
1407 | 22.5k | } |
1408 | | |
1409 | 352k | void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) { |
1410 | 352k | unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) - |
1411 | 352k | SourceMgr.getFileOffset(Range.getBegin()); |
1412 | | // Don't create a replacement, if it does not change anything. |
1413 | 352k | if (StringRef(SourceMgr.getCharacterData(Range.getBegin()), |
1414 | 352k | WhitespaceLength) == Text) { |
1415 | 323k | return; |
1416 | 323k | } |
1417 | 29.4k | auto Err = Replaces.add(tooling::Replacement( |
1418 | 29.4k | SourceMgr, CharSourceRange::getCharRange(Range), Text)); |
1419 | | // FIXME: better error handling. For now, just print an error message in the |
1420 | | // release version. |
1421 | 29.4k | if (Err) { |
1422 | 0 | llvm::errs() << llvm::toString(std::move(Err)) << "\n"; |
1423 | 0 | assert(false); |
1424 | 0 | } |
1425 | 29.4k | } |
1426 | | |
1427 | | void WhitespaceManager::appendNewlineText(std::string &Text, |
1428 | 352k | unsigned Newlines) { |
1429 | 352k | if (UseCRLF) { |
1430 | 472 | Text.reserve(Text.size() + 2 * Newlines); |
1431 | 661 | for (unsigned i = 0; i < Newlines; ++i189 ) |
1432 | 189 | Text.append("\r\n"); |
1433 | 351k | } else { |
1434 | 351k | Text.append(Newlines, '\n'); |
1435 | 351k | } |
1436 | 352k | } |
1437 | | |
1438 | | void WhitespaceManager::appendEscapedNewlineText( |
1439 | | std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn, |
1440 | 651 | unsigned EscapedNewlineColumn) { |
1441 | 651 | if (Newlines > 0) { |
1442 | 648 | unsigned Spaces = |
1443 | 648 | std::max<int>(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1); |
1444 | 1.30k | for (unsigned i = 0; i < Newlines; ++i653 ) { |
1445 | 653 | Text.append(Spaces, ' '); |
1446 | 653 | Text.append(UseCRLF ? "\\\r\n"7 : "\\\n"646 ); |
1447 | 653 | Spaces = std::max<int>(0, EscapedNewlineColumn - 1); |
1448 | 653 | } |
1449 | 648 | } |
1450 | 651 | } |
1451 | | |
1452 | | void WhitespaceManager::appendIndentText(std::string &Text, |
1453 | | unsigned IndentLevel, unsigned Spaces, |
1454 | | unsigned WhitespaceStartColumn, |
1455 | 352k | bool IsAligned) { |
1456 | 352k | switch (Style.UseTab) { |
1457 | 350k | case FormatStyle::UT_Never: |
1458 | 350k | Text.append(Spaces, ' '); |
1459 | 350k | break; |
1460 | 571 | case FormatStyle::UT_Always: { |
1461 | 571 | if (Style.TabWidth) { |
1462 | 553 | unsigned FirstTabWidth = |
1463 | 553 | Style.TabWidth - WhitespaceStartColumn % Style.TabWidth; |
1464 | | |
1465 | | // Insert only spaces when we want to end up before the next tab. |
1466 | 553 | if (Spaces < FirstTabWidth || Spaces == 1125 ) { |
1467 | 449 | Text.append(Spaces, ' '); |
1468 | 449 | break; |
1469 | 449 | } |
1470 | | // Align to the next tab. |
1471 | 104 | Spaces -= FirstTabWidth; |
1472 | 104 | Text.append("\t"); |
1473 | | |
1474 | 104 | Text.append(Spaces / Style.TabWidth, '\t'); |
1475 | 104 | Text.append(Spaces % Style.TabWidth, ' '); |
1476 | 104 | } else if (18 Spaces == 118 ) { |
1477 | 2 | Text.append(Spaces, ' '); |
1478 | 2 | } |
1479 | 122 | break; |
1480 | 571 | } |
1481 | 565 | case FormatStyle::UT_ForIndentation: |
1482 | 565 | if (WhitespaceStartColumn == 0) { |
1483 | 237 | unsigned Indentation = IndentLevel * Style.IndentWidth; |
1484 | 237 | Spaces = appendTabIndent(Text, Spaces, Indentation); |
1485 | 237 | } |
1486 | 565 | Text.append(Spaces, ' '); |
1487 | 565 | break; |
1488 | 738 | case FormatStyle::UT_ForContinuationAndIndentation: |
1489 | 738 | if (WhitespaceStartColumn == 0) |
1490 | 319 | Spaces = appendTabIndent(Text, Spaces, Spaces); |
1491 | 738 | Text.append(Spaces, ' '); |
1492 | 738 | break; |
1493 | 840 | case FormatStyle::UT_AlignWithSpaces: |
1494 | 840 | if (WhitespaceStartColumn == 0) { |
1495 | 358 | unsigned Indentation = |
1496 | 358 | IsAligned ? IndentLevel * Style.IndentWidth57 : Spaces301 ; |
1497 | 358 | Spaces = appendTabIndent(Text, Spaces, Indentation); |
1498 | 358 | } |
1499 | 840 | Text.append(Spaces, ' '); |
1500 | 840 | break; |
1501 | 352k | } |
1502 | 352k | } |
1503 | | |
1504 | | unsigned WhitespaceManager::appendTabIndent(std::string &Text, unsigned Spaces, |
1505 | 914 | unsigned Indentation) { |
1506 | | // This happens, e.g. when a line in a block comment is indented less than the |
1507 | | // first one. |
1508 | 914 | if (Indentation > Spaces) |
1509 | 4 | Indentation = Spaces; |
1510 | 914 | if (Style.TabWidth) { |
1511 | 890 | unsigned Tabs = Indentation / Style.TabWidth; |
1512 | 890 | Text.append(Tabs, '\t'); |
1513 | 890 | Spaces -= Tabs * Style.TabWidth; |
1514 | 890 | } |
1515 | 914 | return Spaces; |
1516 | 914 | } |
1517 | | |
1518 | | } // namespace format |
1519 | | } // namespace clang |