diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp | 334 |
1 files changed, 217 insertions, 117 deletions
diff --git a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp index ddb55c4d853a..3bc6915b8df0 100644 --- a/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp +++ b/contrib/llvm-project/clang/lib/Format/WhitespaceManager.cpp @@ -22,8 +22,13 @@ namespace format { bool WhitespaceManager::Change::IsBeforeInFile::operator()( const Change &C1, const Change &C2) const { return SourceMgr.isBeforeInTranslationUnit( - C1.OriginalWhitespaceRange.getBegin(), - C2.OriginalWhitespaceRange.getBegin()); + C1.OriginalWhitespaceRange.getBegin(), + C2.OriginalWhitespaceRange.getBegin()) || + (C1.OriginalWhitespaceRange.getBegin() == + C2.OriginalWhitespaceRange.getBegin() && + SourceMgr.isBeforeInTranslationUnit( + C1.OriginalWhitespaceRange.getEnd(), + C2.OriginalWhitespaceRange.getEnd())); } WhitespaceManager::Change::Change(const FormatToken &Tok, @@ -302,8 +307,9 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, SmallVector<unsigned, 16> ScopeStack; for (unsigned i = Start; i != End; ++i) { + auto &CurrentChange = Changes[i]; if (ScopeStack.size() != 0 && - Changes[i].indentAndNestingLevel() < + CurrentChange.indentAndNestingLevel() < Changes[ScopeStack.back()].indentAndNestingLevel()) { ScopeStack.pop_back(); } @@ -315,18 +321,18 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, Changes[PreviousNonComment].Tok->is(tok::comment)) { --PreviousNonComment; } - if (i != Start && Changes[i].indentAndNestingLevel() > + if (i != Start && CurrentChange.indentAndNestingLevel() > Changes[PreviousNonComment].indentAndNestingLevel()) { ScopeStack.push_back(i); } bool InsideNestedScope = ScopeStack.size() != 0; bool ContinuedStringLiteral = i > Start && - Changes[i].Tok->is(tok::string_literal) && + CurrentChange.Tok->is(tok::string_literal) && Changes[i - 1].Tok->is(tok::string_literal); bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral; - if (Changes[i].NewlinesBefore > 0 && !SkipMatchCheck) { + if (CurrentChange.NewlinesBefore > 0 && !SkipMatchCheck) { Shift = 0; FoundMatchOnLine = false; } @@ -334,23 +340,26 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, // If this is the first matching token to be aligned, remember by how many // spaces it has to be shifted, so the rest of the changes on the line are // shifted by the same amount - if (!FoundMatchOnLine && !SkipMatchCheck && Matches(Changes[i])) { + if (!FoundMatchOnLine && !SkipMatchCheck && Matches(CurrentChange)) { FoundMatchOnLine = true; - Shift = Column - (RightJustify ? Changes[i].TokenLength : 0) - - Changes[i].StartOfTokenColumn; - Changes[i].Spaces += Shift; + Shift = Column - (RightJustify ? CurrentChange.TokenLength : 0) - + CurrentChange.StartOfTokenColumn; + CurrentChange.Spaces += Shift; // FIXME: This is a workaround that should be removed when we fix // http://llvm.org/PR53699. An assertion later below verifies this. - if (Changes[i].NewlinesBefore == 0) { - Changes[i].Spaces = - std::max(Changes[i].Spaces, - static_cast<int>(Changes[i].Tok->SpacesRequiredBefore)); + if (CurrentChange.NewlinesBefore == 0) { + CurrentChange.Spaces = + std::max(CurrentChange.Spaces, + static_cast<int>(CurrentChange.Tok->SpacesRequiredBefore)); } } + if (Shift == 0) + continue; + // This is for function parameters that are split across multiple lines, // as mentioned in the ScopeStack comment. - if (InsideNestedScope && Changes[i].NewlinesBefore > 0) { + if (InsideNestedScope && CurrentChange.NewlinesBefore > 0) { unsigned ScopeStart = ScopeStack.back(); auto ShouldShiftBeAdded = [&] { // Function declaration @@ -367,35 +376,36 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, return true; } - // Continued function call + // Continued (template) function call. if (ScopeStart > Start + 1 && - Changes[ScopeStart - 2].Tok->is(tok::identifier) && + Changes[ScopeStart - 2].Tok->isOneOf(tok::identifier, + TT_TemplateCloser) && Changes[ScopeStart - 1].Tok->is(tok::l_paren) && Changes[ScopeStart].Tok->isNot(TT_LambdaLSquare)) { - if (Changes[i].Tok->MatchingParen && - Changes[i].Tok->MatchingParen->is(TT_LambdaLBrace)) { + if (CurrentChange.Tok->MatchingParen && + CurrentChange.Tok->MatchingParen->is(TT_LambdaLBrace)) { return false; } if (Changes[ScopeStart].NewlinesBefore > 0) return false; - if (Changes[i].Tok->is(tok::l_brace) && - Changes[i].Tok->is(BK_BracedInit)) { + if (CurrentChange.Tok->is(tok::l_brace) && + CurrentChange.Tok->is(BK_BracedInit)) { return true; } return Style.BinPackArguments; } // Ternary operator - if (Changes[i].Tok->is(TT_ConditionalExpr)) + if (CurrentChange.Tok->is(TT_ConditionalExpr)) return true; // Period Initializer .XXX = 1. - if (Changes[i].Tok->is(TT_DesignatedInitializerPeriod)) + if (CurrentChange.Tok->is(TT_DesignatedInitializerPeriod)) return true; // Continued ternary operator - if (Changes[i].Tok->Previous && - Changes[i].Tok->Previous->is(TT_ConditionalExpr)) { + if (CurrentChange.Tok->Previous && + CurrentChange.Tok->Previous->is(TT_ConditionalExpr)) { return true; } @@ -403,8 +413,8 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, if (ScopeStart > Start + 1 && Changes[ScopeStart - 2].Tok->is(tok::identifier) && Changes[ScopeStart - 1].Tok->is(tok::l_brace) && - Changes[i].Tok->is(tok::l_brace) && - Changes[i].Tok->is(BK_BracedInit)) { + CurrentChange.Tok->is(tok::l_brace) && + CurrentChange.Tok->is(BK_BracedInit)) { return true; } @@ -412,7 +422,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, if (ScopeStart > Start + 1 && Changes[ScopeStart - 2].Tok->isNot(tok::identifier) && Changes[ScopeStart - 1].Tok->is(tok::l_brace) && - Changes[i].Tok->isNot(tok::r_brace)) { + CurrentChange.Tok->isNot(tok::r_brace)) { for (unsigned OuterScopeStart : llvm::reverse(ScopeStack)) { // Lambda. if (OuterScopeStart > Start && @@ -425,30 +435,34 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, return true; } + // Continued template parameter. + if (Changes[ScopeStart - 1].Tok->is(TT_TemplateOpener)) + return true; + return false; }; if (ShouldShiftBeAdded()) - Changes[i].Spaces += Shift; + CurrentChange.Spaces += Shift; } if (ContinuedStringLiteral) - Changes[i].Spaces += Shift; + CurrentChange.Spaces += Shift; // We should not remove required spaces unless we break the line before. - assert(Shift >= 0 || Changes[i].NewlinesBefore > 0 || - Changes[i].Spaces >= + assert(Shift > 0 || Changes[i].NewlinesBefore > 0 || + CurrentChange.Spaces >= static_cast<int>(Changes[i].Tok->SpacesRequiredBefore) || - Changes[i].Tok->is(tok::eof)); + CurrentChange.Tok->is(tok::eof)); - Changes[i].StartOfTokenColumn += Shift; + CurrentChange.StartOfTokenColumn += Shift; if (i + 1 != Changes.size()) Changes[i + 1].PreviousEndOfTokenColumn += Shift; // If PointerAlignment is PAS_Right, keep *s or &s next to the token if ((Style.PointerAlignment == FormatStyle::PAS_Right || Style.ReferenceAlignment == FormatStyle::RAS_Right) && - Changes[i].Spaces != 0) { + CurrentChange.Spaces != 0) { const bool ReferenceNotRightAligned = Style.ReferenceAlignment != FormatStyle::RAS_Right && Style.ReferenceAlignment != FormatStyle::RAS_Pointer; @@ -456,8 +470,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, Previous >= 0 && Changes[Previous].Tok->getType() == TT_PointerOrReference; --Previous) { - assert( - Changes[Previous].Tok->isOneOf(tok::star, tok::amp, tok::ampamp)); + assert(Changes[Previous].Tok->isPointerOrReference()); if (Changes[Previous].Tok->isNot(tok::star)) { if (ReferenceNotRightAligned) continue; @@ -569,16 +582,17 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, unsigned i = StartAt; for (unsigned e = Changes.size(); i != e; ++i) { - if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) + auto &CurrentChange = Changes[i]; + if (CurrentChange.indentAndNestingLevel() < IndentAndNestingLevel) break; - if (Changes[i].NewlinesBefore != 0) { + if (CurrentChange.NewlinesBefore != 0) { CommasBeforeMatch = 0; EndOfSequence = i; // Whether to break the alignment sequence because of an empty line. bool EmptyLineBreak = - (Changes[i].NewlinesBefore > 1) && !ACS.AcrossEmptyLines; + (CurrentChange.NewlinesBefore > 1) && !ACS.AcrossEmptyLines; // Whether to break the alignment sequence because of a line without a // match. @@ -590,19 +604,19 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, // A new line starts, re-initialize line status tracking bools. // Keep the match state if a string literal is continued on this line. - if (i == 0 || !Changes[i].Tok->is(tok::string_literal) || - !Changes[i - 1].Tok->is(tok::string_literal)) { + if (i == 0 || CurrentChange.Tok->isNot(tok::string_literal) || + Changes[i - 1].Tok->isNot(tok::string_literal)) { FoundMatchOnLine = false; } LineIsComment = true; } - if (!Changes[i].Tok->is(tok::comment)) + if (CurrentChange.Tok->isNot(tok::comment)) LineIsComment = false; - if (Changes[i].Tok->is(tok::comma)) { + if (CurrentChange.Tok->is(tok::comma)) { ++CommasBeforeMatch; - } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { + } else if (CurrentChange.indentAndNestingLevel() > IndentAndNestingLevel) { // Call AlignTokens recursively, skipping over this scope block. unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i, ACS, RightJustify); @@ -610,7 +624,7 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, continue; } - if (!Matches(Changes[i])) + if (!Matches(CurrentChange)) continue; // If there is more than one matching token per line, or if the number of @@ -624,16 +638,16 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, if (StartOfSequence == 0) StartOfSequence = i; - unsigned ChangeWidthLeft = Changes[i].StartOfTokenColumn; + unsigned ChangeWidthLeft = CurrentChange.StartOfTokenColumn; unsigned ChangeWidthAnchor = 0; unsigned ChangeWidthRight = 0; if (RightJustify) if (ACS.PadOperators) - ChangeWidthAnchor = Changes[i].TokenLength; + ChangeWidthAnchor = CurrentChange.TokenLength; else - ChangeWidthLeft += Changes[i].TokenLength; + ChangeWidthLeft += CurrentChange.TokenLength; else - ChangeWidthRight = Changes[i].TokenLength; + ChangeWidthRight = CurrentChange.TokenLength; for (unsigned j = i + 1; j != e && Changes[j].NewlinesBefore == 0; ++j) { ChangeWidthRight += Changes[j].Spaces; // Changes are generally 1:1 with the tokens, but a change could also be @@ -731,10 +745,10 @@ void WhitespaceManager::alignConsecutiveMacros() { SpacesRequiredBefore = 0; } - if (!Current || !Current->is(tok::identifier)) + if (!Current || Current->isNot(tok::identifier)) return false; - if (!Current->Previous || !Current->Previous->is(tok::pp_define)) + if (!Current->Previous || Current->Previous->isNot(tok::pp_define)) return false; // For a macro function, 0 spaces are required between the @@ -781,7 +795,7 @@ void WhitespaceManager::alignConsecutiveMacros() { LineIsComment = true; } - if (!Changes[I].Tok->is(tok::comment)) + if (Changes[I].Tok->isNot(tok::comment)) LineIsComment = false; if (!AlignMacrosMatches(Changes[I])) @@ -1033,69 +1047,70 @@ void WhitespaceManager::alignChainedConditionals() { } void WhitespaceManager::alignTrailingComments() { - unsigned MinColumn = 0; - unsigned MaxColumn = UINT_MAX; - unsigned StartOfSequence = 0; + if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Never) + return; + + const int Size = Changes.size(); + int MinColumn = 0; + int StartOfSequence = 0; bool BreakBeforeNext = false; - unsigned Newlines = 0; - unsigned int NewLineThreshold = 1; + int NewLineThreshold = 1; if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Always) NewLineThreshold = Style.AlignTrailingComments.OverEmptyLines + 1; - for (unsigned i = 0, e = Changes.size(); i != e; ++i) { - if (Changes[i].StartOfBlockComment) + for (int I = 0, MaxColumn = INT_MAX, Newlines = 0; I < Size; ++I) { + auto &C = Changes[I]; + if (C.StartOfBlockComment) continue; - Newlines += Changes[i].NewlinesBefore; - if (!Changes[i].IsTrailingComment) + Newlines += C.NewlinesBefore; + if (!C.IsTrailingComment) continue; if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Leave) { - auto OriginalSpaces = - Changes[i].OriginalWhitespaceRange.getEnd().getRawEncoding() - - Changes[i].OriginalWhitespaceRange.getBegin().getRawEncoding() - - Changes[i].Tok->NewlinesBefore; - unsigned RestoredLineLength = Changes[i].StartOfTokenColumn + - Changes[i].TokenLength + OriginalSpaces; + const int OriginalSpaces = + C.OriginalWhitespaceRange.getEnd().getRawEncoding() - + C.OriginalWhitespaceRange.getBegin().getRawEncoding() - + C.Tok->LastNewlineOffset; + assert(OriginalSpaces >= 0); + const auto RestoredLineLength = + C.StartOfTokenColumn + C.TokenLength + OriginalSpaces; // If leaving comments makes the line exceed the column limit, give up to // leave the comments. - if (RestoredLineLength >= Style.ColumnLimit && Style.ColumnLimit != 0) + if (RestoredLineLength >= Style.ColumnLimit && Style.ColumnLimit > 0) break; - Changes[i].Spaces = OriginalSpaces; + C.Spaces = OriginalSpaces; continue; } - unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn; - unsigned ChangeMaxColumn; - - if (Style.ColumnLimit == 0) - ChangeMaxColumn = UINT_MAX; - else if (Style.ColumnLimit >= Changes[i].TokenLength) - ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength; - else - ChangeMaxColumn = ChangeMinColumn; + const int ChangeMinColumn = C.StartOfTokenColumn; + int ChangeMaxColumn; // If we don't create a replacement for this change, we have to consider // it to be immovable. - if (!Changes[i].CreateReplacement) + if (!C.CreateReplacement) + ChangeMaxColumn = ChangeMinColumn; + else if (Style.ColumnLimit == 0) + ChangeMaxColumn = INT_MAX; + else if (Style.ColumnLimit >= C.TokenLength) + ChangeMaxColumn = Style.ColumnLimit - C.TokenLength; + else ChangeMaxColumn = ChangeMinColumn; - if (i + 1 != e && Changes[i + 1].ContinuesPPDirective) + if (I + 1 < Size && Changes[I + 1].ContinuesPPDirective && + ChangeMaxColumn >= 2) { ChangeMaxColumn -= 2; - // If this comment follows an } in column 0, it probably documents the - // closing of a namespace and we don't want to align it. - bool FollowsRBraceInColumn0 = i > 0 && Changes[i].NewlinesBefore == 0 && - Changes[i - 1].Tok->is(tok::r_brace) && - Changes[i - 1].StartOfTokenColumn == 0; + } + bool WasAlignedWithStartOfNextLine = false; - if (Changes[i].NewlinesBefore >= 1) { // A comment on its own line. - unsigned CommentColumn = SourceMgr.getSpellingColumnNumber( - Changes[i].OriginalWhitespaceRange.getEnd()); - for (unsigned j = i + 1; j != e; ++j) { - if (Changes[j].Tok->is(tok::comment)) + if (C.NewlinesBefore >= 1) { // A comment on its own line. + const auto CommentColumn = + SourceMgr.getSpellingColumnNumber(C.OriginalWhitespaceRange.getEnd()); + for (int J = I + 1; J < Size; ++J) { + if (Changes[J].Tok->is(tok::comment)) continue; - unsigned NextColumn = SourceMgr.getSpellingColumnNumber( - Changes[j].OriginalWhitespaceRange.getEnd()); + const auto NextColumn = SourceMgr.getSpellingColumnNumber( + Changes[J].OriginalWhitespaceRange.getEnd()); // The start of the next token was previously aligned with the // start of this comment. WasAlignedWithStartOfNextLine = @@ -1104,34 +1119,71 @@ void WhitespaceManager::alignTrailingComments() { break; } } - if (Style.AlignTrailingComments.Kind == FormatStyle::TCAS_Never || - FollowsRBraceInColumn0) { - alignTrailingComments(StartOfSequence, i, MinColumn); - MinColumn = ChangeMinColumn; - MaxColumn = ChangeMinColumn; - StartOfSequence = i; + + // We don't want to align comments which end a scope, which are here + // identified by most closing braces. + auto DontAlignThisComment = [](const auto *Tok) { + if (Tok->is(tok::semi)) { + Tok = Tok->getPreviousNonComment(); + if (!Tok) + return false; + } + if (Tok->is(tok::r_paren)) { + // Back up past the parentheses and a `TT_DoWhile` that may precede. + Tok = Tok->MatchingParen; + if (!Tok) + return false; + Tok = Tok->getPreviousNonComment(); + if (!Tok) + return false; + if (Tok->is(TT_DoWhile)) { + const auto *Prev = Tok->getPreviousNonComment(); + if (!Prev) { + // A do-while-loop without braces. + return true; + } + Tok = Prev; + } + } + + if (Tok->isNot(tok::r_brace)) + return false; + + while (Tok->Previous && Tok->Previous->is(tok::r_brace)) + Tok = Tok->Previous; + return Tok->NewlinesBefore > 0; + }; + + if (I > 0 && C.NewlinesBefore == 0 && + DontAlignThisComment(Changes[I - 1].Tok)) { + alignTrailingComments(StartOfSequence, I, MinColumn); + // Reset to initial values, but skip this change for the next alignment + // pass. + MinColumn = 0; + MaxColumn = INT_MAX; + StartOfSequence = I + 1; } else if (BreakBeforeNext || Newlines > NewLineThreshold || (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) || // Break the comment sequence if the previous line did not end // in a trailing comment. - (Changes[i].NewlinesBefore == 1 && i > 0 && - !Changes[i - 1].IsTrailingComment) || + (C.NewlinesBefore == 1 && I > 0 && + !Changes[I - 1].IsTrailingComment) || WasAlignedWithStartOfNextLine) { - alignTrailingComments(StartOfSequence, i, MinColumn); + alignTrailingComments(StartOfSequence, I, MinColumn); MinColumn = ChangeMinColumn; MaxColumn = ChangeMaxColumn; - StartOfSequence = i; + StartOfSequence = I; } else { MinColumn = std::max(MinColumn, ChangeMinColumn); MaxColumn = std::min(MaxColumn, ChangeMaxColumn); } - BreakBeforeNext = (i == 0) || (Changes[i].NewlinesBefore > 1) || + BreakBeforeNext = (I == 0) || (C.NewlinesBefore > 1) || // Never start a sequence with a comment at the beginning // of the line. - (Changes[i].NewlinesBefore == 1 && StartOfSequence == i); + (C.NewlinesBefore == 1 && StartOfSequence == I); Newlines = 0; } - alignTrailingComments(StartOfSequence, Changes.size(), MinColumn); + alignTrailingComments(StartOfSequence, Size, MinColumn); } void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End, @@ -1227,6 +1279,7 @@ void WhitespaceManager::alignArrayInitializersRightJustified( if (!CellDescs.isRectangular()) return; + const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1; auto &Cells = CellDescs.Cells; // Now go through and fixup the spaces. auto *CellIter = Cells.begin(); @@ -1244,7 +1297,7 @@ void WhitespaceManager::alignArrayInitializersRightJustified( do { const FormatToken *Previous = Changes[Next->Index].Tok->Previous; if (Previous && Previous->isNot(TT_LineComment)) { - Changes[Next->Index].Spaces = 0; + Changes[Next->Index].Spaces = BracePadding; Changes[Next->Index].NewlinesBefore = 0; } Next = Next->NextColumnElement; @@ -1279,7 +1332,7 @@ void WhitespaceManager::alignArrayInitializersRightJustified( NetWidth; if (Changes[CellIter->Index].NewlinesBefore == 0) { Changes[CellIter->Index].Spaces = (CellWidth - (ThisWidth + NetWidth)); - Changes[CellIter->Index].Spaces += (i > 0) ? 1 : 0; + Changes[CellIter->Index].Spaces += (i > 0) ? 1 : BracePadding; } alignToStartOfCell(CellIter->Index, CellIter->EndIndex); for (const auto *Next = CellIter->NextColumnElement; Next; @@ -1288,7 +1341,7 @@ void WhitespaceManager::alignArrayInitializersRightJustified( calculateCellWidth(Next->Index, Next->EndIndex, true) + NetWidth; if (Changes[Next->Index].NewlinesBefore == 0) { Changes[Next->Index].Spaces = (CellWidth - ThisWidth); - Changes[Next->Index].Spaces += (i > 0) ? 1 : 0; + Changes[Next->Index].Spaces += (i > 0) ? 1 : BracePadding; } alignToStartOfCell(Next->Index, Next->EndIndex); } @@ -1302,12 +1355,13 @@ void WhitespaceManager::alignArrayInitializersLeftJustified( if (!CellDescs.isRectangular()) return; + const int BracePadding = Style.Cpp11BracedListStyle ? 0 : 1; auto &Cells = CellDescs.Cells; // Now go through and fixup the spaces. auto *CellIter = Cells.begin(); // The first cell needs to be against the left brace. if (Changes[CellIter->Index].NewlinesBefore == 0) - Changes[CellIter->Index].Spaces = 0; + Changes[CellIter->Index].Spaces = BracePadding; else Changes[CellIter->Index].Spaces = CellDescs.InitialSpaces; ++CellIter; @@ -1320,7 +1374,8 @@ void WhitespaceManager::alignArrayInitializersLeftJustified( if (Changes[CellIter->Index].NewlinesBefore == 0) { Changes[CellIter->Index].Spaces = MaxNetWidth - ThisNetWidth + - (Changes[CellIter->Index].Tok->isNot(tok::r_brace) ? 1 : 0); + (Changes[CellIter->Index].Tok->isNot(tok::r_brace) ? 1 + : BracePadding); } auto RowCount = 1U; auto Offset = std::distance(Cells.begin(), CellIter); @@ -1334,7 +1389,7 @@ void WhitespaceManager::alignArrayInitializersLeftJustified( if (Changes[Next->Index].NewlinesBefore == 0) { Changes[Next->Index].Spaces = MaxNetWidth - ThisNetWidth + - (Changes[Next->Index].Tok->isNot(tok::r_brace) ? 1 : 0); + (Changes[Next->Index].Tok->isNot(tok::r_brace) ? 1 : BracePadding); } ++RowCount; } @@ -1412,7 +1467,7 @@ WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start, // Account for the added token lengths Changes[j].Spaces = InitialSpaces - InitialTokenLength; } - } else if (C.Tok->is(tok::comment)) { + } else if (C.Tok->is(tok::comment) && C.Tok->NewlinesBefore == 0) { // Trailing comments stay at a space past the last token C.Spaces = Changes[i - 1].Tok->is(tok::comma) ? 1 : 2; } else if (C.Tok->is(tok::l_brace)) { @@ -1512,10 +1567,55 @@ WhitespaceManager::linkCells(CellDescriptions &&CellDesc) { void WhitespaceManager::generateChanges() { for (unsigned i = 0, e = Changes.size(); i != e; ++i) { const Change &C = Changes[i]; - if (i > 0 && Changes[i - 1].OriginalWhitespaceRange.getBegin() == - C.OriginalWhitespaceRange.getBegin()) { - // Do not generate two replacements for the same location. - continue; + if (i > 0) { + auto Last = Changes[i - 1].OriginalWhitespaceRange; + auto New = Changes[i].OriginalWhitespaceRange; + // Do not generate two replacements for the same location. As a special + // case, it is allowed if there is a replacement for the empty range + // between 2 tokens and another non-empty range at the start of the second + // token. We didn't implement logic to combine replacements for 2 + // consecutive source ranges into a single replacement, because the + // program works fine without it. + // + // We can't eliminate empty original whitespace ranges. They appear when + // 2 tokens have no whitespace in between in the input. It does not + // matter whether whitespace is to be added. If no whitespace is to be + // added, the replacement will be empty, and it gets eliminated after this + // step in storeReplacement. For example, if the input is `foo();`, + // there will be a replacement for the range between every consecutive + // pair of tokens. + // + // A replacement at the start of a token can be added by + // BreakableStringLiteralUsingOperators::insertBreak when it adds braces + // around the string literal. Say Verilog code is being formatted and the + // first line is to become the next 2 lines. + // x("long string"); + // x({"long ", + // "string"}); + // There will be a replacement for the empty range between the parenthesis + // and the string and another replacement for the quote character. The + // replacement for the empty range between the parenthesis and the quote + // comes from ContinuationIndenter::addTokenOnCurrentLine when it changes + // the original empty range between the parenthesis and the string to + // another empty one. The replacement for the quote character comes from + // BreakableStringLiteralUsingOperators::insertBreak when it adds the + // brace. In the example, the replacement for the empty range is the same + // as the original text. However, eliminating replacements that are same + // as the original does not help in general. For example, a newline can + // be inserted, causing the first line to become the next 3 lines. + // xxxxxxxxxxx("long string"); + // xxxxxxxxxxx( + // {"long ", + // "string"}); + // In that case, the empty range between the parenthesis and the string + // will be replaced by a newline and 4 spaces. So we will still have to + // deal with a replacement for an empty source range followed by a + // replacement for a non-empty source range. + if (Last.getBegin() == New.getBegin() && + (Last.getEnd() != Last.getBegin() || + New.getEnd() == New.getBegin())) { + continue; + } } if (C.CreateReplacement) { std::string ReplacementText = C.PreviousLinePostfix; |
