16 #include "llvm/ADT/STLExtras.h"
36 : Tok(&Tok), CreateReplacement(CreateReplacement),
37 OriginalWhitespaceRange(OriginalWhitespaceRange),
38 StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
39 PreviousLinePostfix(PreviousLinePostfix),
40 CurrentLinePrefix(CurrentLinePrefix),
41 ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces),
48 unsigned StartOfTokenColumn,
54 Spaces, StartOfTokenColumn, Newlines,
"",
"",
63 Changes.push_back(
Change(Tok,
false,
72 StringRef PreviousPostfix, StringRef CurrentPrefix,
bool InPPDirective,
73 unsigned Newlines,
int Spaces) {
80 std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix,
81 InPPDirective && !Tok.
IsFirst,
true));
89 calculateLineBreakInformation();
90 alignConsecutiveDeclarations();
91 alignConsecutiveAssignments();
92 alignTrailingComments();
93 alignEscapedNewlines();
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) {
104 Changes[i].OriginalWhitespaceRange.getBegin();
106 Changes[i - 1].OriginalWhitespaceRange.getEnd();
107 unsigned OriginalWhitespaceStartOffset =
109 unsigned PreviousOriginalWhitespaceEndOffset =
111 assert(PreviousOriginalWhitespaceEndOffset <=
112 OriginalWhitespaceStartOffset);
113 const char *
const PreviousOriginalWhitespaceEndData =
115 StringRef
Text(PreviousOriginalWhitespaceEndData,
117 PreviousOriginalWhitespaceEndData);
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();
146 Changes[i - 1].TokenLength =
147 NewlinePos + Changes[i - 1].CurrentLinePrefix.size();
152 if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 0)
153 LastOutsideTokenChange->TokenLength +=
154 Changes[i - 1].TokenLength + Changes[i - 1].Spaces;
156 LastOutsideTokenChange = &Changes[i - 1];
158 Changes[i].PreviousEndOfTokenColumn =
159 Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
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) &&
195 OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd;
199 Changes.back().TokenLength = 0;
200 Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment);
202 const WhitespaceManager::Change *LastBlockComment =
nullptr;
203 for (
auto &Change : Changes) {
207 if (Change.IsInsideToken && Change.NewlinesBefore == 0)
208 Change.IsTrailingComment =
false;
209 Change.StartOfBlockComment =
nullptr;
210 Change.IndentationOffset = 0;
211 if (Change.Tok->is(tok::comment)) {
212 if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken)
213 LastBlockComment = &Change;
215 if ((Change.StartOfBlockComment = LastBlockComment))
216 Change.IndentationOffset =
217 Change.StartOfTokenColumn -
218 Change.StartOfBlockComment->StartOfTokenColumn;
221 LastBlockComment =
nullptr;
227 template <
typename F>
231 bool FoundMatchOnLine =
false;
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();
253 if (i != Start && Changes[i].indentAndNestingLevel() >
254 Changes[i - 1].indentAndNestingLevel())
255 ScopeStack.push_back(i);
257 bool InsideNestedScope = ScopeStack.size() != 0;
259 if (Changes[i].NewlinesBefore > 0 && !InsideNestedScope) {
261 FoundMatchOnLine =
false;
267 if (!FoundMatchOnLine && !InsideNestedScope &&
Matches(Changes[i])) {
268 FoundMatchOnLine =
true;
269 Shift = Column - Changes[i].StartOfTokenColumn;
270 Changes[i].Spaces +=
Shift;
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;
284 Changes[i].StartOfTokenColumn +=
Shift;
285 if (i + 1 != Changes.size())
286 Changes[i + 1].PreviousEndOfTokenColumn += Shift;
317 template <
typename F>
321 unsigned MinColumn = 0;
325 unsigned StartOfSequence = 0;
326 unsigned EndOfSequence = 0;
330 auto IndentAndNestingLevel = StartAt < Changes.size()
331 ? Changes[StartAt].indentAndNestingLevel()
332 : std::pair<unsigned, unsigned>(0, 0);
337 unsigned CommasBeforeLastMatch = 0;
338 unsigned CommasBeforeMatch = 0;
341 bool FoundMatchOnLine =
false;
350 auto AlignCurrentSequence = [&] {
351 if (StartOfSequence > 0 && StartOfSequence < EndOfSequence)
360 unsigned i = StartAt;
361 for (
unsigned e = Changes.size(); i != e; ++i) {
362 if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel)
365 if (Changes[i].NewlinesBefore != 0) {
366 CommasBeforeMatch = 0;
370 if (Changes[i].NewlinesBefore > 1 || !FoundMatchOnLine)
371 AlignCurrentSequence();
373 FoundMatchOnLine =
false;
376 if (Changes[i].Tok->is(tok::comma)) {
378 }
else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) {
390 if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch)
391 AlignCurrentSequence();
393 CommasBeforeLastMatch = CommasBeforeMatch;
394 FoundMatchOnLine =
true;
396 if (StartOfSequence == 0)
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;
406 if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn ||
407 CommasBeforeLastMatch != CommasBeforeMatch) {
408 AlignCurrentSequence();
412 MinColumn =
std::max(MinColumn, ChangeMinColumn);
413 MaxColumn =
std::min(MaxColumn, ChangeMaxColumn);
417 AlignCurrentSequence();
421 void WhitespaceManager::alignConsecutiveAssignments() {
426 [&](
const Change &C) {
428 if (C.NewlinesBefore > 0)
432 if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
435 return C.Tok->is(tok::equal);
440 void WhitespaceManager::alignConsecutiveDeclarations() {
451 [](Change
const &C) {
454 return C.Tok->is(TT_StartOfName) ||
455 C.Tok->is(TT_FunctionDeclarationName) ||
456 C.Tok->is(tok::kw_operator);
461 void WhitespaceManager::alignTrailingComments() {
462 unsigned MinColumn = 0;
464 unsigned StartOfSequence = 0;
465 bool BreakBeforeNext =
false;
466 unsigned Newlines = 0;
467 for (
unsigned i = 0, e = Changes.size(); i != e; ++i) {
468 if (Changes[i].StartOfBlockComment)
470 Newlines += Changes[i].NewlinesBefore;
471 if (!Changes[i].IsTrailingComment)
474 unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
475 unsigned ChangeMaxColumn;
479 else if (Style.
ColumnLimit >= Changes[i].TokenLength)
480 ChangeMaxColumn = Style.
ColumnLimit - Changes[i].TokenLength;
482 ChangeMaxColumn = ChangeMinColumn;
486 if (!Changes[i].CreateReplacement)
487 ChangeMaxColumn = ChangeMinColumn;
489 if (i + 1 != e && Changes[i + 1].ContinuesPPDirective)
490 ChangeMaxColumn -= 2;
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) {
499 Changes[i].OriginalWhitespaceRange.getEnd());
500 for (
unsigned j = i + 1; j != e; ++j) {
501 if (Changes[j].Tok->is(tok::comment))
505 Changes[j].OriginalWhitespaceRange.getEnd());
508 WasAlignedWithStartOfNextLine =
509 CommentColumn == NextColumn ||
515 alignTrailingComments(StartOfSequence, i, MinColumn);
516 MinColumn = ChangeMinColumn;
517 MaxColumn = ChangeMinColumn;
519 }
else if (BreakBeforeNext || Newlines > 1 ||
520 (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
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;
531 MinColumn =
std::max(MinColumn, ChangeMinColumn);
532 MaxColumn =
std::min(MaxColumn, ChangeMaxColumn);
535 (i == 0) || (Changes[i].NewlinesBefore > 1) ||
538 (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
541 alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
544 void WhitespaceManager::alignTrailingComments(
unsigned Start,
unsigned End,
546 for (
unsigned i = Start; i !=
End; ++i) {
548 if (Changes[i].IsTrailingComment) {
549 Shift = Column - Changes[i].StartOfTokenColumn;
551 if (Changes[i].StartOfBlockComment) {
552 Shift = Changes[i].IndentationOffset +
553 Changes[i].StartOfBlockComment->StartOfTokenColumn -
554 Changes[i].StartOfTokenColumn;
557 Changes[i].Spaces +=
Shift;
558 if (i + 1 != Changes.size())
559 Changes[i + 1].PreviousEndOfTokenColumn += Shift;
560 Changes[i].StartOfTokenColumn +=
Shift;
564 void WhitespaceManager::alignEscapedNewlines() {
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);
577 alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
583 alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
586 void WhitespaceManager::alignEscapedNewlines(
unsigned Start,
unsigned End,
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;
595 C.EscapedNewlineColumn =
Column;
600 void WhitespaceManager::generateChanges() {
601 for (
unsigned i = 0, e = Changes.size(); i != e; ++i) {
602 const Change &C = Changes[i];
604 assert(Changes[i - 1].OriginalWhitespaceRange.getBegin() !=
605 C.OriginalWhitespaceRange.getBegin() &&
606 "Generating two replacements for the same location");
608 if (C.CreateReplacement) {
609 std::string ReplacementText = C.PreviousLinePostfix;
610 if (C.ContinuesPPDirective)
611 appendNewlineText(ReplacementText, C.NewlinesBefore,
612 C.PreviousEndOfTokenColumn, C.EscapedNewlineColumn);
614 appendNewlineText(ReplacementText, C.NewlinesBefore);
615 appendIndentText(ReplacementText, C.Tok->IndentLevel,
617 C.StartOfTokenColumn -
std::max(0, C.Spaces));
618 ReplacementText.append(C.CurrentLinePrefix);
619 storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
624 void WhitespaceManager::storeReplacement(SourceRange Range,
626 unsigned WhitespaceLength = SourceMgr.
getFileOffset(Range.getEnd()) -
630 WhitespaceLength) ==
Text)
642 void WhitespaceManager::appendNewlineText(std::string &Text,
644 for (
unsigned i = 0; i < Newlines; ++i)
645 Text.append(UseCRLF ?
"\r\n" :
"\n");
648 void WhitespaceManager::appendNewlineText(std::string &Text,
unsigned Newlines,
649 unsigned PreviousEndOfTokenColumn,
650 unsigned EscapedNewlineColumn) {
653 std::min<int>(EscapedNewlineColumn - 2, PreviousEndOfTokenColumn);
654 for (
unsigned i = 0; i < Newlines; ++i) {
655 Text.append(EscapedNewlineColumn - Offset - 1,
' ');
656 Text.append(UseCRLF ?
"\\\r\n" :
"\\\n");
662 void WhitespaceManager::appendIndentText(std::string &Text,
663 unsigned IndentLevel,
unsigned Spaces,
664 unsigned WhitespaceStartColumn) {
667 Text.append(Spaces,
' ');
670 unsigned FirstTabWidth =
673 if (FirstTabWidth + Style.
TabWidth <= Spaces) {
674 Spaces -= FirstTabWidth;
677 Text.append(Spaces / Style.
TabWidth,
'\t');
678 Text.append(Spaces % Style.
TabWidth,
' ');
682 if (WhitespaceStartColumn == 0) {
683 unsigned Indentation = IndentLevel * Style.
IndentWidth;
686 if (Indentation > Spaces)
687 Indentation = Spaces;
688 unsigned Tabs = Indentation / Style.
TabWidth;
689 Text.append(Tabs,
'\t');
692 Text.append(Spaces,
' ');
695 if (WhitespaceStartColumn == 0) {
696 unsigned Tabs = Spaces / Style.
TabWidth;
697 Text.append(Tabs,
'\t');
700 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.
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
SourceLocation getBegin() const
if(T->getSizeExpr()) TRY_TO(TraverseStmt(T-> getSizeExpr()))
std::string toString(const til::SExpr *E)
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.