16 #include "llvm/ADT/STLExtras.h"
34 : CreateReplacement(CreateReplacement),
35 OriginalWhitespaceRange(OriginalWhitespaceRange),
36 StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
37 PreviousLinePostfix(PreviousLinePostfix),
38 CurrentLinePrefix(CurrentLinePrefix), Kind(Kind),
39 ContinuesPPDirective(ContinuesPPDirective),
40 IsStartOfDeclName(IsStartOfDeclName), IndentLevel(IndentLevel),
51 unsigned IndentLevel,
unsigned Spaces,
52 unsigned StartOfTokenColumn,
59 Spaces, StartOfTokenColumn, Newlines,
"",
"", Tok.
Tok.
getKind(),
61 Tok.
is(TT_StartOfName) || Tok.
is(TT_FunctionDeclarationName),
73 Tok.
is(TT_StartOfName) || Tok.
is(TT_FunctionDeclarationName),
79 StringRef PreviousPostfix, StringRef CurrentPrefix,
bool InPPDirective,
80 unsigned Newlines,
unsigned IndentLevel,
int Spaces) {
86 IndentLevel, Spaces,
std::max(0, Spaces), Newlines, PreviousPostfix,
87 CurrentPrefix, Tok.
is(TT_LineComment) ? tok::comment : tok::unknown,
89 Tok.
is(TT_StartOfName) || Tok.
is(TT_FunctionDeclarationName),
98 calculateLineBreakInformation();
99 alignConsecutiveDeclarations();
100 alignConsecutiveAssignments();
101 alignTrailingComments();
102 alignEscapedNewlines();
108 void WhitespaceManager::calculateLineBreakInformation() {
109 Changes[0].PreviousEndOfTokenColumn = 0;
110 Change *LastOutsideTokenChange = &Changes[0];
111 for (
unsigned i = 1, e = Changes.size(); i != e; ++i) {
112 unsigned OriginalWhitespaceStart =
113 SourceMgr.
getFileOffset(Changes[i].OriginalWhitespaceRange.getBegin());
114 unsigned PreviousOriginalWhitespaceEnd = SourceMgr.
getFileOffset(
115 Changes[i - 1].OriginalWhitespaceRange.getEnd());
116 Changes[i - 1].TokenLength = OriginalWhitespaceStart -
117 PreviousOriginalWhitespaceEnd +
118 Changes[i].PreviousLinePostfix.size() +
119 Changes[i - 1].CurrentLinePrefix.size();
123 if (Changes[i - 1].IsInsideToken)
124 LastOutsideTokenChange->TokenLength +=
125 Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
127 LastOutsideTokenChange = &Changes[i - 1];
129 Changes[i].PreviousEndOfTokenColumn =
130 Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
132 Changes[i - 1].IsTrailingComment =
133 (Changes[i].NewlinesBefore > 0 || Changes[i].Kind ==
tok::eof ||
134 (Changes[i].IsInsideToken && Changes[i].Kind == tok::comment)) &&
135 Changes[i - 1].Kind == tok::comment;
139 Changes.back().TokenLength = 0;
140 Changes.back().IsTrailingComment = Changes.back().Kind == tok::comment;
142 const WhitespaceManager::Change *LastBlockComment =
nullptr;
143 for (
auto &Change : Changes) {
146 if (Change.IsInsideToken)
147 Change.IsTrailingComment =
false;
148 Change.StartOfBlockComment =
nullptr;
149 Change.IndentationOffset = 0;
150 if (Change.Kind == tok::comment) {
151 LastBlockComment = &Change;
152 }
else if (Change.Kind == tok::unknown) {
153 if ((Change.StartOfBlockComment = LastBlockComment))
154 Change.IndentationOffset =
155 Change.StartOfTokenColumn -
156 Change.StartOfBlockComment->StartOfTokenColumn;
158 LastBlockComment =
nullptr;
164 template <
typename F>
168 bool FoundMatchOnLine =
false;
170 for (
unsigned i = Start; i !=
End; ++i) {
171 if (Changes[i].NewlinesBefore > 0) {
172 FoundMatchOnLine =
false;
179 if (!FoundMatchOnLine &&
Matches(Changes[i])) {
180 FoundMatchOnLine =
true;
181 Shift = Column - Changes[i].StartOfTokenColumn;
182 Changes[i].Spaces +=
Shift;
186 Changes[i].StartOfTokenColumn +=
Shift;
187 if (i + 1 != Changes.size())
188 Changes[i + 1].PreviousEndOfTokenColumn += Shift;
198 template <
typename F>
201 unsigned MinColumn = 0;
205 unsigned StartOfSequence = 0;
206 unsigned EndOfSequence = 0;
214 unsigned NestingLevelOfLastMatch = 0;
215 unsigned NestingLevel = 0;
220 unsigned CommasBeforeLastMatch = 0;
221 unsigned CommasBeforeMatch = 0;
224 bool FoundMatchOnLine =
false;
233 auto AlignCurrentSequence = [&] {
234 if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
243 for (
unsigned i = 0, e = Changes.size(); i != e; ++i) {
244 if (Changes[i].NewlinesBefore != 0) {
245 CommasBeforeMatch = 0;
249 if (Changes[i].NewlinesBefore > 1 || !FoundMatchOnLine)
250 AlignCurrentSequence();
252 FoundMatchOnLine =
false;
255 if (Changes[i].
Kind == tok::comma) {
257 }
else if (Changes[i].
Kind == tok::r_brace ||
258 Changes[i].
Kind == tok::r_paren ||
259 Changes[i].
Kind == tok::r_square) {
261 }
else if (Changes[i].
Kind == tok::l_brace ||
262 Changes[i].
Kind == tok::l_paren ||
263 Changes[i].
Kind == tok::l_square) {
266 NestingLevelOfLastMatch =
std::min(NestingLevelOfLastMatch, NestingLevel);
276 if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch ||
277 NestingLevel != NestingLevelOfLastMatch)
278 AlignCurrentSequence();
280 CommasBeforeLastMatch = CommasBeforeMatch;
281 NestingLevelOfLastMatch = NestingLevel;
282 FoundMatchOnLine =
true;
284 if (StartOfSequence == 0)
287 unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
288 int LineLengthAfter = -Changes[i].Spaces;
289 for (
unsigned j = i; j != e && Changes[j].NewlinesBefore == 0; ++j)
290 LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength;
291 unsigned ChangeMaxColumn = Style.
ColumnLimit - LineLengthAfter;
294 if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn ||
295 CommasBeforeLastMatch != CommasBeforeMatch) {
296 AlignCurrentSequence();
300 MinColumn =
std::max(MinColumn, ChangeMinColumn);
301 MaxColumn =
std::min(MaxColumn, ChangeMaxColumn);
304 EndOfSequence = Changes.size();
305 AlignCurrentSequence();
308 void WhitespaceManager::alignConsecutiveAssignments() {
313 [&](
const Change &C) {
315 if (C.NewlinesBefore > 0)
319 if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
322 return C.Kind == tok::equal;
327 void WhitespaceManager::alignConsecutiveDeclarations() {
338 AlignTokens(Style, [](Change
const &C) {
return C.IsStartOfDeclName; },
342 void WhitespaceManager::alignTrailingComments() {
343 unsigned MinColumn = 0;
345 unsigned StartOfSequence = 0;
346 bool BreakBeforeNext =
false;
347 unsigned Newlines = 0;
348 for (
unsigned i = 0, e = Changes.size(); i != e; ++i) {
349 if (Changes[i].StartOfBlockComment)
351 Newlines += Changes[i].NewlinesBefore;
352 if (!Changes[i].IsTrailingComment)
355 unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
356 unsigned ChangeMaxColumn = Style.
ColumnLimit - Changes[i].TokenLength;
360 if (!Changes[i].CreateReplacement)
361 ChangeMaxColumn = ChangeMinColumn;
363 if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
364 ChangeMaxColumn -= 2;
367 bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 &&
368 Changes[i - 1].Kind == tok::r_brace &&
369 Changes[i - 1].StartOfTokenColumn == 0;
370 bool WasAlignedWithStartOfNextLine =
false;
371 if (Changes[i].NewlinesBefore == 1) {
373 Changes[i].OriginalWhitespaceRange.getEnd());
374 for (
unsigned j = i + 1; j != e; ++j) {
375 if (Changes[j].
Kind == tok::comment ||
376 Changes[j].
Kind == tok::unknown)
382 Changes[j].OriginalWhitespaceRange.getEnd());
385 WasAlignedWithStartOfNextLine =
386 CommentColumn == NextColumn ||
392 alignTrailingComments(StartOfSequence, i, MinColumn);
393 MinColumn = ChangeMinColumn;
394 MaxColumn = ChangeMinColumn;
396 }
else if (BreakBeforeNext || Newlines > 1 ||
397 (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
400 (Changes[i].NewlinesBefore == 1 && i > 0 &&
401 !Changes[i - 1].IsTrailingComment) ||
402 WasAlignedWithStartOfNextLine) {
403 alignTrailingComments(StartOfSequence, i, MinColumn);
404 MinColumn = ChangeMinColumn;
405 MaxColumn = ChangeMaxColumn;
408 MinColumn =
std::max(MinColumn, ChangeMinColumn);
409 MaxColumn =
std::min(MaxColumn, ChangeMaxColumn);
412 (i == 0) || (Changes[i].NewlinesBefore > 1) ||
415 (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
418 alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
421 void WhitespaceManager::alignTrailingComments(
unsigned Start,
unsigned End,
423 for (
unsigned i = Start; i !=
End; ++i) {
425 if (Changes[i].IsTrailingComment) {
426 Shift = Column - Changes[i].StartOfTokenColumn;
428 if (Changes[i].StartOfBlockComment) {
429 Shift = Changes[i].IndentationOffset +
430 Changes[i].StartOfBlockComment->StartOfTokenColumn -
431 Changes[i].StartOfTokenColumn;
434 Changes[i].Spaces +=
Shift;
436 Changes[i + 1].PreviousEndOfTokenColumn +=
Shift;
437 Changes[i].StartOfTokenColumn +=
Shift;
441 void WhitespaceManager::alignEscapedNewlines() {
442 unsigned MaxEndOfLine =
444 unsigned StartOfMacro = 0;
445 for (
unsigned i = 1, e = Changes.size(); i < e; ++i) {
446 Change &C = Changes[i];
447 if (C.NewlinesBefore > 0) {
448 if (C.ContinuesPPDirective) {
449 MaxEndOfLine =
std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine);
451 alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
457 alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
460 void WhitespaceManager::alignEscapedNewlines(
unsigned Start,
unsigned End,
462 for (
unsigned i = Start; i <
End; ++i) {
463 Change &C = Changes[i];
464 if (C.NewlinesBefore > 0) {
465 assert(C.ContinuesPPDirective);
466 if (C.PreviousEndOfTokenColumn + 1 > Column)
467 C.EscapedNewlineColumn = 0;
469 C.EscapedNewlineColumn = Column;
474 void WhitespaceManager::generateChanges() {
475 for (
unsigned i = 0, e = Changes.size(); i != e; ++i) {
476 const Change &C = Changes[i];
478 assert(Changes[i - 1].OriginalWhitespaceRange.getBegin() !=
479 C.OriginalWhitespaceRange.getBegin() &&
480 "Generating two replacements for the same location");
482 if (C.CreateReplacement) {
483 std::string ReplacementText = C.PreviousLinePostfix;
484 if (C.ContinuesPPDirective)
485 appendNewlineText(ReplacementText, C.NewlinesBefore,
486 C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
488 appendNewlineText(ReplacementText, C.NewlinesBefore);
489 appendIndentText(ReplacementText, C.IndentLevel,
std::max(0, C.Spaces),
490 C.StartOfTokenColumn -
std::max(0, C.Spaces));
491 ReplacementText.append(C.CurrentLinePrefix);
492 storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
497 void WhitespaceManager::storeReplacement(SourceRange Range,
499 unsigned WhitespaceLength = SourceMgr.
getFileOffset(Range.getEnd()) -
503 WhitespaceLength) ==
Text)
509 void WhitespaceManager::appendNewlineText(std::string &Text,
511 for (
unsigned i = 0; i < Newlines; ++i)
512 Text.append(UseCRLF ?
"\r\n" :
"\n");
515 void WhitespaceManager::appendNewlineText(std::string &Text,
unsigned Newlines,
516 unsigned PreviousEndOfTokenColumn,
517 unsigned EscapedNewlineColumn) {
520 std::min<int>(EscapedNewlineColumn - 1, PreviousEndOfTokenColumn);
521 for (
unsigned i = 0; i < Newlines; ++i) {
522 Text.append(EscapedNewlineColumn - Offset - 1,
' ');
523 Text.append(UseCRLF ?
"\\\r\n" :
"\\\n");
529 void WhitespaceManager::appendIndentText(std::string &Text,
530 unsigned IndentLevel,
unsigned Spaces,
531 unsigned WhitespaceStartColumn) {
534 Text.append(Spaces,
' ');
537 unsigned FirstTabWidth =
540 if (FirstTabWidth + Style.
TabWidth <= Spaces) {
541 Spaces -= FirstTabWidth;
544 Text.append(Spaces / Style.
TabWidth,
'\t');
545 Text.append(Spaces % Style.
TabWidth,
' ');
549 if (WhitespaceStartColumn == 0) {
550 unsigned Indentation = IndentLevel * Style.
IndentWidth;
553 if (Indentation > Spaces)
554 Indentation = Spaces;
555 unsigned Tabs = Indentation / Style.
TabWidth;
556 Text.append(Tabs,
'\t');
559 Text.append(Spaces,
' ');
562 if (WhitespaceStartColumn == 0) {
563 unsigned Tabs = Spaces / Style.
TabWidth;
564 Text.append(Tabs,
'\t');
567 Text.append(Spaces,
' ');
const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const
Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer...
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
tok::TokenKind getKind() const
WhitespaceManager class manages whitespace around tokens and their replacements.
bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const
Determines the order of 2 source locations in the translation unit.
char __ovld __cnfn min(char x, char y)
Returns y if y < x, otherwise it returns x.
static CharSourceRange getCharRange(SourceRange R)
Encodes a location in the source.
unsigned getSpellingColumnNumber(SourceLocation Loc, bool *Invalid=nullptr) const
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
SourceLocation getBegin() const
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T-> getSizeExpr()))
char __ovld __cnfn max(char x, char y)
Returns y if x < y, otherwise it returns x.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
A trivial tuple used to represent a source range.