clang  6.0.0svn
WhitespaceManager.cpp
Go to the documentation of this file.
1 //===--- WhitespaceManager.cpp - Format C++ code --------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief This file implements WhitespaceManager class.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "WhitespaceManager.h"
16 #include "llvm/ADT/STLExtras.h"
17 
18 namespace clang {
19 namespace format {
20 
22 operator()(const Change &C1, const Change &C2) const {
23  return SourceMgr.isBeforeInTranslationUnit(
26 }
27 
29  bool CreateReplacement,
31  int Spaces, unsigned StartOfTokenColumn,
32  unsigned NewlinesBefore,
33  StringRef PreviousLinePostfix,
34  StringRef CurrentLinePrefix,
36  : Tok(&Tok), CreateReplacement(CreateReplacement),
37  OriginalWhitespaceRange(OriginalWhitespaceRange),
38  StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
39  PreviousLinePostfix(PreviousLinePostfix),
40  CurrentLinePrefix(CurrentLinePrefix),
41  ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces),
42  IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0),
45 
47  unsigned Spaces,
48  unsigned StartOfTokenColumn,
49  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  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  InPPDirective && !Tok.IsFirst,
67  /*IsInsideToken=*/false));
68 }
69 
71  const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
72  StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
73  unsigned Newlines, int Spaces) {
74  if (Tok.Finalized)
75  return;
77  Changes.push_back(
78  Change(Tok, /*CreateReplacement=*/true,
79  SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces,
80  std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,
81  InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/true));
82 }
83 
85  if (Changes.empty())
86  return Replaces;
87 
88  std::sort(Changes.begin(), Changes.end(), Change::IsBeforeInFile(SourceMgr));
89  calculateLineBreakInformation();
90  alignConsecutiveDeclarations();
91  alignConsecutiveAssignments();
92  alignTrailingComments();
93  alignEscapedNewlines();
94  generateChanges();
95 
96  return Replaces;
97 }
98 
99 void WhitespaceManager::calculateLineBreakInformation() {
100  Changes[0].PreviousEndOfTokenColumn = 0;
101  Change *LastOutsideTokenChange = &Changes[0];
102  for (unsigned i = 1, e = Changes.size(); i != e; ++i) {
103  SourceLocation OriginalWhitespaceStart =
104  Changes[i].OriginalWhitespaceRange.getBegin();
105  SourceLocation PreviousOriginalWhitespaceEnd =
106  Changes[i - 1].OriginalWhitespaceRange.getEnd();
107  unsigned OriginalWhitespaceStartOffset =
108  SourceMgr.getFileOffset(OriginalWhitespaceStart);
109  unsigned PreviousOriginalWhitespaceEndOffset =
110  SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd);
111  assert(PreviousOriginalWhitespaceEndOffset <=
112  OriginalWhitespaceStartOffset);
113  const char *const PreviousOriginalWhitespaceEndData =
114  SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd);
115  StringRef Text(PreviousOriginalWhitespaceEndData,
116  SourceMgr.getCharacterData(OriginalWhitespaceStart) -
117  PreviousOriginalWhitespaceEndData);
118  // Usually consecutive changes would occur in consecutive tokens. This is
119  // not the case however when analyzing some preprocessor runs of the
120  // annotated lines. For example, in this code:
121  //
122  // #if A // line 1
123  // int i = 1;
124  // #else B // line 2
125  // int i = 2;
126  // #endif // line 3
127  //
128  // one of the runs will produce the sequence of lines marked with line 1, 2
129  // and 3. So the two consecutive whitespace changes just before '// line 2'
130  // and before '#endif // line 3' span multiple lines and tokens:
131  //
132  // #else B{change X}[// line 2
133  // int i = 2;
134  // ]{change Y}#endif // line 3
135  //
136  // For this reason, if the text between consecutive changes spans multiple
137  // newlines, the token length must be adjusted to the end of the original
138  // line of the token.
139  auto NewlinePos = Text.find_first_of('\n');
140  if (NewlinePos == StringRef::npos) {
141  Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset -
142  PreviousOriginalWhitespaceEndOffset +
143  Changes[i].PreviousLinePostfix.size() +
144  Changes[i - 1].CurrentLinePrefix.size();
145  } else {
146  Changes[i - 1].TokenLength =
147  NewlinePos + Changes[i - 1].CurrentLinePrefix.size();
148  }
149 
150  // If there are multiple changes in this token, sum up all the changes until
151  // the end of the line.
152  if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 0)
153  LastOutsideTokenChange->TokenLength +=
154  Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
155  else
156  LastOutsideTokenChange = &Changes[i - 1];
157 
158  Changes[i].PreviousEndOfTokenColumn =
159  Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
160 
161  Changes[i - 1].IsTrailingComment =
162  (Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof) ||
163  (Changes[i].IsInsideToken && Changes[i].Tok->is(tok::comment))) &&
164  Changes[i - 1].Tok->is(tok::comment) &&
165  // FIXME: This is a dirty hack. The problem is that
166  // BreakableLineCommentSection does comment reflow changes and here is
167  // the aligning of trailing comments. Consider the case where we reflow
168  // the second line up in this example:
169  //
170  // // line 1
171  // // line 2
172  //
173  // That amounts to 2 changes by BreakableLineCommentSection:
174  // - the first, delimited by (), for the whitespace between the tokens,
175  // - and second, delimited by [], for the whitespace at the beginning
176  // of the second token:
177  //
178  // // line 1(
179  // )[// ]line 2
180  //
181  // So in the end we have two changes like this:
182  //
183  // // line1()[ ]line 2
184  //
185  // Note that the OriginalWhitespaceStart of the second change is the
186  // same as the PreviousOriginalWhitespaceEnd of the first change.
187  // In this case, the below check ensures that the second change doesn't
188  // get treated as a trailing comment change here, since this might
189  // trigger additional whitespace to be wrongly inserted before "line 2"
190  // by the comment aligner here.
191  //
192  // For a proper solution we need a mechanism to say to WhitespaceManager
193  // that a particular change breaks the current sequence of trailing
194  // comments.
195  OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd;
196  }
197  // FIXME: The last token is currently not always an eof token; in those
198  // cases, setting TokenLength of the last token to 0 is wrong.
199  Changes.back().TokenLength = 0;
200  Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);
201 
202  const WhitespaceManager::Change *LastBlockComment = nullptr;
203  for (auto &Change : Changes) {
204  // Reset the IsTrailingComment flag for changes inside of trailing comments
205  // so they don't get realigned later. Comment line breaks however still need
206  // to be aligned.
208  Change.IsTrailingComment = false;
209  Change.StartOfBlockComment = nullptr;
211  if (Change.Tok->is(tok::comment)) {
212  if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken)
213  LastBlockComment = &Change;
214  else {
215  if ((Change.StartOfBlockComment = LastBlockComment))
219  }
220  } else {
221  LastBlockComment = nullptr;
222  }
223  }
224 }
225 
226 // Align a single sequence of tokens, see AlignTokens below.
227 template <typename F>
228 static void
229 AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
231  bool FoundMatchOnLine = false;
232  int Shift = 0;
233 
234  // ScopeStack keeps track of the current scope depth. It contains indices of
235  // the first token on each scope.
236  // We only run the "Matches" function on tokens from the outer-most scope.
237  // However, we do need to pay special attention to one class of tokens
238  // that are not in the outer-most scope, and that is function parameters
239  // which are split across multiple lines, as illustrated by this example:
240  // double a(int x);
241  // int b(int y,
242  // double z);
243  // In the above example, we need to take special care to ensure that
244  // 'double z' is indented along with it's owning function 'b'.
245  SmallVector<unsigned, 16> ScopeStack;
246 
247  for (unsigned i = Start; i != End; ++i) {
248  if (ScopeStack.size() != 0 &&
249  Changes[i].indentAndNestingLevel() <
250  Changes[ScopeStack.back()].indentAndNestingLevel())
251  ScopeStack.pop_back();
252 
253  if (i != Start && Changes[i].indentAndNestingLevel() >
254  Changes[i - 1].indentAndNestingLevel())
255  ScopeStack.push_back(i);
256 
257  bool InsideNestedScope = ScopeStack.size() != 0;
258 
259  if (Changes[i].NewlinesBefore > 0 && !InsideNestedScope) {
260  Shift = 0;
261  FoundMatchOnLine = false;
262  }
263 
264  // If this is the first matching token to be aligned, remember by how many
265  // spaces it has to be shifted, so the rest of the changes on the line are
266  // shifted by the same amount
267  if (!FoundMatchOnLine && !InsideNestedScope && Matches(Changes[i])) {
268  FoundMatchOnLine = true;
269  Shift = Column - Changes[i].StartOfTokenColumn;
270  Changes[i].Spaces += Shift;
271  }
272 
273  // This is for function parameters that are split across multiple lines,
274  // as mentioned in the ScopeStack comment.
275  if (InsideNestedScope && Changes[i].NewlinesBefore > 0) {
276  unsigned ScopeStart = ScopeStack.back();
277  if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) ||
278  (ScopeStart > Start + 1 &&
279  Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)))
280  Changes[i].Spaces += Shift;
281  }
282 
283  assert(Shift >= 0);
284  Changes[i].StartOfTokenColumn += Shift;
285  if (i + 1 != Changes.size())
286  Changes[i + 1].PreviousEndOfTokenColumn += Shift;
287  }
288 }
289 
290 // Walk through a subset of the changes, starting at StartAt, and find
291 // sequences of matching tokens to align. To do so, keep track of the lines and
292 // whether or not a matching token was found on a line. If a matching token is
293 // found, extend the current sequence. If the current line cannot be part of a
294 // sequence, e.g. because there is an empty line before it or it contains only
295 // non-matching tokens, finalize the previous sequence.
296 // The value returned is the token on which we stopped, either because we
297 // exhausted all items inside Changes, or because we hit a scope level higher
298 // than our initial scope.
299 // This function is recursive. Each invocation processes only the scope level
300 // equal to the initial level, which is the level of Changes[StartAt].
301 // If we encounter a scope level greater than the initial level, then we call
302 // ourselves recursively, thereby avoiding the pollution of the current state
303 // with the alignment requirements of the nested sub-level. This recursive
304 // behavior is necessary for aligning function prototypes that have one or more
305 // arguments.
306 // If this function encounters a scope level less than the initial level,
307 // it returns the current position.
308 // There is a non-obvious subtlety in the recursive behavior: Even though we
309 // defer processing of nested levels to recursive invocations of this
310 // function, when it comes time to align a sequence of tokens, we run the
311 // alignment on the entire sequence, including the nested levels.
312 // When doing so, most of the nested tokens are skipped, because their
313 // alignment was already handled by the recursive invocations of this function.
314 // However, the special exception is that we do NOT skip function parameters
315 // that are split across multiple lines. See the test case in FormatTest.cpp
316 // that mentions "split function parameter alignment" for an example of this.
317 template <typename F>
318 static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
320  unsigned StartAt) {
321  unsigned MinColumn = 0;
322  unsigned MaxColumn = UINT_MAX;
323 
324  // Line number of the start and the end of the current token sequence.
325  unsigned StartOfSequence = 0;
326  unsigned EndOfSequence = 0;
327 
328  // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
329  // abort when we hit any token in a higher scope than the starting one.
330  auto IndentAndNestingLevel = StartAt < Changes.size()
331  ? Changes[StartAt].indentAndNestingLevel()
332  : std::pair<unsigned, unsigned>(0, 0);
333 
334  // Keep track of the number of commas before the matching tokens, we will only
335  // align a sequence of matching tokens if they are preceded by the same number
336  // of commas.
337  unsigned CommasBeforeLastMatch = 0;
338  unsigned CommasBeforeMatch = 0;
339 
340  // Whether a matching token has been found on the current line.
341  bool FoundMatchOnLine = false;
342 
343  // Aligns a sequence of matching tokens, on the MinColumn column.
344  //
345  // Sequences start from the first matching token to align, and end at the
346  // first token of the first line that doesn't need to be aligned.
347  //
348  // We need to adjust the StartOfTokenColumn of each Change that is on a line
349  // containing any matching token to be aligned and located after such token.
350  auto AlignCurrentSequence = [&] {
351  if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
352  AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
353  Changes);
354  MinColumn = 0;
355  MaxColumn = UINT_MAX;
356  StartOfSequence = 0;
357  EndOfSequence = 0;
358  };
359 
360  unsigned i = StartAt;
361  for (unsigned e = Changes.size(); i != e; ++i) {
362  if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
363  break;
364 
365  if (Changes[i].NewlinesBefore != 0) {
366  CommasBeforeMatch = 0;
367  EndOfSequence = i;
368  // If there is a blank line, or if the last line didn't contain any
369  // matching token, the sequence ends here.
370  if (Changes[i].NewlinesBefore > 1 || !FoundMatchOnLine)
371  AlignCurrentSequence();
372 
373  FoundMatchOnLine = false;
374  }
375 
376  if (Changes[i].Tok->is(tok::comma)) {
377  ++CommasBeforeMatch;
378  } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
379  // Call AlignTokens recursively, skipping over this scope block.
380  unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i);
381  i = StoppedAt - 1;
382  continue;
383  }
384 
385  if (!Matches(Changes[i]))
386  continue;
387 
388  // If there is more than one matching token per line, or if the number of
389  // preceding commas, do not match anymore, end the sequence.
390  if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)
391  AlignCurrentSequence();
392 
393  CommasBeforeLastMatch = CommasBeforeMatch;
394  FoundMatchOnLine = true;
395 
396  if (StartOfSequence == 0)
397  StartOfSequence = i;
398 
399  unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
400  int LineLengthAfter = -Changes[i].Spaces;
401  for (unsigned j = i; j != e && Changes[j].NewlinesBefore == 0; ++j)
402  LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
403  unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
404 
405  // If we are restricted by the maximum column width, end the sequence.
406  if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn ||
407  CommasBeforeLastMatch != CommasBeforeMatch) {
408  AlignCurrentSequence();
409  StartOfSequence = i;
410  }
411 
412  MinColumn = std::max(MinColumn, ChangeMinColumn);
413  MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
414  }
415 
416  EndOfSequence = i;
417  AlignCurrentSequence();
418  return i;
419 }
420 
421 void WhitespaceManager::alignConsecutiveAssignments() {
423  return;
424 
426  [&](const Change &C) {
427  // Do not align on equal signs that are first on a line.
428  if (C.NewlinesBefore > 0)
429  return false;
430 
431  // Do not align on equal signs that are last on a line.
432  if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
433  return false;
434 
435  return C.Tok->is(tok::equal);
436  },
437  Changes, /*StartAt=*/0);
438 }
439 
440 void WhitespaceManager::alignConsecutiveDeclarations() {
442  return;
443 
444  // FIXME: Currently we don't handle properly the PointerAlignment: Right
445  // The * and & are not aligned and are left dangling. Something has to be done
446  // about it, but it raises the question of alignment of code like:
447  // const char* const* v1;
448  // float const* v2;
449  // SomeVeryLongType const& v3;
451  [](Change const &C) {
452  // tok::kw_operator is necessary for aligning operator overload
453  // definitions.
454  return C.Tok->is(TT_StartOfName) ||
455  C.Tok->is(TT_FunctionDeclarationName) ||
456  C.Tok->is(tok::kw_operator);
457  },
458  Changes, /*StartAt=*/0);
459 }
460 
461 void WhitespaceManager::alignTrailingComments() {
462  unsigned MinColumn = 0;
463  unsigned MaxColumn = UINT_MAX;
464  unsigned StartOfSequence = 0;
465  bool BreakBeforeNext = false;
466  unsigned Newlines = 0;
467  for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
469  continue;
470  Newlines += Changes[i].NewlinesBefore;
471  if (!Changes[i].IsTrailingComment)
472  continue;
473 
474  unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
475  unsigned ChangeMaxColumn;
476 
477  if (Style.ColumnLimit == 0)
478  ChangeMaxColumn = UINT_MAX;
479  else if (Style.ColumnLimit >= Changes[i].TokenLength)
480  ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
481  else
482  ChangeMaxColumn = ChangeMinColumn;
483 
484  // If we don't create a replacement for this change, we have to consider
485  // it to be immovable.
486  if (!Changes[i].CreateReplacement)
487  ChangeMaxColumn = ChangeMinColumn;
488 
489  if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
490  ChangeMaxColumn -= 2;
491  // If this comment follows an } in column 0, it probably documents the
492  // closing of a namespace and we don't want to align it.
493  bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
494  Changes[i - 1].Tok->is(tok::r_brace) &&
495  Changes[i - 1].StartOfTokenColumn == 0;
496  bool WasAlignedWithStartOfNextLine = false;
497  if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
498  unsigned CommentColumn = SourceMgr.getSpellingColumnNumber(
500  for (unsigned j = i + 1; j != e; ++j) {
501  if (Changes[j].Tok->is(tok::comment))
502  continue;
503 
504  unsigned NextColumn = SourceMgr.getSpellingColumnNumber(
506  // The start of the next token was previously aligned with the
507  // start of this comment.
508  WasAlignedWithStartOfNextLine =
509  CommentColumn == NextColumn ||
510  CommentColumn == NextColumn + Style.IndentWidth;
511  break;
512  }
513  }
514  if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
515  alignTrailingComments(StartOfSequence, i, MinColumn);
516  MinColumn = ChangeMinColumn;
517  MaxColumn = ChangeMinColumn;
518  StartOfSequence = i;
519  } else if (BreakBeforeNext || Newlines > 1 ||
520  (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
521  // Break the comment sequence if the previous line did not end
522  // in a trailing comment.
523  (Changes[i].NewlinesBefore == 1 && i > 0 &&
524  !Changes[i - 1].IsTrailingComment) ||
525  WasAlignedWithStartOfNextLine) {
526  alignTrailingComments(StartOfSequence, i, MinColumn);
527  MinColumn = ChangeMinColumn;
528  MaxColumn = ChangeMaxColumn;
529  StartOfSequence = i;
530  } else {
531  MinColumn = std::max(MinColumn, ChangeMinColumn);
532  MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
533  }
534  BreakBeforeNext =
535  (i == 0) || (Changes[i].NewlinesBefore > 1) ||
536  // Never start a sequence with a comment at the beginning of
537  // the line.
538  (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
539  Newlines = 0;
540  }
541  alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
542 }
543 
544 void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
545  unsigned Column) {
546  for (unsigned i = Start; i != End; ++i) {
547  int Shift = 0;
548  if (Changes[i].IsTrailingComment) {
549  Shift = Column - Changes[i].StartOfTokenColumn;
550  }
551  if (Changes[i].StartOfBlockComment) {
552  Shift = Changes[i].IndentationOffset +
553  Changes[i].StartOfBlockComment->StartOfTokenColumn -
554  Changes[i].StartOfTokenColumn;
555  }
556  assert(Shift >= 0);
557  Changes[i].Spaces += Shift;
558  if (i + 1 != Changes.size())
559  Changes[i + 1].PreviousEndOfTokenColumn += Shift;
560  Changes[i].StartOfTokenColumn += Shift;
561  }
562 }
563 
564 void WhitespaceManager::alignEscapedNewlines() {
566  return;
567 
569  unsigned MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit;
570  unsigned StartOfMacro = 0;
571  for (unsigned i = 1, e = Changes.size(); i < e; ++i) {
572  Change &C = Changes[i];
573  if (C.NewlinesBefore > 0) {
574  if (C.ContinuesPPDirective) {
575  MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine);
576  } else {
577  alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
578  MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit;
579  StartOfMacro = i;
580  }
581  }
582  }
583  alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
584 }
585 
586 void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End,
587  unsigned Column) {
588  for (unsigned i = Start; i < End; ++i) {
589  Change &C = Changes[i];
590  if (C.NewlinesBefore > 0) {
591  assert(C.ContinuesPPDirective);
592  if (C.PreviousEndOfTokenColumn + 1 > Column)
593  C.EscapedNewlineColumn = 0;
594  else
595  C.EscapedNewlineColumn = Column;
596  }
597  }
598 }
599 
600 void WhitespaceManager::generateChanges() {
601  for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
602  const Change &C = Changes[i];
603  if (i > 0) {
604  assert(Changes[i - 1].OriginalWhitespaceRange.getBegin() !=
605  C.OriginalWhitespaceRange.getBegin() &&
606  "Generating two replacements for the same location");
607  }
608  if (C.CreateReplacement) {
609  std::string ReplacementText = C.PreviousLinePostfix;
610  if (C.ContinuesPPDirective)
611  appendEscapedNewlineText(ReplacementText, C.NewlinesBefore,
612  C.PreviousEndOfTokenColumn,
613  C.EscapedNewlineColumn);
614  else
615  appendNewlineText(ReplacementText, C.NewlinesBefore);
616  appendIndentText(ReplacementText, C.Tok->IndentLevel,
617  std::max(0, C.Spaces),
618  C.StartOfTokenColumn - std::max(0, C.Spaces));
619  ReplacementText.append(C.CurrentLinePrefix);
620  storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
621  }
622  }
623 }
624 
625 void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) {
626  unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) -
627  SourceMgr.getFileOffset(Range.getBegin());
628  // Don't create a replacement, if it does not change anything.
629  if (StringRef(SourceMgr.getCharacterData(Range.getBegin()),
630  WhitespaceLength) == Text)
631  return;
632  auto Err = Replaces.add(tooling::Replacement(
633  SourceMgr, CharSourceRange::getCharRange(Range), Text));
634  // FIXME: better error handling. For now, just print an error message in the
635  // release version.
636  if (Err) {
637  llvm::errs() << llvm::toString(std::move(Err)) << "\n";
638  assert(false);
639  }
640 }
641 
642 void WhitespaceManager::appendNewlineText(std::string &Text,
643  unsigned Newlines) {
644  for (unsigned i = 0; i < Newlines; ++i)
645  Text.append(UseCRLF ? "\r\n" : "\n");
646 }
647 
648 void WhitespaceManager::appendEscapedNewlineText(
649  std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn,
650  unsigned EscapedNewlineColumn) {
651  if (Newlines > 0) {
652  unsigned Spaces =
653  std::max<int>(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1);
654  for (unsigned i = 0; i < Newlines; ++i) {
655  Text.append(Spaces, ' ');
656  Text.append(UseCRLF ? "\\\r\n" : "\\\n");
657  Spaces = std::max<int>(0, EscapedNewlineColumn - 1);
658  }
659  }
660 }
661 
662 void WhitespaceManager::appendIndentText(std::string &Text,
663  unsigned IndentLevel, unsigned Spaces,
664  unsigned WhitespaceStartColumn) {
665  switch (Style.UseTab) {
667  Text.append(Spaces, ' ');
668  break;
669  case FormatStyle::UT_Always: {
670  unsigned FirstTabWidth =
671  Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
672  // Indent with tabs only when there's at least one full tab.
673  if (FirstTabWidth + Style.TabWidth <= Spaces) {
674  Spaces -= FirstTabWidth;
675  Text.append("\t");
676  }
677  Text.append(Spaces / Style.TabWidth, '\t');
678  Text.append(Spaces % Style.TabWidth, ' ');
679  break;
680  }
682  if (WhitespaceStartColumn == 0) {
683  unsigned Indentation = IndentLevel * Style.IndentWidth;
684  // This happens, e.g. when a line in a block comment is indented less than
685  // the first one.
686  if (Indentation > Spaces)
687  Indentation = Spaces;
688  unsigned Tabs = Indentation / Style.TabWidth;
689  Text.append(Tabs, '\t');
690  Spaces -= Tabs * Style.TabWidth;
691  }
692  Text.append(Spaces, ' ');
693  break;
695  if (WhitespaceStartColumn == 0) {
696  unsigned Tabs = Spaces / Style.TabWidth;
697  Text.append(Tabs, '\t');
698  Spaces -= Tabs * Style.TabWidth;
699  }
700  Text.append(Spaces, ' ');
701  break;
702  }
703 }
704 
705 } // namespace format
706 } // 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.
Use tabs only for indentation.
Definition: Format.h:1512
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T -> getSizeExpr()))
unsigned IndentWidth
The number of columns to use for indentation.
Definition: Format.h:1092
unsigned OriginalColumn
The original 0-based column of this token, including expanded tabs.
Definition: FormatToken.h:215
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:99
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:205
bool IsFirst
Indicates that this is the first token of the file.
Definition: FormatToken.h:156
unsigned NewlinesBefore
The number of newlines immediately before the Token.
Definition: FormatToken.h:130
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.
Use tabs whenever we need to fill whitespace that spans at least from one tab stop to the next one...
Definition: Format.h:1517
EscapedNewlineAlignmentStyle AlignEscapedNewlines
Options for aligning backslashes in escaped newlines.
Definition: Format.h:133
Use tabs only for line continuation and indentation.
Definition: Format.h:1514
uint32_t Offset
Definition: CacheTokens.cpp:43
AvailabilityChange Changes[NumAvailabilitySlots]
Definition: AttributeList.h:57
#define UINT_MAX
Definition: limits.h:72
bool AlignConsecutiveAssignments
If true, aligns consecutive assignments.
Definition: Format.h:88
unsigned ColumnLimit
The column limit.
Definition: Format.h:840
SourceLocation getStartOfNonWhitespace() const
Returns actual token start location without leading escaped newlines and whitespace.
Definition: FormatToken.h:439
static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, SmallVector< WhitespaceManager::Change, 16 > &Changes, unsigned StartAt)
A text replacement.
Definition: Replacement.h:81
UseTabStyle UseTab
The way to use tab characters in the resulting file.
Definition: Format.h:1521
WhitespaceManager class manages whitespace around tokens and their replacements.
SourceLocation End
Align escaped newlines as far left as possible.
Definition: Format.h:121
Don&#39;t align escaped newlines.
Definition: Format.h:110
A wrapper around a Token storing information about the whitespace characters preceding it...
Definition: FormatToken.h:120
char __ovld __cnfn min(char x, char y)
Returns y if y < x, otherwise it returns x.
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:33
Encodes a location in the source.
bool is(tok::TokenKind Kind) const
Definition: FormatToken.h:297
const bool InPPDirective
SourceRange WhitespaceRange
The range of the whitespace immediately preceding the Token.
Definition: FormatToken.h:137
The FormatStyle is used to configure the formatting to follow specific guidelines.
Definition: Format.h:46
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:295
std::string toString(const til::SExpr *E)
bool operator()(const Change &C1, const Change &C2) const
unsigned TabWidth
The number of columns used for tab stops.
Definition: Format.h:1505
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
bool AlignTrailingComments
If true, aligns trailing comments.
Definition: Format.h:152
StringRef Text
Definition: Format.cpp:1317
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:290
SourceLocation getBegin() const
const FormatStyle & Style