diff options
| author | 2020-08-03 15:06:44 +0000 | |
|---|---|---|
| committer | 2020-08-03 15:06:44 +0000 | |
| commit | b64793999546ed8adebaeebd9d8345d18db8927d (patch) | |
| tree | 4357c27b561d73b0e089727c6ed659f2ceff5f47 /gnu/llvm/tools/clang/lib/Format/WhitespaceManager.cpp | |
| parent | Add support for UTF-8 DISPLAY-HINTs with octet length. For now only (diff) | |
| download | wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.tar.xz wireguard-openbsd-b64793999546ed8adebaeebd9d8345d18db8927d.zip | |
Remove LLVM 8.0.1 files.
Diffstat (limited to 'gnu/llvm/tools/clang/lib/Format/WhitespaceManager.cpp')
| -rw-r--r-- | gnu/llvm/tools/clang/lib/Format/WhitespaceManager.cpp | 717 |
1 files changed, 0 insertions, 717 deletions
diff --git a/gnu/llvm/tools/clang/lib/Format/WhitespaceManager.cpp b/gnu/llvm/tools/clang/lib/Format/WhitespaceManager.cpp deleted file mode 100644 index 032b1333322..00000000000 --- a/gnu/llvm/tools/clang/lib/Format/WhitespaceManager.cpp +++ /dev/null @@ -1,717 +0,0 @@ -//===--- WhitespaceManager.cpp - Format C++ code --------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file implements WhitespaceManager class. -/// -//===----------------------------------------------------------------------===// - -#include "WhitespaceManager.h" -#include "llvm/ADT/STLExtras.h" - -namespace clang { -namespace format { - -bool WhitespaceManager::Change::IsBeforeInFile:: -operator()(const Change &C1, const Change &C2) const { - return SourceMgr.isBeforeInTranslationUnit( - C1.OriginalWhitespaceRange.getBegin(), - C2.OriginalWhitespaceRange.getBegin()); -} - -WhitespaceManager::Change::Change(const FormatToken &Tok, - bool CreateReplacement, - SourceRange OriginalWhitespaceRange, - int Spaces, unsigned StartOfTokenColumn, - unsigned NewlinesBefore, - StringRef PreviousLinePostfix, - StringRef CurrentLinePrefix, - bool ContinuesPPDirective, bool IsInsideToken) - : Tok(&Tok), CreateReplacement(CreateReplacement), - OriginalWhitespaceRange(OriginalWhitespaceRange), - StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore), - PreviousLinePostfix(PreviousLinePostfix), - CurrentLinePrefix(CurrentLinePrefix), - ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces), - IsInsideToken(IsInsideToken), IsTrailingComment(false), TokenLength(0), - PreviousEndOfTokenColumn(0), EscapedNewlineColumn(0), - StartOfBlockComment(nullptr), IndentationOffset(0) {} - -void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines, - unsigned Spaces, - unsigned StartOfTokenColumn, - bool InPPDirective) { - if (Tok.Finalized) - return; - Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue; - Changes.push_back(Change(Tok, /*CreateReplacement=*/true, Tok.WhitespaceRange, - Spaces, StartOfTokenColumn, Newlines, "", "", - InPPDirective && !Tok.IsFirst, - /*IsInsideToken=*/false)); -} - -void WhitespaceManager::addUntouchableToken(const FormatToken &Tok, - bool InPPDirective) { - if (Tok.Finalized) - return; - Changes.push_back(Change(Tok, /*CreateReplacement=*/false, - Tok.WhitespaceRange, /*Spaces=*/0, - Tok.OriginalColumn, Tok.NewlinesBefore, "", "", - InPPDirective && !Tok.IsFirst, - /*IsInsideToken=*/false)); -} - -llvm::Error -WhitespaceManager::addReplacement(const tooling::Replacement &Replacement) { - return Replaces.add(Replacement); -} - -void WhitespaceManager::replaceWhitespaceInToken( - const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, - StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, - unsigned Newlines, int Spaces) { - if (Tok.Finalized) - return; - SourceLocation Start = Tok.getStartOfNonWhitespace().getLocWithOffset(Offset); - Changes.push_back( - Change(Tok, /*CreateReplacement=*/true, - SourceRange(Start, Start.getLocWithOffset(ReplaceChars)), Spaces, - std::max(0, Spaces), Newlines, PreviousPostfix, CurrentPrefix, - InPPDirective && !Tok.IsFirst, /*IsInsideToken=*/true)); -} - -const tooling::Replacements &WhitespaceManager::generateReplacements() { - if (Changes.empty()) - return Replaces; - - llvm::sort(Changes, Change::IsBeforeInFile(SourceMgr)); - calculateLineBreakInformation(); - alignConsecutiveDeclarations(); - alignConsecutiveAssignments(); - alignTrailingComments(); - alignEscapedNewlines(); - generateChanges(); - - return Replaces; -} - -void WhitespaceManager::calculateLineBreakInformation() { - Changes[0].PreviousEndOfTokenColumn = 0; - Change *LastOutsideTokenChange = &Changes[0]; - for (unsigned i = 1, e = Changes.size(); i != e; ++i) { - SourceLocation OriginalWhitespaceStart = - Changes[i].OriginalWhitespaceRange.getBegin(); - SourceLocation PreviousOriginalWhitespaceEnd = - Changes[i - 1].OriginalWhitespaceRange.getEnd(); - unsigned OriginalWhitespaceStartOffset = - SourceMgr.getFileOffset(OriginalWhitespaceStart); - unsigned PreviousOriginalWhitespaceEndOffset = - SourceMgr.getFileOffset(PreviousOriginalWhitespaceEnd); - assert(PreviousOriginalWhitespaceEndOffset <= - OriginalWhitespaceStartOffset); - const char *const PreviousOriginalWhitespaceEndData = - SourceMgr.getCharacterData(PreviousOriginalWhitespaceEnd); - StringRef Text(PreviousOriginalWhitespaceEndData, - SourceMgr.getCharacterData(OriginalWhitespaceStart) - - PreviousOriginalWhitespaceEndData); - // Usually consecutive changes would occur in consecutive tokens. This is - // not the case however when analyzing some preprocessor runs of the - // annotated lines. For example, in this code: - // - // #if A // line 1 - // int i = 1; - // #else B // line 2 - // int i = 2; - // #endif // line 3 - // - // one of the runs will produce the sequence of lines marked with line 1, 2 - // and 3. So the two consecutive whitespace changes just before '// line 2' - // and before '#endif // line 3' span multiple lines and tokens: - // - // #else B{change X}[// line 2 - // int i = 2; - // ]{change Y}#endif // line 3 - // - // For this reason, if the text between consecutive changes spans multiple - // newlines, the token length must be adjusted to the end of the original - // line of the token. - auto NewlinePos = Text.find_first_of('\n'); - if (NewlinePos == StringRef::npos) { - Changes[i - 1].TokenLength = OriginalWhitespaceStartOffset - - PreviousOriginalWhitespaceEndOffset + - Changes[i].PreviousLinePostfix.size() + - Changes[i - 1].CurrentLinePrefix.size(); - } else { - Changes[i - 1].TokenLength = - NewlinePos + Changes[i - 1].CurrentLinePrefix.size(); - } - - // If there are multiple changes in this token, sum up all the changes until - // the end of the line. - if (Changes[i - 1].IsInsideToken && Changes[i - 1].NewlinesBefore == 0) - LastOutsideTokenChange->TokenLength += - Changes[i - 1].TokenLength + Changes[i - 1].Spaces; - else - LastOutsideTokenChange = &Changes[i - 1]; - - Changes[i].PreviousEndOfTokenColumn = - Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength; - - Changes[i - 1].IsTrailingComment = - (Changes[i].NewlinesBefore > 0 || Changes[i].Tok->is(tok::eof) || - (Changes[i].IsInsideToken && Changes[i].Tok->is(tok::comment))) && - Changes[i - 1].Tok->is(tok::comment) && - // FIXME: This is a dirty hack. The problem is that - // BreakableLineCommentSection does comment reflow changes and here is - // the aligning of trailing comments. Consider the case where we reflow - // the second line up in this example: - // - // // line 1 - // // line 2 - // - // That amounts to 2 changes by BreakableLineCommentSection: - // - the first, delimited by (), for the whitespace between the tokens, - // - and second, delimited by [], for the whitespace at the beginning - // of the second token: - // - // // line 1( - // )[// ]line 2 - // - // So in the end we have two changes like this: - // - // // line1()[ ]line 2 - // - // Note that the OriginalWhitespaceStart of the second change is the - // same as the PreviousOriginalWhitespaceEnd of the first change. - // In this case, the below check ensures that the second change doesn't - // get treated as a trailing comment change here, since this might - // trigger additional whitespace to be wrongly inserted before "line 2" - // by the comment aligner here. - // - // For a proper solution we need a mechanism to say to WhitespaceManager - // that a particular change breaks the current sequence of trailing - // comments. - OriginalWhitespaceStart != PreviousOriginalWhitespaceEnd; - } - // FIXME: The last token is currently not always an eof token; in those - // cases, setting TokenLength of the last token to 0 is wrong. - Changes.back().TokenLength = 0; - Changes.back().IsTrailingComment = Changes.back().Tok->is(tok::comment); - - const WhitespaceManager::Change *LastBlockComment = nullptr; - for (auto &Change : Changes) { - // Reset the IsTrailingComment flag for changes inside of trailing comments - // so they don't get realigned later. Comment line breaks however still need - // to be aligned. - if (Change.IsInsideToken && Change.NewlinesBefore == 0) - Change.IsTrailingComment = false; - Change.StartOfBlockComment = nullptr; - Change.IndentationOffset = 0; - if (Change.Tok->is(tok::comment)) { - if (Change.Tok->is(TT_LineComment) || !Change.IsInsideToken) - LastBlockComment = &Change; - else { - if ((Change.StartOfBlockComment = LastBlockComment)) - Change.IndentationOffset = - Change.StartOfTokenColumn - - Change.StartOfBlockComment->StartOfTokenColumn; - } - } else { - LastBlockComment = nullptr; - } - } -} - -// Align a single sequence of tokens, see AlignTokens below. -template <typename F> -static void -AlignTokenSequence(unsigned Start, unsigned End, unsigned Column, F &&Matches, - SmallVector<WhitespaceManager::Change, 16> &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. - // 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: - // double a(int x); - // int b(int y, - // double z); - // In the above example, we need to take special care to ensure that - // 'double z' is indented along with it's owning function 'b'. - SmallVector<unsigned, 16> ScopeStack; - - for (unsigned i = Start; i != End; ++i) { - if (ScopeStack.size() != 0 && - Changes[i].indentAndNestingLevel() < - Changes[ScopeStack.back()].indentAndNestingLevel()) - ScopeStack.pop_back(); - - // Compare current token to previous non-comment token to ensure whether - // it is in a deeper scope or not. - unsigned PreviousNonComment = i - 1; - while (PreviousNonComment > Start && - Changes[PreviousNonComment].Tok->is(tok::comment)) - PreviousNonComment--; - if (i != Start && Changes[i].indentAndNestingLevel() > - Changes[PreviousNonComment].indentAndNestingLevel()) - ScopeStack.push_back(i); - - bool InsideNestedScope = ScopeStack.size() != 0; - - if (Changes[i].NewlinesBefore > 0 && !InsideNestedScope) { - 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 && !InsideNestedScope && Matches(Changes[i])) { - FoundMatchOnLine = true; - Shift = Column - Changes[i].StartOfTokenColumn; - Changes[i].Spaces += Shift; - } - - // This is for function parameters that are split across multiple lines, - // as mentioned in the ScopeStack comment. - if (InsideNestedScope && Changes[i].NewlinesBefore > 0) { - unsigned ScopeStart = ScopeStack.back(); - if (Changes[ScopeStart - 1].Tok->is(TT_FunctionDeclarationName) || - (ScopeStart > Start + 1 && - Changes[ScopeStart - 2].Tok->is(TT_FunctionDeclarationName))) - Changes[i].Spaces += Shift; - } - - assert(Shift >= 0); - Changes[i].StartOfTokenColumn += Shift; - if (i + 1 != Changes.size()) - Changes[i + 1].PreviousEndOfTokenColumn += Shift; - } -} - -// Walk through a subset of the changes, starting at StartAt, and find -// sequences of matching tokens to align. To do so, keep track of the lines and -// whether or not a matching token was found on a line. If a matching token is -// found, extend the current sequence. If the current line cannot be part of a -// sequence, e.g. because there is an empty line before it or it contains only -// non-matching tokens, finalize the previous sequence. -// The value returned is the token on which we stopped, either because we -// exhausted all items inside Changes, or because we hit a scope level higher -// than our initial scope. -// This function is recursive. Each invocation processes only the scope level -// equal to the initial level, which is the level of Changes[StartAt]. -// If we encounter a scope level greater than the initial level, then we call -// ourselves recursively, thereby avoiding the pollution of the current state -// with the alignment requirements of the nested sub-level. This recursive -// behavior is necessary for aligning function prototypes that have one or more -// arguments. -// If this function encounters a scope level less than the initial level, -// it returns the current position. -// There is a non-obvious subtlety in the recursive behavior: Even though we -// defer processing of nested levels to recursive invocations of this -// function, when it comes time to align a sequence of tokens, we run the -// alignment on the entire sequence, including the nested levels. -// When doing so, most of the nested tokens are skipped, because their -// alignment was already handled by the recursive invocations of this function. -// However, the special exception is that we do NOT skip function parameters -// that are split across multiple lines. See the test case in FormatTest.cpp -// that mentions "split function parameter alignment" for an example of this. -template <typename F> -static unsigned AlignTokens(const FormatStyle &Style, F &&Matches, - SmallVector<WhitespaceManager::Change, 16> &Changes, - unsigned StartAt) { - unsigned MinColumn = 0; - unsigned MaxColumn = UINT_MAX; - - // Line number of the start and the end of the current token sequence. - unsigned StartOfSequence = 0; - unsigned EndOfSequence = 0; - - // 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() - ? Changes[StartAt].indentAndNestingLevel() - : std::pair<unsigned, unsigned>(0, 0); - - // Keep track of the number of commas before the matching tokens, we will only - // align a sequence of matching tokens if they are preceded by the same number - // of commas. - unsigned CommasBeforeLastMatch = 0; - unsigned CommasBeforeMatch = 0; - - // Whether a matching token has been found on the current line. - bool FoundMatchOnLine = false; - - // Aligns a sequence of matching tokens, on the MinColumn column. - // - // Sequences start from the first matching token to align, and end at the - // first token of the first line that doesn't need to be aligned. - // - // We need to adjust the StartOfTokenColumn of each Change that is on a line - // containing any matching token to be aligned and located after such token. - auto AlignCurrentSequence = [&] { - if (StartOfSequence > 0 && StartOfSequence < EndOfSequence) - AlignTokenSequence(StartOfSequence, EndOfSequence, MinColumn, Matches, - Changes); - MinColumn = 0; - MaxColumn = UINT_MAX; - StartOfSequence = 0; - EndOfSequence = 0; - }; - - unsigned i = StartAt; - for (unsigned e = Changes.size(); i != e; ++i) { - if (Changes[i].indentAndNestingLevel() < IndentAndNestingLevel) - break; - - if (Changes[i].NewlinesBefore != 0) { - CommasBeforeMatch = 0; - EndOfSequence = i; - // If there is a blank line, or if the last line didn't contain any - // matching token, the sequence ends here. - if (Changes[i].NewlinesBefore > 1 || !FoundMatchOnLine) - AlignCurrentSequence(); - - FoundMatchOnLine = false; - } - - if (Changes[i].Tok->is(tok::comma)) { - ++CommasBeforeMatch; - } else if (Changes[i].indentAndNestingLevel() > IndentAndNestingLevel) { - // Call AlignTokens recursively, skipping over this scope block. - unsigned StoppedAt = AlignTokens(Style, Matches, Changes, i); - i = StoppedAt - 1; - continue; - } - - if (!Matches(Changes[i])) - continue; - - // 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) - AlignCurrentSequence(); - - CommasBeforeLastMatch = CommasBeforeMatch; - FoundMatchOnLine = true; - - if (StartOfSequence == 0) - StartOfSequence = i; - - unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn; - int LineLengthAfter = -Changes[i].Spaces; - for (unsigned j = i; j != e && Changes[j].NewlinesBefore == 0; ++j) - LineLengthAfter += Changes[j].Spaces + Changes[j].TokenLength; - unsigned ChangeMaxColumn = Style.ColumnLimit - LineLengthAfter; - - // If we are restricted by the maximum column width, end the sequence. - if (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn || - CommasBeforeLastMatch != CommasBeforeMatch) { - AlignCurrentSequence(); - StartOfSequence = i; - } - - MinColumn = std::max(MinColumn, ChangeMinColumn); - MaxColumn = std::min(MaxColumn, ChangeMaxColumn); - } - - EndOfSequence = i; - AlignCurrentSequence(); - return i; -} - -void WhitespaceManager::alignConsecutiveAssignments() { - if (!Style.AlignConsecutiveAssignments) - return; - - AlignTokens(Style, - [&](const Change &C) { - // Do not align on equal signs that are first on a line. - if (C.NewlinesBefore > 0) - return false; - - // Do not align on equal signs that are last on a line. - if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0) - return false; - - return C.Tok->is(tok::equal); - }, - Changes, /*StartAt=*/0); -} - -void WhitespaceManager::alignConsecutiveDeclarations() { - if (!Style.AlignConsecutiveDeclarations) - return; - - // FIXME: Currently we don't handle properly the PointerAlignment: Right - // The * and & are not aligned and are left dangling. Something has to be done - // about it, but it raises the question of alignment of code like: - // const char* const* v1; - // float const* v2; - // SomeVeryLongType const& v3; - AlignTokens(Style, - [](Change const &C) { - // tok::kw_operator is necessary for aligning operator overload - // definitions. - return C.Tok->is(TT_StartOfName) || - C.Tok->is(TT_FunctionDeclarationName) || - C.Tok->is(tok::kw_operator); - }, - Changes, /*StartAt=*/0); -} - -void WhitespaceManager::alignTrailingComments() { - unsigned MinColumn = 0; - unsigned MaxColumn = UINT_MAX; - unsigned StartOfSequence = 0; - bool BreakBeforeNext = false; - unsigned Newlines = 0; - for (unsigned i = 0, e = Changes.size(); i != e; ++i) { - if (Changes[i].StartOfBlockComment) - continue; - Newlines += Changes[i].NewlinesBefore; - if (!Changes[i].IsTrailingComment) - 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; - - // If we don't create a replacement for this change, we have to consider - // it to be immovable. - if (!Changes[i].CreateReplacement) - ChangeMaxColumn = ChangeMinColumn; - - if (i + 1 != e && Changes[i + 1].ContinuesPPDirective) - 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)) - continue; - - unsigned NextColumn = SourceMgr.getSpellingColumnNumber( - Changes[j].OriginalWhitespaceRange.getEnd()); - // The start of the next token was previously aligned with the - // start of this comment. - WasAlignedWithStartOfNextLine = - CommentColumn == NextColumn || - CommentColumn == NextColumn + Style.IndentWidth; - break; - } - } - if (!Style.AlignTrailingComments || FollowsRBraceInColumn0) { - alignTrailingComments(StartOfSequence, i, MinColumn); - MinColumn = ChangeMinColumn; - MaxColumn = ChangeMinColumn; - StartOfSequence = i; - } else if (BreakBeforeNext || Newlines > 1 || - (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) || - WasAlignedWithStartOfNextLine) { - alignTrailingComments(StartOfSequence, i, MinColumn); - MinColumn = ChangeMinColumn; - MaxColumn = ChangeMaxColumn; - StartOfSequence = i; - } else { - MinColumn = std::max(MinColumn, ChangeMinColumn); - MaxColumn = std::min(MaxColumn, ChangeMaxColumn); - } - BreakBeforeNext = - (i == 0) || (Changes[i].NewlinesBefore > 1) || - // Never start a sequence with a comment at the beginning of - // the line. - (Changes[i].NewlinesBefore == 1 && StartOfSequence == i); - Newlines = 0; - } - alignTrailingComments(StartOfSequence, Changes.size(), MinColumn); -} - -void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End, - unsigned Column) { - for (unsigned i = Start; i != End; ++i) { - int Shift = 0; - if (Changes[i].IsTrailingComment) { - Shift = Column - Changes[i].StartOfTokenColumn; - } - if (Changes[i].StartOfBlockComment) { - Shift = Changes[i].IndentationOffset + - Changes[i].StartOfBlockComment->StartOfTokenColumn - - Changes[i].StartOfTokenColumn; - } - assert(Shift >= 0); - Changes[i].Spaces += Shift; - if (i + 1 != Changes.size()) - Changes[i + 1].PreviousEndOfTokenColumn += Shift; - Changes[i].StartOfTokenColumn += Shift; - } -} - -void WhitespaceManager::alignEscapedNewlines() { - if (Style.AlignEscapedNewlines == FormatStyle::ENAS_DontAlign) - return; - - bool AlignLeft = Style.AlignEscapedNewlines == FormatStyle::ENAS_Left; - unsigned MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit; - unsigned StartOfMacro = 0; - for (unsigned i = 1, e = Changes.size(); i < e; ++i) { - Change &C = Changes[i]; - if (C.NewlinesBefore > 0) { - if (C.ContinuesPPDirective) { - MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine); - } else { - alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine); - MaxEndOfLine = AlignLeft ? 0 : Style.ColumnLimit; - StartOfMacro = i; - } - } - } - alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine); -} - -void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End, - unsigned Column) { - for (unsigned i = Start; i < End; ++i) { - Change &C = Changes[i]; - if (C.NewlinesBefore > 0) { - assert(C.ContinuesPPDirective); - if (C.PreviousEndOfTokenColumn + 1 > Column) - C.EscapedNewlineColumn = 0; - else - C.EscapedNewlineColumn = Column; - } - } -} - -void WhitespaceManager::generateChanges() { - for (unsigned i = 0, e = Changes.size(); i != e; ++i) { - const Change &C = Changes[i]; - if (i > 0) { - assert(Changes[i - 1].OriginalWhitespaceRange.getBegin() != - C.OriginalWhitespaceRange.getBegin() && - "Generating two replacements for the same location"); - } - if (C.CreateReplacement) { - std::string ReplacementText = C.PreviousLinePostfix; - if (C.ContinuesPPDirective) - appendEscapedNewlineText(ReplacementText, C.NewlinesBefore, - C.PreviousEndOfTokenColumn, - C.EscapedNewlineColumn); - else - appendNewlineText(ReplacementText, C.NewlinesBefore); - appendIndentText(ReplacementText, C.Tok->IndentLevel, - std::max(0, C.Spaces), - C.StartOfTokenColumn - std::max(0, C.Spaces)); - ReplacementText.append(C.CurrentLinePrefix); - storeReplacement(C.OriginalWhitespaceRange, ReplacementText); - } - } -} - -void WhitespaceManager::storeReplacement(SourceRange Range, StringRef Text) { - unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) - - SourceMgr.getFileOffset(Range.getBegin()); - // Don't create a replacement, if it does not change anything. - if (StringRef(SourceMgr.getCharacterData(Range.getBegin()), - WhitespaceLength) == Text) - return; - auto Err = Replaces.add(tooling::Replacement( - SourceMgr, CharSourceRange::getCharRange(Range), Text)); - // FIXME: better error handling. For now, just print an error message in the - // release version. - if (Err) { - llvm::errs() << llvm::toString(std::move(Err)) << "\n"; - assert(false); - } -} - -void WhitespaceManager::appendNewlineText(std::string &Text, - unsigned Newlines) { - for (unsigned i = 0; i < Newlines; ++i) - Text.append(UseCRLF ? "\r\n" : "\n"); -} - -void WhitespaceManager::appendEscapedNewlineText( - std::string &Text, unsigned Newlines, unsigned PreviousEndOfTokenColumn, - unsigned EscapedNewlineColumn) { - if (Newlines > 0) { - unsigned Spaces = - std::max<int>(1, EscapedNewlineColumn - PreviousEndOfTokenColumn - 1); - for (unsigned i = 0; i < Newlines; ++i) { - Text.append(Spaces, ' '); - Text.append(UseCRLF ? "\\\r\n" : "\\\n"); - Spaces = std::max<int>(0, EscapedNewlineColumn - 1); - } - } -} - -void WhitespaceManager::appendIndentText(std::string &Text, - unsigned IndentLevel, unsigned Spaces, - unsigned WhitespaceStartColumn) { - switch (Style.UseTab) { - case FormatStyle::UT_Never: - Text.append(Spaces, ' '); - break; - case FormatStyle::UT_Always: { - unsigned FirstTabWidth = - Style.TabWidth - WhitespaceStartColumn % Style.TabWidth; - // Indent with tabs only when there's at least one full tab. - if (FirstTabWidth + Style.TabWidth <= Spaces) { - Spaces -= FirstTabWidth; - Text.append("\t"); - } - Text.append(Spaces / Style.TabWidth, '\t'); - Text.append(Spaces % Style.TabWidth, ' '); - break; - } - case FormatStyle::UT_ForIndentation: - if (WhitespaceStartColumn == 0) { - unsigned Indentation = IndentLevel * Style.IndentWidth; - // This happens, e.g. when a line in a block comment is indented less than - // the first one. - if (Indentation > Spaces) - Indentation = Spaces; - unsigned Tabs = Indentation / Style.TabWidth; - Text.append(Tabs, '\t'); - Spaces -= Tabs * Style.TabWidth; - } - Text.append(Spaces, ' '); - break; - case FormatStyle::UT_ForContinuationAndIndentation: - if (WhitespaceStartColumn == 0) { - unsigned Tabs = Spaces / Style.TabWidth; - Text.append(Tabs, '\t'); - Spaces -= Tabs * Style.TabWidth; - } - Text.append(Spaces, ' '); - break; - } -} - -} // namespace format -} // namespace clang |
