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