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