diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index d97f56751ea69..e7081aac66c98 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -6486,13 +6486,14 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) const { << "):\n"; const FormatToken *Tok = Line.First; while (Tok) { - llvm::errs() << " M=" << Tok->MustBreakBefore + llvm::errs() << " I=" << Tok->IndentLevel << " M=" << Tok->MustBreakBefore << " C=" << Tok->CanBreakBefore << " T=" << getTokenTypeName(Tok->getType()) << " S=" << Tok->SpacesRequiredBefore << " F=" << Tok->Finalized << " B=" << Tok->BlockParameterCount << " BK=" << Tok->getBlockKind() << " P=" << Tok->SplitPenalty - << " Name=" << Tok->Tok.getName() << " L=" << Tok->TotalLength + << " Name=" << Tok->Tok.getName() << " N=" << Tok->NestingLevel + << " L=" << Tok->TotalLength << " PPK=" << Tok->getPackingKind() << " FakeLParens="; for (prec::Level LParen : Tok->FakeLParens) llvm::errs() << LParen << "/"; diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index cc3cc0f6906cc..30c06bbb4d071 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -279,20 +279,19 @@ void WhitespaceManager::calculateLineBreakInformation() { } // Align a single sequence of tokens, see AlignTokens below. -// Column - The token for which Matches returns true is moved to this column. +// Column - The tokens indexed in Matches are moved to this column. // RightJustify - Whether it is the token's right end or left end that gets // moved to that column. -template static void AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, - unsigned Column, bool RightJustify, F &&Matches, + unsigned Column, bool RightJustify, + ArrayRef Matches, SmallVector &Changes) { - bool FoundMatchOnLine = false; int Shift = 0; // ScopeStack keeps track of the current scope depth. It contains indices of // the first token on each scope. - // We only run the "Matches" function on tokens from the outer-most scope. + // The "Matches" indices should only have tokens from the outer-most scope. // However, we do need to pay special attention to one class of tokens // that are not in the outer-most scope, and that is function parameters // which are split across multiple lines, as illustrated by this example: @@ -314,6 +313,9 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, for (unsigned i = Start; i != End; ++i) { auto &CurrentChange = Changes[i]; + if (!Matches.empty() && Matches[0] < i) + Matches.consume_front(); + assert(Matches.empty() || Matches[0] >= i); if (!ScopeStack.empty() && CurrentChange.indentAndNestingLevel() < Changes[ScopeStack.back()].indentAndNestingLevel()) { @@ -338,26 +340,16 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, Changes[i - 1].Tok->is(tok::string_literal); bool SkipMatchCheck = InsideNestedScope || ContinuedStringLiteral; - if (CurrentChange.NewlinesBefore > 0 && !SkipMatchCheck) { + if (CurrentChange.NewlinesBefore > 0 && !SkipMatchCheck) Shift = 0; - FoundMatchOnLine = false; - } // 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(CurrentChange)) { - FoundMatchOnLine = true; + if (!Matches.empty() && Matches[0] == i) { 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 (CurrentChange.NewlinesBefore == 0) { - CurrentChange.Spaces = - std::max(CurrentChange.Spaces, - static_cast(CurrentChange.Tok->SpacesRequiredBefore)); - } } if (Shift == 0) @@ -532,12 +524,14 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, bool RightJustify = false) { // We arrange each line in 3 parts. The operator to be aligned (the anchor), // and text to its left and right. In the aligned text the width of each part - // will be the maximum of that over the block that has been aligned. Maximum - // widths of each part so far. When RightJustify is true and ACS.PadOperators - // is false, the part from start of line to the right end of the anchor. - // Otherwise, only the part to the left of the anchor. Including the space - // that exists on its left from the start. Not including the padding added on - // the left to right-justify the anchor. + // will be the maximum of that over the block that has been aligned. + + // Maximum widths of each part so far. + // When RightJustify is true and ACS.PadOperators is false, the part from + // start of line to the right end of the anchor. Otherwise, only the part to + // the left of the anchor. Including the space that exists on its left from + // the start. Not including the padding added on the left to right-justify the + // anchor. unsigned WidthLeft = 0; // The operator to be aligned when RightJustify is true and ACS.PadOperators // is false. 0 otherwise. @@ -550,6 +544,9 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, unsigned StartOfSequence = 0; unsigned EndOfSequence = 0; + // The positions of the tokens to be aligned. + SmallVector MatchedIndices; + // Measure the scope level (i.e. depth of (), [], {}) of the first token, and // abort when we hit any token in a higher scope than the starting one. auto IndentAndNestingLevel = StartAt < Changes.size() @@ -578,7 +575,7 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, auto AlignCurrentSequence = [&] { if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) { AlignTokenSequence(Style, StartOfSequence, EndOfSequence, - WidthLeft + WidthAnchor, RightJustify, Matches, + WidthLeft + WidthAnchor, RightJustify, MatchedIndices, Changes); } WidthLeft = 0; @@ -586,6 +583,7 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, WidthRight = 0; StartOfSequence = 0; EndOfSequence = 0; + MatchedIndices.clear(); }; unsigned i = StartAt; @@ -637,8 +635,10 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, // If there is more than one matching token per line, or if the number of // preceding commas, do not match anymore, end the sequence. - if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch) + if (FoundMatchOnLine || CommasBeforeMatch != CommasBeforeLastMatch) { + MatchedIndices.push_back(i); AlignCurrentSequence(); + } CommasBeforeLastMatch = CommasBeforeMatch; FoundMatchOnLine = true; @@ -684,6 +684,7 @@ static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, WidthAnchor = NewAnchor; WidthRight = NewRight; } + MatchedIndices.push_back(i); } EndOfSequence = i; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index d9db06667d802..cd8e67d3a2425 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -20312,6 +20312,11 @@ TEST_F(FormatTest, AlignConsecutiveDeclarations) { " return 2;\n" "} };", BracedAlign); + verifyFormat("const volatile auto result{ []() {\n" + " const auto something = 1;\n" + " return 2;\n" + "} };", + BracedAlign); verifyFormat("int foo{ []() {\n" " int bar{ 0 };\n" " return 0;\n"