clang  11.0.0git
WhitespaceManager.cpp
Go to the documentation of this file.
1 //===--- WhitespaceManager.cpp - Format C++ code --------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file implements WhitespaceManager class.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "WhitespaceManager.h"
15 #include "llvm/ADT/STLExtras.h"
16 
17 namespace clang {
18 namespace format {
19 
21  const Change &C1, const Change &C2) const {
22  return SourceMgr.isBeforeInTranslationUnit(
25 }
26 
28  bool CreateReplacement,
30  int Spaces, unsigned StartOfTokenColumn,
31  unsigned NewlinesBefore,
32  StringRef PreviousLinePostfix,
33  StringRef CurrentLinePrefix, bool IsAligned,
35  : Tok(&Tok), CreateReplacement(CreateReplacement),
36  OriginalWhitespaceRange(OriginalWhitespaceRange),
37  StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
38  PreviousLinePostfix(PreviousLinePostfix),
39  CurrentLinePrefix(CurrentLinePrefix), IsAligned(IsAligned),
40  ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces),
41  IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0),
44 }
45 
47  unsigned Spaces,
48  unsigned StartOfTokenColumn,
49  bool IsAligned, bool InPPDirective) {
50  if (Tok.Finalized)
51  return;
52  Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue;
53  Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange,
54  Spaces, StartOfTokenColumn, Newlines, "", "",
55  IsAligned, InPPDirective && !Tok.IsFirst,
56  /*IsInsideToken=*/false));
57 }
58 
60  bool InPPDirective) {
61  if (Tok.Finalized)
62  return;
63  Changes.push_back(Change(Tok, /*CreateReplacement=*/false,
64  Tok.WhitespaceRange, /*Spaces=*/0,
65  Tok.OriginalColumn, Tok.NewlinesBefore, "", "",
66  /*IsAligned=*/false, InPPDirective && !Tok.IsFirst,
67  /*IsInsideToken=*/false));
68 }
69 
72  return Replaces.add(Replacement);
73 }
74 
76  const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
77  StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
78  unsigned Newlines, int Spaces) {
79  if (Tok.Finalized)
80  return;
82  Changes.push_back(
83  Change(Tok, /*CreateReplacement=*/true,
84  SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces,
85  std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,
86  /*IsAligned=*/true, InPPDirective && !Tok.IsFirst,
87  /*IsInsideToken=*/true));
88 }
89 
91  if (Changes.empty())
92  return Replaces;
93 
94  llvm::sort(Changes, Change::IsBeforeInFile(SourceMgr));
95  calculateLineBreakInformation();
96  alignConsecutiveMacros();
97  alignConsecutiveDeclarations();
98  alignConsecutiveBitFields();
99  alignConsecutiveAssignments();
100  alignChainedConditionals();
101  alignTrailingComments();
102  alignEscapedNewlines();
103  generateChanges();
104 
105  return Replaces;
106 }
107 
108 void WhitespaceManager::calculateLineBreakInformation() {
109  Changes[0].PreviousEndOfTokenColumn = 0;
110  Change *LastOutsideTokenChange = &Changes[0];
111  for (unsigned i = 1, e = Changes.size(); i != e; ++i) {
112  SourceLocation OriginalWhitespaceStart =
113  Changes[i].OriginalWhitespaceRange.getBegin();
114  SourceLocation PreviousOriginalWhitespaceEnd =
115  Changes[i - 1].OriginalWhitespaceRange.getEnd();
116  unsigned OriginalWhitespaceStartOffset =
117  SourceMgr.getFileOffset(OriginalWhitespaceStart);
118  unsigned PreviousOriginalWhitespaceEndOffset =
119  SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd);
120  assert(PreviousOriginalWhitespaceEndOffset <=
121  OriginalWhitespaceStartOffset);
122  const char *const PreviousOriginalWhitespaceEndData =
123  SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd);
124  StringRef Text(PreviousOriginalWhitespaceEndData,
125  SourceMgr.getCharacterData(OriginalWhitespaceStart) -
126  PreviousOriginalWhitespaceEndData);
127  // Usually consecutive changes would occur in consecutive tokens. This is
128  // not the case however when analyzing some preprocessor runs of the
129  // annotated lines. For example, in this code:
130  //
131  // #if A // line 1
132  // int i = 1;
133  // #else B // line 2
134  // int i = 2;
135  // #endif // line 3
136  //
137  // one of the runs will produce the sequence of lines marked with line 1, 2
138  // and 3. So the two consecutive whitespace changes just before '// line 2'
139  // and before '#endif // line 3' span multiple lines and tokens:
140  //
141  // #else B{change X}[// line 2
142  // int i = 2;
143  // ]{change Y}#endif // line 3
144  //
145  // For this reason, if the text between consecutive changes spans multiple
146  // newlines, the token length must be adjusted to the end of the original
147  // line of the token.
148  auto NewlinePos = Text.find_first_of('\n');
149  if (NewlinePos == StringRef::npos) {
150  Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset -
151  PreviousOriginalWhitespaceEndOffset +
152  Changes[i].PreviousLinePostfix.size() +
153  Changes[i - 1].CurrentLinePrefix.size();
154  } else {
155  Changes[i - 1].TokenLength =
156  NewlinePos + Changes[i - 1].CurrentLinePrefix.size();
157  }
158 
159  // If there are multiple changes in this token, sum up all the changes until
160  // the end of the line.
161  if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 0)
162  LastOutsideTokenChange->TokenLength +=
163  Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
164  else
165  LastOutsideTokenChange = &Changes[i - 1];
166 
167  Changes[i].PreviousEndOfTokenColumn =
168  Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
169 
170  Changes[i - 1].IsTrailingComment =
171  (Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof) ||
172  (Changes[i].IsInsideToken && Changes[i].Tok->is(tok::comment))) &&
173  Changes[i - 1].Tok->is(tok::comment) &&
174  // FIXME: This is a dirty hack. The problem is that
175  // BreakableLineCommentSection does comment reflow changes and here is
176  // the aligning of trailing comments. Consider the case where we reflow
177  // the second line up in this example:
178  //
179  // // line 1
180  // // line 2
181  //
182  // That amounts to 2 changes by BreakableLineCommentSection:
183  // - the first, delimited by (), for the whitespace between the tokens,
184  // - and second, delimited by [], for the whitespace at the beginning
185  // of the second token:
186  //
187  // // line 1(
188  // )[// ]line 2
189  //
190  // So in the end we have two changes like this:
191  //
192  // // line1()[ ]line 2
193  //
194  // Note that the OriginalWhitespaceStart of the second change is the
195  // same as the PreviousOriginalWhitespaceEnd of the first change.
196  // In this case, the below check ensures that the second change doesn't
197  // get treated as a trailing comment change here, since this might
198  // trigger additional whitespace to be wrongly inserted before "line 2"
199  // by the comment aligner here.
200  //
201  // For a proper solution we need a mechanism to say to WhitespaceManager
202  // that a particular change breaks the current sequence of trailing
203  // comments.
204  OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd;
205  }
206  // FIXME: The last token is currently not always an eof token; in those
207  // cases, setting TokenLength of the last token to 0 is wrong.
208  Changes.back().TokenLength = 0;
209  Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);
210 
211  const WhitespaceManager::Change *LastBlockComment = nullptr;
212  for (auto &Change : Changes) {
213  // Reset the IsTrailingComment flag for changes inside of trailing comments
214  // so they don't get realigned later. Comment line breaks however still need
215  // to be aligned.
217  Change.IsTrailingComment = false;
218  Change.StartOfBlockComment = nullptr;
220  if (Change.Tok->is(tok::comment)) {
221  if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken)
222  LastBlockComment = &Change;
223  else {
224  if ((Change.StartOfBlockComment = LastBlockComment))
228  }
229  } else {
230  LastBlockComment = nullptr;
231  }
232  }
233 
234  // Compute conditional nesting level
235  // Level is increased for each conditional, unless this conditional continues
236  // a chain of conditional, i.e. starts immediately after the colon of another
237  // conditional.
238  SmallVector<bool, 16> ScopeStack;
239  int ConditionalsLevel = 0;
240  for (auto &Change : Changes) {
241  for (unsigned i = 0, e = Change.Tok->FakeLParens.size(); i != e; ++i) {
242  bool isNestedConditional =
243  Change.Tok->FakeLParens[e - 1 - i] == prec::Conditional &&
244  !(i == 0 && Change.Tok->Previous &&
245  Change.Tok->Previous->is(TT_ConditionalExpr) &&
246  Change.Tok->Previous->is(tok::colon));
247  if (isNestedConditional)
249  ScopeStack.push_back(isNestedConditional);
250  }
251 
253 
254  for (unsigned i = Change.Tok->FakeRParens; i > 0 && ScopeStack.size();
255  --i) {
256  if (ScopeStack.pop_back_val())
257  --ConditionalsLevel;
258  }
259  }
260 }
261 
262 // Align a single sequence of tokens, see AlignTokens below.
263 template <typename F>
264 static void
265 AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
267  bool FoundMatchOnLine = false;
268  int Shift = 0;
269 
270  // ScopeStack keeps track of the current scope depth. It contains indices of
271  // the first token on each scope.
272  // We only run the "Matches" function on tokens from the outer-most scope.
273  // However, we do need to pay special attention to one class of tokens
274  // that are not in the outer-most scope, and that is function parameters
275  // which are split across multiple lines, as illustrated by this example:
276  // double a(int x);
277  // int b(int y,
278  // double z);
279  // In the above example, we need to take special care to ensure that
280  // 'double z' is indented along with it's owning function 'b'.
281  // Special handling is required for 'nested' ternary operators.
282  SmallVector<unsigned, 16> ScopeStack;
283 
284  for (unsigned i = Start; i != End; ++i) {
285  if (ScopeStack.size() != 0 &&
286  Changes[i].indentAndNestingLevel() <
287  Changes[ScopeStack.back()].indentAndNestingLevel())
288  ScopeStack.pop_back();
289 
290  // Compare current token to previous non-comment token to ensure whether
291  // it is in a deeper scope or not.
292  unsigned PreviousNonComment = i - 1;
293  while (PreviousNonComment > Start &&
294  Changes[PreviousNonComment].Tok->is(tok::comment))
295  PreviousNonComment--;
296  if (i != Start && Changes[i].indentAndNestingLevel() >
297  Changes[PreviousNonComment].indentAndNestingLevel())
298  ScopeStack.push_back(i);
299 
300  bool InsideNestedScope = ScopeStack.size() != 0;
301 
302  if (Changes[i].NewlinesBefore > 0 && !InsideNestedScope) {
303  Shift = 0;
304  FoundMatchOnLine = false;
305  }
306 
307  // If this is the first matching token to be aligned, remember by how many
308  // spaces it has to be shifted, so the rest of the changes on the line are
309  // shifted by the same amount
310  if (!FoundMatchOnLine && !InsideNestedScope && Matches(Changes[i])) {
311  FoundMatchOnLine = true;
312  Shift = Column - Changes[i].StartOfTokenColumn;
313  Changes[i].Spaces += Shift;
314  }
315 
316  // This is for function parameters that are split across multiple lines,
317  // as mentioned in the ScopeStack comment.
318  if (InsideNestedScope && Changes[i].NewlinesBefore > 0) {
319  unsigned ScopeStart = ScopeStack.back();
320  if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) ||
321  (ScopeStart > Start + 1 &&
322  Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)) ||
323  Changes[i].Tok->is(TT_ConditionalExpr) ||
324  (Changes[i].Tok->Previous &&
325  Changes[i].Tok->Previous->is(TT_ConditionalExpr)))
326  Changes[i].Spaces += Shift;
327  }
328 
329  assert(Shift >= 0);
330  Changes[i].StartOfTokenColumn += Shift;
331  if (i + 1 != Changes.size())
332  Changes[i + 1].PreviousEndOfTokenColumn += Shift;
333  }
334 }
335 
336 // Walk through a subset of the changes, starting at StartAt, and find
337 // sequences of matching tokens to align. To do so, keep track of the lines and
338 // whether or not a matching token was found on a line. If a matching token is
339 // found, extend the current sequence. If the current line cannot be part of a
340 // sequence, e.g. because there is an empty line before it or it contains only
341 // non-matching tokens, finalize the previous sequence.
342 // The value returned is the token on which we stopped, either because we
343 // exhausted all items inside Changes, or because we hit a scope level higher
344 // than our initial scope.
345 // This function is recursive. Each invocation processes only the scope level
346 // equal to the initial level, which is the level of Changes[StartAt].
347 // If we encounter a scope level greater than the initial level, then we call
348 // ourselves recursively, thereby avoiding the pollution of the current state
349 // with the alignment requirements of the nested sub-level. This recursive
350 // behavior is necessary for aligning function prototypes that have one or more
351 // arguments.
352 // If this function encounters a scope level less than the initial level,
353 // it returns the current position.
354 // There is a non-obvious subtlety in the recursive behavior: Even though we
355 // defer processing of nested levels to recursive invocations of this
356 // function, when it comes time to align a sequence of tokens, we run the
357 // alignment on the entire sequence, including the nested levels.
358 // When doing so, most of the nested tokens are skipped, because their
359 // alignment was already handled by the recursive invocations of this function.
360 // However, the special exception is that we do NOT skip function parameters
361 // that are split across multiple lines. See the test case in FormatTest.cpp
362 // that mentions "split function parameter alignment" for an example of this.
363 template <typename F>
364 static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
366  unsigned StartAt) {
367  unsigned MinColumn = 0;
368  unsigned MaxColumn = UINT_MAX;
369 
370  // Line number of the start and the end of the current token sequence.
371  unsigned StartOfSequence = 0;
372  unsigned EndOfSequence = 0;
373 
374  // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
375  // abort when we hit any token in a higher scope than the starting one.
376  auto IndentAndNestingLevel = StartAt < Changes.size()
377  ? Changes[StartAt].indentAndNestingLevel()
378  : std::tuple<unsigned, unsigned, unsigned>();
379 
380  // Keep track of the number of commas before the matching tokens, we will only
381  // align a sequence of matching tokens if they are preceded by the same number
382  // of commas.
383  unsigned CommasBeforeLastMatch = 0;
384  unsigned CommasBeforeMatch = 0;
385 
386  // Whether a matching token has been found on the current line.
387  bool FoundMatchOnLine = false;
388 
389  // Aligns a sequence of matching tokens, on the MinColumn column.
390  //
391  // Sequences start from the first matching token to align, and end at the
392  // first token of the first line that doesn't need to be aligned.
393  //
394  // We need to adjust the StartOfTokenColumn of each Change that is on a line
395  // containing any matching token to be aligned and located after such token.
396  auto AlignCurrentSequence = [&] {
397  if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
398  AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
399  Changes);
400  MinColumn = 0;
401  MaxColumn = UINT_MAX;
402  StartOfSequence = 0;
403  EndOfSequence = 0;
404  };
405 
406  unsigned i = StartAt;
407  for (unsigned e = Changes.size(); i != e; ++i) {
408  if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
409  break;
410 
411  if (Changes[i].NewlinesBefore != 0) {
412  CommasBeforeMatch = 0;
413  EndOfSequence = i;
414  // If there is a blank line, there is a forced-align-break (eg,
415  // preprocessor), or if the last line didn't contain any matching token,
416  // the sequence ends here.
417  if (Changes[i].NewlinesBefore > 1 ||
418  Changes[i].Tok->MustBreakAlignBefore || !FoundMatchOnLine)
419  AlignCurrentSequence();
420 
421  FoundMatchOnLine = false;
422  }
423 
424  if (Changes[i].Tok->is(tok::comma)) {
425  ++CommasBeforeMatch;
426  } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
427  // Call AlignTokens recursively, skipping over this scope block.
428  unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i);
429  i = StoppedAt - 1;
430  continue;
431  }
432 
433  if (!Matches(Changes[i]))
434  continue;
435 
436  // If there is more than one matching token per line, or if the number of
437  // preceding commas, do not match anymore, end the sequence.
438  if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)
439  AlignCurrentSequence();
440 
441  CommasBeforeLastMatch = CommasBeforeMatch;
442  FoundMatchOnLine = true;
443 
444  if (StartOfSequence == 0)
445  StartOfSequence = i;
446 
447  unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
448  int LineLengthAfter = Changes[i].TokenLength;
449  for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 0; ++j) {
450  LineLengthAfter += Changes[j].Spaces;
451  // Changes are generally 1:1 with the tokens, but a change could also be
452  // inside of a token, in which case it's counted more than once: once for
453  // the whitespace surrounding the token (!IsInsideToken) and once for
454  // each whitespace change within it (IsInsideToken).
455  // Therefore, changes inside of a token should only count the space.
456  if (!Changes[j].IsInsideToken)
457  LineLengthAfter += Changes[j].TokenLength;
458  }
459  unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
460 
461  // If we are restricted by the maximum column width, end the sequence.
462  if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn ||
463  CommasBeforeLastMatch != CommasBeforeMatch) {
464  AlignCurrentSequence();
465  StartOfSequence = i;
466  }
467 
468  MinColumn = std::max(MinColumn, ChangeMinColumn);
469  MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
470  }
471 
472  EndOfSequence = i;
473  AlignCurrentSequence();
474  return i;
475 }
476 
477 // Aligns a sequence of matching tokens, on the MinColumn column.
478 //
479 // Sequences start from the first matching token to align, and end at the
480 // first token of the first line that doesn't need to be aligned.
481 //
482 // We need to adjust the StartOfTokenColumn of each Change that is on a line
483 // containing any matching token to be aligned and located after such token.
484 static void AlignMacroSequence(
485  unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn,
486  unsigned &MaxColumn, bool &FoundMatchOnLine,
487  std::function<bool(const WhitespaceManager::Change &C)> AlignMacrosMatches,
489  if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) {
490 
491  FoundMatchOnLine = false;
492  int Shift = 0;
493 
494  for (unsigned I = StartOfSequence; I != EndOfSequence; ++I) {
495  if (Changes[I].NewlinesBefore > 0) {
496  Shift = 0;
497  FoundMatchOnLine = false;
498  }
499 
500  // If this is the first matching token to be aligned, remember by how many
501  // spaces it has to be shifted, so the rest of the changes on the line are
502  // shifted by the same amount
503  if (!FoundMatchOnLine && AlignMacrosMatches(Changes[I])) {
504  FoundMatchOnLine = true;
505  Shift = MinColumn - Changes[I].StartOfTokenColumn;
506  Changes[I].Spaces += Shift;
507  }
508 
509  assert(Shift >= 0);
510  Changes[I].StartOfTokenColumn += Shift;
511  if (I + 1 != Changes.size())
512  Changes[I + 1].PreviousEndOfTokenColumn += Shift;
513  }
514  }
515 
516  MinColumn = 0;
517  MaxColumn = UINT_MAX;
518  StartOfSequence = 0;
519  EndOfSequence = 0;
520 }
521 
522 void WhitespaceManager::alignConsecutiveMacros() {
524  return;
525 
526  auto AlignMacrosMatches = [](const Change &C) {
527  const FormatToken *Current = C.Tok;
528  unsigned SpacesRequiredBefore = 1;
529 
530  if (Current->SpacesRequiredBefore == 0 || !Current->Previous)
531  return false;
532 
533  Current = Current->Previous;
534 
535  // If token is a ")", skip over the parameter list, to the
536  // token that precedes the "("
537  if (Current->is(tok::r_paren) && Current->MatchingParen) {
538  Current = Current->MatchingParen->Previous;
539  SpacesRequiredBefore = 0;
540  }
541 
542  if (!Current || !Current->is(tok::identifier))
543  return false;
544 
545  if (!Current->Previous || !Current->Previous->is(tok::pp_define))
546  return false;
547 
548  // For a macro function, 0 spaces are required between the
549  // identifier and the lparen that opens the parameter list.
550  // For a simple macro, 1 space is required between the
551  // identifier and the first token of the defined value.
552  return Current->Next->SpacesRequiredBefore == SpacesRequiredBefore;
553  };
554 
555  unsigned MinColumn = 0;
556  unsigned MaxColumn = UINT_MAX;
557 
558  // Start and end of the token sequence we're processing.
559  unsigned StartOfSequence = 0;
560  unsigned EndOfSequence = 0;
561 
562  // Whether a matching token has been found on the current line.
563  bool FoundMatchOnLine = false;
564 
565  unsigned I = 0;
566  for (unsigned E = Changes.size(); I != E; ++I) {
567  if (Changes[I].NewlinesBefore != 0) {
568  EndOfSequence = I;
569  // If there is a blank line, or if the last line didn't contain any
570  // matching token, the sequence ends here.
571  if (Changes[I].NewlinesBefore > 1 || !FoundMatchOnLine)
572  AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn,
573  FoundMatchOnLine, AlignMacrosMatches, Changes);
574 
575  FoundMatchOnLine = false;
576  }
577 
578  if (!AlignMacrosMatches(Changes[I]))
579  continue;
580 
581  FoundMatchOnLine = true;
582 
583  if (StartOfSequence == 0)
584  StartOfSequence = I;
585 
586  unsigned ChangeMinColumn = Changes[I].StartOfTokenColumn;
587  int LineLengthAfter = -Changes[I].Spaces;
588  for (unsigned j = I; j != E && Changes[j].NewlinesBefore == 0; ++j)
589  LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
590  unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
591 
592  MinColumn = std::max(MinColumn, ChangeMinColumn);
593  MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
594  }
595 
596  EndOfSequence = I;
597  AlignMacroSequence(StartOfSequence, EndOfSequence, MinColumn, MaxColumn,
598  FoundMatchOnLine, AlignMacrosMatches, Changes);
599 }
600 
601 void WhitespaceManager::alignConsecutiveAssignments() {
603  return;
604 
605  AlignTokens(
606  Style,
607  [&](const Change &C) {
608  // Do not align on equal signs that are first on a line.
609  if (C.NewlinesBefore > 0)
610  return false;
611 
612  // Do not align on equal signs that are last on a line.
613  if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
614  return false;
615 
616  return C.Tok->is(tok::equal);
617  },
618  Changes, /*StartAt=*/0);
619 }
620 
621 void WhitespaceManager::alignConsecutiveBitFields() {
623  return;
624 
625  AlignTokens(
626  Style,
627  [&](Change const &C) {
628  // Do not align on ':' that is first on a line.
629  if (C.NewlinesBefore > 0)
630  return false;
631 
632  // Do not align on ':' that is last on a line.
633  if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
634  return false;
635 
636  return C.Tok->is(TT_BitFieldColon);
637  },
638  Changes, /*StartAt=*/0);
639 }
640 
641 void WhitespaceManager::alignConsecutiveDeclarations() {
643  return;
644 
645  // FIXME: Currently we don't handle properly the PointerAlignment: Right
646  // The * and & are not aligned and are left dangling. Something has to be done
647  // about it, but it raises the question of alignment of code like:
648  // const char* const* v1;
649  // float const* v2;
650  // SomeVeryLongType const& v3;
651  AlignTokens(
652  Style,
653  [](Change const &C) {
654  // tok::kw_operator is necessary for aligning operator overload
655  // definitions.
656  if (C.Tok->isOneOf(TT_FunctionDeclarationName, tok::kw_operator))
657  return true;
658  if (C.Tok->isNot(TT_StartOfName))
659  return false;
660  // Check if there is a subsequent name that starts the same declaration.
661  for (FormatToken *Next = C.Tok->Next; Next; Next = Next->Next) {
662  if (Next->is(tok::comment))
663  continue;
664  if (!Next->Tok.getIdentifierInfo())
665  break;
666  if (Next->isOneOf(TT_StartOfName, TT_FunctionDeclarationName,
667  tok::kw_operator))
668  return false;
669  }
670  return true;
671  },
672  Changes, /*StartAt=*/0);
673 }
674 
675 void WhitespaceManager::alignChainedConditionals() {
676  if (Style.BreakBeforeTernaryOperators) {
677  AlignTokens(
678  Style,
679  [](Change const &C) {
680  // Align question operators and last colon
681  return C.Tok->is(TT_ConditionalExpr) &&
682  ((C.Tok->is(tok::question) && !C.NewlinesBefore) ||
683  (C.Tok->is(tok::colon) && C.Tok->Next &&
684  (C.Tok->Next->FakeLParens.size() == 0 ||
685  C.Tok->Next->FakeLParens.back() != prec::Conditional)));
686  },
687  Changes, /*StartAt=*/0);
688  } else {
689  static auto AlignWrappedOperand = [](Change const &C) {
690  auto Previous = C.Tok->getPreviousNonComment(); // Previous;
691  return C.NewlinesBefore && Previous && Previous->is(TT_ConditionalExpr) &&
692  (Previous->is(tok::question) ||
693  (Previous->is(tok::colon) &&
694  (C.Tok->FakeLParens.size() == 0 ||
695  C.Tok->FakeLParens.back() != prec::Conditional)));
696  };
697  // Ensure we keep alignment of wrapped operands with non-wrapped operands
698  // Since we actually align the operators, the wrapped operands need the
699  // extra offset to be properly aligned.
700  for (Change &C : Changes) {
701  if (AlignWrappedOperand(C))
702  C.StartOfTokenColumn -= 2;
703  }
704  AlignTokens(
705  Style,
706  [this](Change const &C) {
707  // Align question operators if next operand is not wrapped, as
708  // well as wrapped operands after question operator or last
709  // colon in conditional sequence
710  return (C.Tok->is(TT_ConditionalExpr) && C.Tok->is(tok::question) &&
711  &C != &Changes.back() && (&C + 1)->NewlinesBefore == 0 &&
712  !(&C + 1)->IsTrailingComment) ||
713  AlignWrappedOperand(C);
714  },
715  Changes, /*StartAt=*/0);
716  }
717 }
718 
719 void WhitespaceManager::alignTrailingComments() {
720  unsigned MinColumn = 0;
721  unsigned MaxColumn = UINT_MAX;
722  unsigned StartOfSequence = 0;
723  bool BreakBeforeNext = false;
724  unsigned Newlines = 0;
725  for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
726  if (Changes[i].StartOfBlockComment)
727  continue;
728  Newlines += Changes[i].NewlinesBefore;
729  if (Changes[i].Tok->MustBreakAlignBefore)
730  BreakBeforeNext = true;
731  if (!Changes[i].IsTrailingComment)
732  continue;
733 
734  unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
735  unsigned ChangeMaxColumn;
736 
737  if (Style.ColumnLimit == 0)
738  ChangeMaxColumn = UINT_MAX;
739  else if (Style.ColumnLimit >= Changes[i].TokenLength)
740  ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
741  else
742  ChangeMaxColumn = ChangeMinColumn;
743 
744  // If we don't create a replacement for this change, we have to consider
745  // it to be immovable.
746  if (!Changes[i].CreateReplacement)
747  ChangeMaxColumn = ChangeMinColumn;
748 
749  if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
750  ChangeMaxColumn -= 2;
751  // If this comment follows an } in column 0, it probably documents the
752  // closing of a namespace and we don't want to align it.
753  bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
754  Changes[i - 1].Tok->is(tok::r_brace) &&
755  Changes[i - 1].StartOfTokenColumn == 0;
756  bool WasAlignedWithStartOfNextLine = false;
757  if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
758  unsigned CommentColumn = SourceMgr.getSpellingColumnNumber(
759  Changes[i].OriginalWhitespaceRange.getEnd());
760  for (unsigned j = i + 1; j != e; ++j) {
761  if (Changes[j].Tok->is(tok::comment))
762  continue;
763 
764  unsigned NextColumn = SourceMgr.getSpellingColumnNumber(
765  Changes[j].OriginalWhitespaceRange.getEnd());
766  // The start of the next token was previously aligned with the
767  // start of this comment.
768  WasAlignedWithStartOfNextLine =
769  CommentColumn == NextColumn ||
770  CommentColumn == NextColumn + Style.IndentWidth;
771  break;
772  }
773  }
774  if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
775  alignTrailingComments(StartOfSequence, i, MinColumn);
776  MinColumn = ChangeMinColumn;
777  MaxColumn = ChangeMinColumn;
778  StartOfSequence = i;
779  } else if (BreakBeforeNext || Newlines > 1 ||
780  (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
781  // Break the comment sequence if the previous line did not end
782  // in a trailing comment.
783  (Changes[i].NewlinesBefore == 1 && i > 0 &&
784  !Changes[i - 1].IsTrailingComment) ||
785  WasAlignedWithStartOfNextLine) {
786  alignTrailingComments(StartOfSequence, i, MinColumn);
787  MinColumn = ChangeMinColumn;
788  MaxColumn = ChangeMaxColumn;
789  StartOfSequence = i;
790  } else {
791  MinColumn = std::max(MinColumn, ChangeMinColumn);
792  MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
793  }
794  BreakBeforeNext = (i == 0) || (Changes[i].NewlinesBefore > 1) ||
795  // Never start a sequence with a comment at the beginning
796  // of the line.
797  (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
798  Newlines = 0;
799  }
800  alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
801 }
802 
803 void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
804  unsigned Column) {
805  for (unsigned i = Start; i != End; ++i) {
806  int Shift = 0;
807  if (Changes[i].IsTrailingComment) {
808  Shift = Column - Changes[i].StartOfTokenColumn;
809  }
810  if (Changes[i].StartOfBlockComment) {
811  Shift = Changes[i].IndentationOffset +
812  Changes[i].StartOfBlockComment->StartOfTokenColumn -
813  Changes[i].StartOfTokenColumn;
814  }
815  assert(Shift >= 0);
816  Changes[i].Spaces += Shift;
817  if (i + 1 != Changes.size())
818  Changes[i + 1].PreviousEndOfTokenColumn += Shift;
819  Changes[i].StartOfTokenColumn += Shift;
820  }
821 }
822 
823 void WhitespaceManager::alignEscapedNewlines() {
825  return;
826 
828  unsigned MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit;
829  unsigned StartOfMacro = 0;
830  for (unsigned i = 1, e = Changes.size(); i < e; ++i) {
831  Change &C = Changes[i];
832  if (C.NewlinesBefore > 0) {
833  if (C.ContinuesPPDirective) {
834  MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine);
835  } else {
836  alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
837  MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit;
838  StartOfMacro = i;
839  }
840  }
841  }
842  alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
843 }
844 
845 void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End,
846  unsigned Column) {
847  for (unsigned i = Start; i < End; ++i) {
848  Change &C = Changes[i];
849  if (C.NewlinesBefore > 0) {
850  assert(C.ContinuesPPDirective);
851  if (C.PreviousEndOfTokenColumn + 1 > Column)
852  C.EscapedNewlineColumn = 0;
853  else
854  C.EscapedNewlineColumn = Column;
855  }
856  }
857 }
858 
859 void WhitespaceManager::generateChanges() {
860  for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
861  const Change &C = Changes[i];
862  if (i > 0) {
863  assert(Changes[i - 1].OriginalWhitespaceRange.getBegin() !=
864  C.OriginalWhitespaceRange.getBegin() &&
865  "Generating two replacements for the same location");
866  }
867  if (C.CreateReplacement) {
868  std::string ReplacementText = C.PreviousLinePostfix;
869  if (C.ContinuesPPDirective)
870  appendEscapedNewlineText(ReplacementText, C.NewlinesBefore,
871  C.PreviousEndOfTokenColumn,
872  C.EscapedNewlineColumn);
873  else
874  appendNewlineText(ReplacementText, C.NewlinesBefore);
875  appendIndentText(
876  ReplacementText, C.Tok->IndentLevel, std::max(0, C.Spaces),
877  C.StartOfTokenColumn - std::max(0, C.Spaces), C.IsAligned);
878  ReplacementText.append(C.CurrentLinePrefix);
879  storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
880  }
881  }
882 }
883 
884 void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) {
885  unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) -
886  SourceMgr.getFileOffset(Range.getBegin());
887  // Don't create a replacement, if it does not change anything.
888  if (StringRef(SourceMgr.getCharacterData(Range.getBegin()),
889  WhitespaceLength) == Text)
890  return;
891  auto Err = Replaces.add(tooling::Replacement(
892  SourceMgr, CharSourceRange::getCharRange(Range), Text));
893  // FIXME: better error handling. For now, just print an error message in the
894  // release version.
895  if (Err) {
896  llvm::errs() << llvm::toString(std::move(Err)) << "\n";
897  assert(false);
898  }
899 }
900 
901 void WhitespaceManager::appendNewlineText(std::string &Text,
902  unsigned Newlines) {
903  for (unsigned i = 0; i < Newlines; ++i)
904  Text.append(UseCRLF ? "\r\n" : "\n");
905 }
906 
907 void WhitespaceManager::appendEscapedNewlineText(
908  std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn,
909  unsigned EscapedNewlineColumn) {
910  if (Newlines > 0) {
911  unsigned Spaces =
912  std::max<int>(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1);
913  for (unsigned i = 0; i < Newlines; ++i) {
914  Text.append(Spaces, ' ');
915  Text.append(UseCRLF ? "\\\r\n" : "\\\n");
916  Spaces = std::max<int>(0, EscapedNewlineColumn - 1);
917  }
918  }
919 }
920 
921 void WhitespaceManager::appendIndentText(std::string &Text,
922  unsigned IndentLevel, unsigned Spaces,
923  unsigned WhitespaceStartColumn,
924  bool IsAligned) {
925  switch (Style.UseTab) {
926  case FormatStyle::UT_Never:
927  Text.append(Spaces, ' ');
928  break;
929  case FormatStyle::UT_Always: {
930  if (Style.TabWidth) {
931  unsigned FirstTabWidth =
932  Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
933 
934  // Insert only spaces when we want to end up before the next tab.
935  if (Spaces < FirstTabWidth || Spaces == 1) {
936  Text.append(Spaces, ' ');
937  break;
938  }
939  // Align to the next tab.
940  Spaces -= FirstTabWidth;
941  Text.append("\t");
942 
943  Text.append(Spaces / Style.TabWidth, '\t');
944  Text.append(Spaces % Style.TabWidth, ' ');
945  } else if (Spaces == 1) {
946  Text.append(Spaces, ' ');
947  }
948  break;
949  }
950  case FormatStyle::UT_ForIndentation:
951  if (WhitespaceStartColumn == 0) {
952  unsigned Indentation = IndentLevel * Style.IndentWidth;
953  Spaces = appendTabIndent(Text, Spaces, Indentation);
954  }
955  Text.append(Spaces, ' ');
956  break;
957  case FormatStyle::UT_ForContinuationAndIndentation:
958  if (WhitespaceStartColumn == 0)
959  Spaces = appendTabIndent(Text, Spaces, Spaces);
960  Text.append(Spaces, ' ');
961  break;
962  case FormatStyle::UT_AlignWithSpaces:
963  if (WhitespaceStartColumn == 0) {
964  unsigned Indentation =
965  IsAligned ? IndentLevel * Style.IndentWidth : Spaces;
966  Spaces = appendTabIndent(Text, Spaces, Indentation);
967  }
968  Text.append(Spaces, ' ');
969  break;
970  }
971 }
972 
973 unsigned WhitespaceManager::appendTabIndent(std::string &Text, unsigned Spaces,
974  unsigned Indentation) {
975  // This happens, e.g. when a line in a block comment is indented less than the
976  // first one.
977  if (Indentation > Spaces)
978  Indentation = Spaces;
979  if (Style.TabWidth) {
980  unsigned Tabs = Indentation / Style.TabWidth;
981  Text.append(Tabs, '\t');
982  Spaces -= Tabs * Style.TabWidth;
983  }
984  return Spaces;
985 }
986 
987 } // namespace format
988 } // namespace clang
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
unsigned OriginalColumn
The original 0-based column of this token, including expanded tabs.
Definition: FormatToken.h:242
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
bool AlignConsecutiveDeclarations
If true, aligns consecutive declarations.
Definition: Format.h:131
static void AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches, SmallVector< WhitespaceManager::Change, 16 > &Changes)
Maintains a set of replacements that are conflict-free.
Definition: Replacement.h:209
bool IsFirst
Indicates that this is the first token of the file.
Definition: FormatToken.h:178
Change(const FormatToken &Tok, bool CreateReplacement, SourceRange OriginalWhitespaceRange, int Spaces, unsigned StartOfTokenColumn, unsigned NewlinesBefore, StringRef PreviousLinePostfix, StringRef CurrentLinePrefix, bool IsAligned, bool ContinuesPPDirective, bool IsInsideToken)
Creates a Change.
unsigned NewlinesBefore
The number of newlines immediately before the Token.
Definition: FormatToken.h:152
FormatToken * Next
The next token in the unwrapped line.
Definition: FormatToken.h:320
void replaceWhitespaceInToken(const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, unsigned Newlines, int Spaces)
Inserts or replaces whitespace in the middle of a token.
unsigned FakeRParens
Insert this many fake ) after this token for correct indentation.
Definition: FormatToken.h:287
EscapedNewlineAlignmentStyle AlignEscapedNewlines
Options for aligning backslashes in escaped newlines.
Definition: Format.h:165
FormatToken * Previous
The previous token in the unwrapped line.
Definition: FormatToken.h:317
unsigned SpacesRequiredBefore
The number of spaces that should be inserted before this token.
Definition: FormatToken.h:210
#define UINT_MAX
Definition: limits.h:56
bool AlignConsecutiveAssignments
If true, aligns consecutive assignments.
Definition: Format.h:109
SourceLocation getStartOfNonWhitespace() const
Returns actual token start location without leading escaped newlines and whitespace.
Definition: FormatToken.h:499
void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned Spaces, unsigned StartOfTokenColumn, bool isAligned=false, bool InPPDirective=false)
Replaces the whitespace in front of Tok.
static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, SmallVector< WhitespaceManager::Change, 16 > &Changes, unsigned StartAt)
A text replacement.
Definition: Replacement.h:83
WhitespaceManager class manages whitespace around tokens and their replacements.
unsigned Offset
Definition: Format.cpp:2020
__DEVICE__ int min(int __a, int __b)
SourceLocation End
llvm::Error addReplacement(const tooling::Replacement &Replacement)
StateNode * Previous
Align escaped newlines as far left as possible.
Definition: Format.h:153
Don&#39;t align escaped newlines.
Definition: Format.h:142
A wrapper around a Token storing information about the whitespace characters preceding it...
Definition: FormatToken.h:142
const tooling::Replacements & generateReplacements()
Returns all the Replacements created during formatting.
Represents a change before a token, a break inside a token, or the layout of an unchanged token (or w...
SourceLocation getEnd() const
static CharSourceRange getCharRange(SourceRange R)
#define false
Definition: stdbool.h:17
Encodes a location in the source.
bool is(tok::TokenKind Kind) const
Definition: FormatToken.h:334
const bool InPPDirective
SourceRange WhitespaceRange
The range of the whitespace immediately preceding the Token.
Definition: FormatToken.h:159
SmallVector< prec::Level, 4 > FakeLParens
Stores the number of required fake parentheses and the corresponding operator precedence.
Definition: FormatToken.h:285
The FormatStyle is used to configure the formatting to follow specific guidelines.
Definition: Format.h:54
Dataflow Directional Tag Classes.
Functor to sort changes in original source order.
void addUntouchableToken(const FormatToken &Tok, bool InPPDirective)
Adds information about an unchangeable token&#39;s whitespace.
bool Finalized
If true, this token has been fully formatted (indented and potentially re-formatted inside)...
Definition: FormatToken.h:332
static void AlignMacroSequence(unsigned &StartOfSequence, unsigned &EndOfSequence, unsigned &MinColumn, unsigned &MaxColumn, bool &FoundMatchOnLine, std::function< bool(const WhitespaceManager::Change &C)> AlignMacrosMatches, SmallVector< WhitespaceManager::Change, 16 > &Changes)
std::string toString(const til::SExpr *E)
bool operator()(const Change &C1, const Change &C2) const
bool AlignConsecutiveMacros
If true, aligns consecutive C/C++ preprocessor macros.
Definition: Format.h:98
__DEVICE__ int max(int __a, int __b)
FormatToken * MatchingParen
If this is a bracket, this points to the matching one.
Definition: FormatToken.h:314
bool AlignTrailingComments
If true, aligns trailing comments.
Definition: Format.h:211
bool MustBreakAlignBefore
Whether to not align across this token.
Definition: FormatToken.h:190
StringRef Text
Definition: Format.cpp:2019
A trivial tuple used to represent a source range.
FormatDecision Decision
Stores the formatting decision for the token once it was made.
Definition: FormatToken.h:327
SourceLocation getBegin() const
bool AlignConsecutiveBitFields
If true, aligns consecutive bitfield members.
Definition: Format.h:120
const FormatStyle & Style
std::tuple< unsigned, unsigned, unsigned > indentAndNestingLevel() const