]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/Format/WhitespaceManager.cpp
Merge ^/head r317281 through r317502.
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / Format / WhitespaceManager.cpp
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
21 bool WhitespaceManager::Change::IsBeforeInFile::
22 operator()(const Change &C1, const Change &C2) const {
23   return SourceMgr.isBeforeInTranslationUnit(
24       C1.OriginalWhitespaceRange.getBegin(),
25       C2.OriginalWhitespaceRange.getBegin());
26 }
27
28 WhitespaceManager::Change::Change(const FormatToken &Tok,
29                                   bool CreateReplacement,
30                                   SourceRange OriginalWhitespaceRange,
31                                   int Spaces, unsigned StartOfTokenColumn,
32                                   unsigned NewlinesBefore,
33                                   StringRef PreviousLinePostfix,
34                                   StringRef CurrentLinePrefix,
35                                   bool ContinuesPPDirective, bool IsInsideToken)
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),
43       PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0),
44       StartOfBlockComment(nullptr), IndentationOffset(0) {}
45
46 void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines,
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
59 void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
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
70 void WhitespaceManager::replaceWhitespaceInToken(
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;
76   SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
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
84 const tooling::Replacements &WhitespaceManager::generateReplacements() {
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     unsigned OriginalWhitespaceStart =
104         SourceMgr.getFileOffset(Changes[i].OriginalWhitespaceRange.getBegin());
105     unsigned PreviousOriginalWhitespaceEnd = SourceMgr.getFileOffset(
106         Changes[i - 1].OriginalWhitespaceRange.getEnd());
107     Changes[i - 1].TokenLength = OriginalWhitespaceStart -
108                                  PreviousOriginalWhitespaceEnd +
109                                  Changes[i].PreviousLinePostfix.size() +
110                                  Changes[i - 1].CurrentLinePrefix.size();
111
112     // If there are multiple changes in this token, sum up all the changes until
113     // the end of the line.
114     if (Changes[i - 1].IsInsideToken)
115       LastOutsideTokenChange->TokenLength +=
116           Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
117     else
118       LastOutsideTokenChange = &Changes[i - 1];
119
120     Changes[i].PreviousEndOfTokenColumn =
121         Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
122
123     Changes[i - 1].IsTrailingComment =
124         (Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof) ||
125          (Changes[i].IsInsideToken && Changes[i].Tok->is(tok::comment))) &&
126         Changes[i - 1].Tok->is(tok::comment) &&
127         // FIXME: This is a dirty hack. The problem is that
128         // BreakableLineCommentSection does comment reflow changes and here is
129         // the aligning of trailing comments. Consider the case where we reflow
130         // the second line up in this example:
131         // 
132         // // line 1
133         // // line 2
134         // 
135         // That amounts to 2 changes by BreakableLineCommentSection:
136         //  - the first, delimited by (), for the whitespace between the tokens,
137         //  - and second, delimited by [], for the whitespace at the beginning
138         //  of the second token:
139         // 
140         // // line 1(
141         // )[// ]line 2
142         //
143         // So in the end we have two changes like this:
144         //
145         // // line1()[ ]line 2
146         //
147         // Note that the OriginalWhitespaceStart of the second change is the
148         // same as the PreviousOriginalWhitespaceEnd of the first change.
149         // In this case, the below check ensures that the second change doesn't
150         // get treated as a trailing comment change here, since this might
151         // trigger additional whitespace to be wrongly inserted before "line 2"
152         // by the comment aligner here.
153         //
154         // For a proper solution we need a mechanism to say to WhitespaceManager
155         // that a particular change breaks the current sequence of trailing
156         // comments.
157         OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd;
158   }
159   // FIXME: The last token is currently not always an eof token; in those
160   // cases, setting TokenLength of the last token to 0 is wrong.
161   Changes.back().TokenLength = 0;
162   Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);
163
164   const WhitespaceManager::Change *LastBlockComment = nullptr;
165   for (auto &Change : Changes) {
166     // Reset the IsTrailingComment flag for changes inside of trailing comments
167     // so they don't get realigned later. Comment line breaks however still need
168     // to be aligned.
169     if (Change.IsInsideToken && Change.NewlinesBefore == 0)
170       Change.IsTrailingComment = false;
171     Change.StartOfBlockComment = nullptr;
172     Change.IndentationOffset = 0;
173     if (Change.Tok->is(tok::comment)) {
174       if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken)
175         LastBlockComment = &Change;
176       else {
177         if ((Change.StartOfBlockComment = LastBlockComment))
178           Change.IndentationOffset =
179               Change.StartOfTokenColumn -
180               Change.StartOfBlockComment->StartOfTokenColumn;
181       }
182     } else {
183       LastBlockComment = nullptr;
184     }
185   }
186 }
187
188 // Align a single sequence of tokens, see AlignTokens below.
189 template <typename F>
190 static void
191 AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches,
192                    SmallVector<WhitespaceManager::Change, 16> &Changes) {
193   bool FoundMatchOnLine = false;
194   int Shift = 0;
195
196   // ScopeStack keeps track of the current scope depth. It contains indices of
197   // the first token on each scope.
198   // We only run the "Matches" function on tokens from the outer-most scope.
199   // However, we do need to pay special attention to one class of tokens
200   // that are not in the outer-most scope, and that is function parameters
201   // which are split across multiple lines, as illustrated by this example:
202   //   double a(int x);
203   //   int    b(int  y,
204   //          double z);
205   // In the above example, we need to take special care to ensure that
206   // 'double z' is indented along with it's owning function 'b'.
207   SmallVector<unsigned, 16> ScopeStack;
208
209   for (unsigned i = Start; i != End; ++i) {
210     if (ScopeStack.size() != 0 &&
211         Changes[i].nestingAndIndentLevel() <
212             Changes[ScopeStack.back()].nestingAndIndentLevel())
213       ScopeStack.pop_back();
214
215     if (i != Start && Changes[i].nestingAndIndentLevel() >
216                           Changes[i - 1].nestingAndIndentLevel())
217       ScopeStack.push_back(i);
218
219     bool InsideNestedScope = ScopeStack.size() != 0;
220
221     if (Changes[i].NewlinesBefore > 0 && !InsideNestedScope) {
222       Shift = 0;
223       FoundMatchOnLine = false;
224     }
225
226     // If this is the first matching token to be aligned, remember by how many
227     // spaces it has to be shifted, so the rest of the changes on the line are
228     // shifted by the same amount
229     if (!FoundMatchOnLine && !InsideNestedScope && Matches(Changes[i])) {
230       FoundMatchOnLine = true;
231       Shift = Column - Changes[i].StartOfTokenColumn;
232       Changes[i].Spaces += Shift;
233     }
234
235     // This is for function parameters that are split across multiple lines,
236     // as mentioned in the ScopeStack comment.
237     if (InsideNestedScope && Changes[i].NewlinesBefore > 0) {
238       unsigned ScopeStart = ScopeStack.back();
239       if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) ||
240           (ScopeStart > Start + 1 &&
241            Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName)))
242         Changes[i].Spaces += Shift;
243     }
244
245     assert(Shift >= 0);
246     Changes[i].StartOfTokenColumn += Shift;
247     if (i + 1 != Changes.size())
248       Changes[i + 1].PreviousEndOfTokenColumn += Shift;
249   }
250 }
251
252 // Walk through a subset of the changes, starting at StartAt, and find
253 // sequences of matching tokens to align. To do so, keep track of the lines and
254 // whether or not a matching token was found on a line. If a matching token is
255 // found, extend the current sequence. If the current line cannot be part of a
256 // sequence, e.g. because there is an empty line before it or it contains only
257 // non-matching tokens, finalize the previous sequence.
258 // The value returned is the token on which we stopped, either because we
259 // exhausted all items inside Changes, or because we hit a scope level higher
260 // than our initial scope.
261 // This function is recursive. Each invocation processes only the scope level
262 // equal to the initial level, which is the level of Changes[StartAt].
263 // If we encounter a scope level greater than the initial level, then we call
264 // ourselves recursively, thereby avoiding the pollution of the current state
265 // with the alignment requirements of the nested sub-level. This recursive
266 // behavior is necessary for aligning function prototypes that have one or more
267 // arguments.
268 // If this function encounters a scope level less than the initial level,
269 // it returns the current position.
270 // There is a non-obvious subtlety in the recursive behavior: Even though we
271 // defer processing of nested levels to recursive invocations of this
272 // function, when it comes time to align a sequence of tokens, we run the
273 // alignment on the entire sequence, including the nested levels.
274 // When doing so, most of the nested tokens are skipped, because their
275 // alignment was already handled by the recursive invocations of this function.
276 // However, the special exception is that we do NOT skip function parameters
277 // that are split across multiple lines. See the test case in FormatTest.cpp
278 // that mentions "split function parameter alignment" for an example of this.
279 template <typename F>
280 static unsigned AlignTokens(const FormatStyle &Style, F &&Matches,
281                             SmallVector<WhitespaceManager::Change, 16> &Changes,
282                             unsigned StartAt) {
283   unsigned MinColumn = 0;
284   unsigned MaxColumn = UINT_MAX;
285
286   // Line number of the start and the end of the current token sequence.
287   unsigned StartOfSequence = 0;
288   unsigned EndOfSequence = 0;
289
290   // Measure the scope level (i.e. depth of (), [], {}) of the first token, and
291   // abort when we hit any token in a higher scope than the starting one.
292   auto NestingAndIndentLevel = StartAt < Changes.size()
293                                    ? Changes[StartAt].nestingAndIndentLevel()
294                                    : std::pair<unsigned, unsigned>(0, 0);
295
296   // Keep track of the number of commas before the matching tokens, we will only
297   // align a sequence of matching tokens if they are preceded by the same number
298   // of commas.
299   unsigned CommasBeforeLastMatch = 0;
300   unsigned CommasBeforeMatch = 0;
301
302   // Whether a matching token has been found on the current line.
303   bool FoundMatchOnLine = false;
304
305   // Aligns a sequence of matching tokens, on the MinColumn column.
306   //
307   // Sequences start from the first matching token to align, and end at the
308   // first token of the first line that doesn't need to be aligned.
309   //
310   // We need to adjust the StartOfTokenColumn of each Change that is on a line
311   // containing any matching token to be aligned and located after such token.
312   auto AlignCurrentSequence = [&] {
313     if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
314       AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches,
315                          Changes);
316     MinColumn = 0;
317     MaxColumn = UINT_MAX;
318     StartOfSequence = 0;
319     EndOfSequence = 0;
320   };
321
322   unsigned i = StartAt;
323   for (unsigned e = Changes.size(); i != e; ++i) {
324     if (Changes[i].nestingAndIndentLevel() < NestingAndIndentLevel)
325       break;
326
327     if (Changes[i].NewlinesBefore != 0) {
328       CommasBeforeMatch = 0;
329       EndOfSequence = i;
330       // If there is a blank line, or if the last line didn't contain any
331       // matching token, the sequence ends here.
332       if (Changes[i].NewlinesBefore > 1 || !FoundMatchOnLine)
333         AlignCurrentSequence();
334
335       FoundMatchOnLine = false;
336     }
337
338     if (Changes[i].Tok->is(tok::comma)) {
339       ++CommasBeforeMatch;
340     } else if (Changes[i].nestingAndIndentLevel() > NestingAndIndentLevel) {
341       // Call AlignTokens recursively, skipping over this scope block.
342       unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i);
343       i = StoppedAt - 1;
344       continue;
345     }
346
347     if (!Matches(Changes[i]))
348       continue;
349
350     // If there is more than one matching token per line, or if the number of
351     // preceding commas, do not match anymore, end the sequence.
352     if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)
353       AlignCurrentSequence();
354
355     CommasBeforeLastMatch = CommasBeforeMatch;
356     FoundMatchOnLine = true;
357
358     if (StartOfSequence == 0)
359       StartOfSequence = i;
360
361     unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
362     int LineLengthAfter = -Changes[i].Spaces;
363     for (unsigned j = i; j != e && Changes[j].NewlinesBefore == 0; ++j)
364       LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
365     unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter;
366
367     // If we are restricted by the maximum column width, end the sequence.
368     if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn ||
369         CommasBeforeLastMatch != CommasBeforeMatch) {
370       AlignCurrentSequence();
371       StartOfSequence = i;
372     }
373
374     MinColumn = std::max(MinColumn, ChangeMinColumn);
375     MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
376   }
377
378   EndOfSequence = i;
379   AlignCurrentSequence();
380   return i;
381 }
382
383 void WhitespaceManager::alignConsecutiveAssignments() {
384   if (!Style.AlignConsecutiveAssignments)
385     return;
386
387   AlignTokens(Style,
388               [&](const Change &C) {
389                 // Do not align on equal signs that are first on a line.
390                 if (C.NewlinesBefore > 0)
391                   return false;
392
393                 // Do not align on equal signs that are last on a line.
394                 if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
395                   return false;
396
397                 return C.Tok->is(tok::equal);
398               },
399               Changes, /*StartAt=*/0);
400 }
401
402 void WhitespaceManager::alignConsecutiveDeclarations() {
403   if (!Style.AlignConsecutiveDeclarations)
404     return;
405
406   // FIXME: Currently we don't handle properly the PointerAlignment: Right
407   // The * and & are not aligned and are left dangling. Something has to be done
408   // about it, but it raises the question of alignment of code like:
409   //   const char* const* v1;
410   //   float const* v2;
411   //   SomeVeryLongType const& v3;
412   AlignTokens(Style,
413               [](Change const &C) {
414                 // tok::kw_operator is necessary for aligning operator overload
415                 // definitions.
416                 return C.Tok->is(TT_StartOfName) ||
417                        C.Tok->is(TT_FunctionDeclarationName) ||
418                        C.Tok->is(tok::kw_operator);
419               },
420               Changes, /*StartAt=*/0);
421 }
422
423 void WhitespaceManager::alignTrailingComments() {
424   unsigned MinColumn = 0;
425   unsigned MaxColumn = UINT_MAX;
426   unsigned StartOfSequence = 0;
427   bool BreakBeforeNext = false;
428   unsigned Newlines = 0;
429   for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
430     if (Changes[i].StartOfBlockComment)
431       continue;
432     Newlines += Changes[i].NewlinesBefore;
433     if (!Changes[i].IsTrailingComment)
434       continue;
435
436     unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
437     unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
438
439     // If we don't create a replacement for this change, we have to consider
440     // it to be immovable.
441     if (!Changes[i].CreateReplacement)
442       ChangeMaxColumn = ChangeMinColumn;
443
444     if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
445       ChangeMaxColumn -= 2;
446     // If this comment follows an } in column 0, it probably documents the
447     // closing of a namespace and we don't want to align it.
448     bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
449                                   Changes[i - 1].Tok->is(tok::r_brace) &&
450                                   Changes[i - 1].StartOfTokenColumn == 0;
451     bool WasAlignedWithStartOfNextLine = false;
452     if (Changes[i].NewlinesBefore == 1) { // A comment on its own line.
453       unsigned CommentColumn = SourceMgr.getSpellingColumnNumber(
454           Changes[i].OriginalWhitespaceRange.getEnd());
455       for (unsigned j = i + 1; j != e; ++j) {
456         if (Changes[j].Tok->is(tok::comment))
457           continue;
458
459         unsigned NextColumn = SourceMgr.getSpellingColumnNumber(
460             Changes[j].OriginalWhitespaceRange.getEnd());
461         // The start of the next token was previously aligned with the
462         // start of this comment.
463         WasAlignedWithStartOfNextLine =
464             CommentColumn == NextColumn ||
465             CommentColumn == NextColumn + Style.IndentWidth;
466         break;
467       }
468     }
469     if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) {
470       alignTrailingComments(StartOfSequence, i, MinColumn);
471       MinColumn = ChangeMinColumn;
472       MaxColumn = ChangeMinColumn;
473       StartOfSequence = i;
474     } else if (BreakBeforeNext || Newlines > 1 ||
475                (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
476                // Break the comment sequence if the previous line did not end
477                // in a trailing comment.
478                (Changes[i].NewlinesBefore == 1 && i > 0 &&
479                 !Changes[i - 1].IsTrailingComment) ||
480                WasAlignedWithStartOfNextLine) {
481       alignTrailingComments(StartOfSequence, i, MinColumn);
482       MinColumn = ChangeMinColumn;
483       MaxColumn = ChangeMaxColumn;
484       StartOfSequence = i;
485     } else {
486       MinColumn = std::max(MinColumn, ChangeMinColumn);
487       MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
488     }
489     BreakBeforeNext =
490         (i == 0) || (Changes[i].NewlinesBefore > 1) ||
491         // Never start a sequence with a comment at the beginning of
492         // the line.
493         (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
494     Newlines = 0;
495   }
496   alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
497 }
498
499 void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
500                                               unsigned Column) {
501   for (unsigned i = Start; i != End; ++i) {
502     int Shift = 0;
503     if (Changes[i].IsTrailingComment) {
504       Shift = Column - Changes[i].StartOfTokenColumn;
505     }
506     if (Changes[i].StartOfBlockComment) {
507       Shift = Changes[i].IndentationOffset +
508               Changes[i].StartOfBlockComment->StartOfTokenColumn -
509               Changes[i].StartOfTokenColumn;
510     }
511     assert(Shift >= 0);
512     Changes[i].Spaces += Shift;
513     if (i + 1 != Changes.size())
514       Changes[i + 1].PreviousEndOfTokenColumn += Shift;
515     Changes[i].StartOfTokenColumn += Shift;
516   }
517 }
518
519 void WhitespaceManager::alignEscapedNewlines() {
520   unsigned MaxEndOfLine =
521       Style.AlignEscapedNewlinesLeft ? 0 : Style.ColumnLimit;
522   unsigned StartOfMacro = 0;
523   for (unsigned i = 1, e = Changes.size(); i < e; ++i) {
524     Change &C = Changes[i];
525     if (C.NewlinesBefore > 0) {
526       if (C.ContinuesPPDirective) {
527         MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine);
528       } else {
529         alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
530         MaxEndOfLine = Style.AlignEscapedNewlinesLeft ? 0 : Style.ColumnLimit;
531         StartOfMacro = i;
532       }
533     }
534   }
535   alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
536 }
537
538 void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End,
539                                              unsigned Column) {
540   for (unsigned i = Start; i < End; ++i) {
541     Change &C = Changes[i];
542     if (C.NewlinesBefore > 0) {
543       assert(C.ContinuesPPDirective);
544       if (C.PreviousEndOfTokenColumn + 1 > Column)
545         C.EscapedNewlineColumn = 0;
546       else
547         C.EscapedNewlineColumn = Column;
548     }
549   }
550 }
551
552 void WhitespaceManager::generateChanges() {
553   for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
554     const Change &C = Changes[i];
555     if (i > 0) {
556       assert(Changes[i - 1].OriginalWhitespaceRange.getBegin() !=
557                  C.OriginalWhitespaceRange.getBegin() &&
558              "Generating two replacements for the same location");
559     }
560     if (C.CreateReplacement) {
561       std::string ReplacementText = C.PreviousLinePostfix;
562       if (C.ContinuesPPDirective)
563         appendNewlineText(ReplacementText, C.NewlinesBefore,
564                           C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
565       else
566         appendNewlineText(ReplacementText, C.NewlinesBefore);
567       appendIndentText(ReplacementText, C.Tok->IndentLevel,
568                        std::max(0, C.Spaces),
569                        C.StartOfTokenColumn - std::max(0, C.Spaces));
570       ReplacementText.append(C.CurrentLinePrefix);
571       storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
572     }
573   }
574 }
575
576 void WhitespaceManager::storeReplacement(SourceRange Range,
577                                          StringRef Text) {
578   unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) -
579                               SourceMgr.getFileOffset(Range.getBegin());
580   // Don't create a replacement, if it does not change anything.
581   if (StringRef(SourceMgr.getCharacterData(Range.getBegin()),
582                 WhitespaceLength) == Text)
583     return;
584   auto Err = Replaces.add(tooling::Replacement(
585       SourceMgr, CharSourceRange::getCharRange(Range), Text));
586   // FIXME: better error handling. For now, just print an error message in the
587   // release version.
588   if (Err) {
589     llvm::errs() << llvm::toString(std::move(Err)) << "\n";
590     assert(false);
591   }
592 }
593
594 void WhitespaceManager::appendNewlineText(std::string &Text,
595                                           unsigned Newlines) {
596   for (unsigned i = 0; i < Newlines; ++i)
597     Text.append(UseCRLF ? "\r\n" : "\n");
598 }
599
600 void WhitespaceManager::appendNewlineText(std::string &Text, unsigned Newlines,
601                                           unsigned PreviousEndOfTokenColumn,
602                                           unsigned EscapedNewlineColumn) {
603   if (Newlines > 0) {
604     unsigned Offset =
605         std::min<int>(EscapedNewlineColumn - 1, PreviousEndOfTokenColumn);
606     for (unsigned i = 0; i < Newlines; ++i) {
607       Text.append(EscapedNewlineColumn - Offset - 1, ' ');
608       Text.append(UseCRLF ? "\\\r\n" : "\\\n");
609       Offset = 0;
610     }
611   }
612 }
613
614 void WhitespaceManager::appendIndentText(std::string &Text,
615                                          unsigned IndentLevel, unsigned Spaces,
616                                          unsigned WhitespaceStartColumn) {
617   switch (Style.UseTab) {
618   case FormatStyle::UT_Never:
619     Text.append(Spaces, ' ');
620     break;
621   case FormatStyle::UT_Always: {
622     unsigned FirstTabWidth =
623         Style.TabWidth - WhitespaceStartColumn % Style.TabWidth;
624     // Indent with tabs only when there's at least one full tab.
625     if (FirstTabWidth + Style.TabWidth <= Spaces) {
626       Spaces -= FirstTabWidth;
627       Text.append("\t");
628     }
629     Text.append(Spaces / Style.TabWidth, '\t');
630     Text.append(Spaces % Style.TabWidth, ' ');
631     break;
632   }
633   case FormatStyle::UT_ForIndentation:
634     if (WhitespaceStartColumn == 0) {
635       unsigned Indentation = IndentLevel * Style.IndentWidth;
636       // This happens, e.g. when a line in a block comment is indented less than
637       // the first one.
638       if (Indentation > Spaces)
639         Indentation = Spaces;
640       unsigned Tabs = Indentation / Style.TabWidth;
641       Text.append(Tabs, '\t');
642       Spaces -= Tabs * Style.TabWidth;
643     }
644     Text.append(Spaces, ' ');
645     break;
646   case FormatStyle::UT_ForContinuationAndIndentation:
647     if (WhitespaceStartColumn == 0) {
648       unsigned Tabs = Spaces / Style.TabWidth;
649       Text.append(Tabs, '\t');
650       Spaces -= Tabs * Style.TabWidth;
651     }
652     Text.append(Spaces, ' ');
653     break;
654   }
655 }
656
657 } // namespace format
658 } // namespace clang