From ae76f7f850a9101a20191b10241ca72c23dc40dd Mon Sep 17 00:00:00 2001 From: Manuel Klimek <klimek@google.com> Date: Fri, 11 Oct 2013 21:25:45 +0000 Subject: [PATCH] Support formatting of preprocessor branches. We now correctly format: void SomeFunction(int param1, #ifdef X NoTemplate param2, #else template < #ifdef A MyType<Some> > #else Type1, Type2> #endif param2, #endif param3) { f(); } git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@192503 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Format/ContinuationIndenter.cpp | 4 +- lib/Format/ContinuationIndenter.h | 2 +- lib/Format/Format.cpp | 72 ++++++++++++++----- lib/Format/FormatToken.cpp | 1 + lib/Format/FormatToken.h | 17 ++++- lib/Format/TokenAnnotator.cpp | 21 ++++-- lib/Format/UnwrappedLineParser.cpp | 106 +++++++++++++++++++++------- lib/Format/UnwrappedLineParser.h | 26 ++++++- lib/Format/WhitespaceManager.cpp | 15 +++- lib/Format/WhitespaceManager.h | 5 +- unittests/Format/FormatTest.cpp | 64 ++++++++++++++--- 11 files changed, 265 insertions(+), 68 deletions(-) diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index 560e65ea684..aaddc34499b 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -221,7 +221,7 @@ unsigned ContinuationIndenter::addTokenToState(LineState &State, bool Newline, void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, unsigned ExtraSpaces) { - const FormatToken &Current = *State.NextToken; + FormatToken &Current = *State.NextToken; const FormatToken &Previous = *State.NextToken->Previous; if (Current.is(tok::equal) && (State.Line->First->is(tok::kw_for) || State.ParenLevel == 0) && @@ -301,7 +301,7 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, bool DryRun) { - const FormatToken &Current = *State.NextToken; + FormatToken &Current = *State.NextToken; const FormatToken &Previous = *State.NextToken->Previous; // If we are continuing an expression, we want to indent an extra 4 spaces. unsigned ContinuationIndent = diff --git a/lib/Format/ContinuationIndenter.h b/lib/Format/ContinuationIndenter.h index c3642d24c48..60e0027ec74 100644 --- a/lib/Format/ContinuationIndenter.h +++ b/lib/Format/ContinuationIndenter.h @@ -250,7 +250,7 @@ struct LineState { unsigned Column; /// \brief The token that needs to be next formatted. - const FormatToken *NextToken; + FormatToken *NextToken; /// \brief \c true if this line contains a continued for-loop section. bool LineContainsContinuedForLoopSection; diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index 7fc66167f08..aac9fffb01e 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -447,14 +447,19 @@ private: // State already examined with lower penalty. continue; - addNextStateToQueue(Penalty, Node, /*NewLine=*/false); - addNextStateToQueue(Penalty, Node, /*NewLine=*/true); + FormatDecision LastFormat = Node->State.NextToken->Decision; + if (LastFormat == FD_Unformatted || LastFormat == FD_Continue) + addNextStateToQueue(Penalty, Node, /*NewLine=*/false); + if (LastFormat == FD_Unformatted || LastFormat == FD_Break) + addNextStateToQueue(Penalty, Node, /*NewLine=*/true); } - if (Queue.empty()) + if (Queue.empty()) { // We were unable to find a solution, do nothing. // FIXME: Add diagnostic? + DEBUG(llvm::dbgs() << "Could not find a solution.\n"); return 0; + } // Reconstruct the solution. if (!DryRun) @@ -815,29 +820,54 @@ public: const std::vector<CharSourceRange> &Ranges) : Style(Style), Lex(Lex), SourceMgr(SourceMgr), Whitespaces(SourceMgr, Style, inputUsesCRLF(Lex.getBuffer())), - Ranges(Ranges), Encoding(encoding::detectEncoding(Lex.getBuffer())) { + Ranges(Ranges), UnwrappedLines(1), + Encoding(encoding::detectEncoding(Lex.getBuffer())) { DEBUG(llvm::dbgs() << "File encoding: " << (Encoding == encoding::Encoding_UTF8 ? "UTF8" : "unknown") << "\n"); } - virtual ~Formatter() { - for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { - delete AnnotatedLines[i]; - } - } - tooling::Replacements format() { + tooling::Replacements Result; FormatTokenLexer Tokens(Lex, SourceMgr, Style, Encoding); UnwrappedLineParser Parser(Style, Tokens.lex(), *this); bool StructuralError = Parser.parse(); + assert(UnwrappedLines.rbegin()->empty()); + for (unsigned Run = 0, RunE = UnwrappedLines.size(); Run + 1 != RunE; + ++Run) { + DEBUG(llvm::dbgs() << "Run " << Run << "...\n"); + SmallVector<AnnotatedLine *, 16> AnnotatedLines; + for (unsigned i = 0, e = UnwrappedLines[Run].size(); i != e; ++i) { + AnnotatedLines.push_back(new AnnotatedLine(UnwrappedLines[Run][i])); + } + tooling::Replacements RunResult = + format(AnnotatedLines, StructuralError, Tokens); + DEBUG({ + llvm::dbgs() << "Replacements for run " << Run << ":\n"; + for (tooling::Replacements::iterator I = RunResult.begin(), + E = RunResult.end(); + I != E; ++I) { + llvm::dbgs() << I->toString() << "\n"; + } + }); + for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { + delete AnnotatedLines[i]; + } + Result.insert(RunResult.begin(), RunResult.end()); + Whitespaces.reset(); + } + return Result; + } + + tooling::Replacements format(SmallVectorImpl<AnnotatedLine *> &AnnotatedLines, + bool StructuralError, FormatTokenLexer &Tokens) { TokenAnnotator Annotator(Style, Tokens.getIdentTable().get("in")); for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { Annotator.annotate(*AnnotatedLines[i]); } - deriveLocalStyle(); + deriveLocalStyle(AnnotatedLines); for (unsigned i = 0, e = AnnotatedLines.size(); i != e; ++i) { Annotator.calculateFormattingInformation(*AnnotatedLines[i]); } @@ -920,8 +950,7 @@ public: } else { // Format the first token if necessary, and notify the WhitespaceManager // about the unchanged whitespace. - for (const FormatToken *Tok = TheLine.First; Tok != NULL; - Tok = Tok->Next) { + for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) { if (Tok == TheLine.First && (Tok->NewlinesBefore > 0 || Tok->IsFirst)) { unsigned LevelIndent = Tok->OriginalColumn; @@ -947,6 +976,9 @@ public: // last token. PreviousLineWasTouched = false; } + for (FormatToken *Tok = TheLine.First; Tok != NULL; Tok = Tok->Next) { + Tok->Finalized = true; + } PreviousLine = *I; } return Whitespaces.generateReplacements(); @@ -957,7 +989,8 @@ private: return Text.count('\r') * 2 > Text.count('\n'); } - void deriveLocalStyle() { + void + deriveLocalStyle(const SmallVectorImpl<AnnotatedLine *> &AnnotatedLines) { unsigned CountBoundToVariable = 0; unsigned CountBoundToType = 0; bool HasCpp03IncompatibleFormat = false; @@ -1229,13 +1262,18 @@ private: } virtual void consumeUnwrappedLine(const UnwrappedLine &TheLine) { - AnnotatedLines.push_back(new AnnotatedLine(TheLine)); + assert(!UnwrappedLines.empty()); + UnwrappedLines.back().push_back(TheLine); + } + + virtual void finishRun() { + UnwrappedLines.push_back(SmallVector<UnwrappedLine, 16>()); } /// \brief Add a new line and the required indent before the first Token /// of the \c UnwrappedLine if there was no structural parsing error. /// Returns the indent level of the \c UnwrappedLine. - void formatFirstToken(const FormatToken &RootToken, + void formatFirstToken(FormatToken &RootToken, const AnnotatedLine *PreviousLine, unsigned Indent, bool InPPDirective) { unsigned Newlines = @@ -1272,7 +1310,7 @@ private: SourceManager &SourceMgr; WhitespaceManager Whitespaces; std::vector<CharSourceRange> Ranges; - SmallVector<AnnotatedLine *, 16> AnnotatedLines; + SmallVector<SmallVector<UnwrappedLine, 16>, 2> UnwrappedLines; encoding::Encoding Encoding; bool BinPackInconclusiveFunctions; diff --git a/lib/Format/FormatToken.cpp b/lib/Format/FormatToken.cpp index 7469216a147..35764ce8823 100644 --- a/lib/Format/FormatToken.cpp +++ b/lib/Format/FormatToken.cpp @@ -145,6 +145,7 @@ void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) { bool HasRowWithSufficientColumns = false; unsigned Column = 0; for (unsigned i = 0, e = ItemLengths.size(); i != e; ++i) { + assert(i < MustBreakBeforeItem.size()); if (MustBreakBeforeItem[i] || Column == Columns) { ++Format.LineCount; Column = 0; diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 2541c782aca..12621027cc5 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -76,6 +76,12 @@ enum ParameterPackingKind { PPK_Inconclusive }; +enum FormatDecision { + FD_Unformatted, + FD_Continue, + FD_Break +}; + class TokenRole; class AnnotatedLine; @@ -93,7 +99,8 @@ struct FormatToken { LongestObjCSelectorName(0), FakeRParens(0), StartsBinaryExpression(false), EndsBinaryExpression(false), LastInChainOfCalls(false), PartOfMultiVariableDeclStmt(false), - MatchingParen(NULL), Previous(NULL), Next(NULL) {} + MatchingParen(NULL), Previous(NULL), Next(NULL), + Decision(FD_Unformatted), Finalized(false) {} /// \brief The \c Token. Token Tok; @@ -338,6 +345,14 @@ struct FormatToken { SmallVector<AnnotatedLine *, 1> Children; + /// \brief Stores the formatting decision for the token once it was made. + FormatDecision Decision; + + /// \brief If \c true, this token has been fully formatted (indented and + /// potentially re-formatted inside), and we do not allow further formatting + /// changes. + bool Finalized; + private: // Disallow copying. FormatToken(const FormatToken &) LLVM_DELETED_FUNCTION; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index a564d52cde9..9d9f5ef20f3 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -523,11 +523,17 @@ private: if (CurrentToken != NULL) CurrentToken = CurrentToken->Next; - // Reset token type in case we have already looked at it and then recovered - // from an error (e.g. failure to find the matching >). - if (CurrentToken != NULL && CurrentToken->Type != TT_LambdaLSquare && - CurrentToken->Type != TT_ImplicitStringLiteral) - CurrentToken->Type = TT_Unknown; + if (CurrentToken != NULL) { + // Reset token type in case we have already looked at it and then + // recovered from an error (e.g. failure to find the matching >). + if (CurrentToken->Type != TT_LambdaLSquare && + CurrentToken->Type != TT_ImplicitStringLiteral) + CurrentToken->Type = TT_Unknown; + if (CurrentToken->Role) + CurrentToken->Role.reset(NULL); + CurrentToken->FakeLParens.clear(); + CurrentToken->FakeRParens = 0; + } } /// \brief A struct to hold information valid in a specific context, e.g. @@ -1482,10 +1488,13 @@ void TokenAnnotator::printDebugInfo(const AnnotatedLine &Line) { << " C=" << Tok->CanBreakBefore << " T=" << Tok->Type << " S=" << Tok->SpacesRequiredBefore << " P=" << Tok->SplitPenalty << " Name=" << Tok->Tok.getName() - << " PPK=" << Tok->PackingKind << " FakeLParens="; + << " L=" << Tok->TotalLength << " PPK=" << Tok->PackingKind + << " FakeLParens="; for (unsigned i = 0, e = Tok->FakeLParens.size(); i != e; ++i) llvm::errs() << Tok->FakeLParens[i] << "/"; llvm::errs() << " FakeRParens=" << Tok->FakeRParens << "\n"; + if (Tok->Next == NULL) + assert(Tok == Line.Last); Tok = Tok->Next; } llvm::errs() << "----\n"; diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index d8aa3f383da..93840dcad8f 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -174,6 +174,8 @@ public: return Tokens[Position]; } + void reset() { Position = -1; } + private: ArrayRef<FormatToken *> Tokens; int Position; @@ -186,23 +188,54 @@ UnwrappedLineParser::UnwrappedLineParser(const FormatStyle &Style, UnwrappedLineConsumer &Callback) : Line(new UnwrappedLine), MustBreakBeforeNextToken(false), CurrentLines(&Lines), StructuralError(false), Style(Style), Tokens(NULL), - Callback(Callback), AllTokens(Tokens) {} + Callback(Callback), AllTokens(Tokens), PPBranchLevel(-1) {} + +void UnwrappedLineParser::reset() { + PPBranchLevel = -1; + Line.reset(new UnwrappedLine); + CommentsBeforeNextToken.clear(); + FormatTok = NULL; + MustBreakBeforeNextToken = false; + PreprocessorDirectives.clear(); + CurrentLines = &Lines; + DeclarationScopeStack.clear(); + StructuralError = false; + PPStack.clear(); +} bool UnwrappedLineParser::parse() { - DEBUG(llvm::dbgs() << "----\n"); IndexedTokenSource TokenSource(AllTokens); - Tokens = &TokenSource; - readToken(); - parseFile(); - for (SmallVectorImpl<UnwrappedLine>::iterator I = Lines.begin(), - E = Lines.end(); - I != E; ++I) { - Callback.consumeUnwrappedLine(*I); - } + do { + DEBUG(llvm::dbgs() << "----\n"); + reset(); + Tokens = &TokenSource; + TokenSource.reset(); + + readToken(); + parseFile(); + // Create line with eof token. + pushToken(FormatTok); + addUnwrappedLine(); + + for (SmallVectorImpl<UnwrappedLine>::iterator I = Lines.begin(), + E = Lines.end(); + I != E; ++I) { + Callback.consumeUnwrappedLine(*I); + } + Callback.finishRun(); + Lines.clear(); + while (!PPLevelBranchIndex.empty() && + PPLevelBranchIndex.back() + 1 == PPLevelBranchCount.back()) { + PPLevelBranchIndex.resize(PPLevelBranchIndex.size() - 1); + PPLevelBranchCount.resize(PPLevelBranchCount.size() - 1); + } + if (!PPLevelBranchIndex.empty()) { + ++PPLevelBranchIndex.back(); + assert(PPLevelBranchIndex.size() == PPLevelBranchCount.size()); + assert(PPLevelBranchIndex.back() <= PPLevelBranchCount.back()); + } + } while (!PPLevelBranchIndex.empty()); - // Create line with eof token. - pushToken(FormatTok); - Callback.consumeUnwrappedLine(*Line); return StructuralError; } @@ -379,11 +412,11 @@ void UnwrappedLineParser::parsePPDirective() { parsePPDefine(); return; case tok::pp_if: - parsePPIf(); + parsePPIf(/*IfDef=*/false); break; case tok::pp_ifdef: case tok::pp_ifndef: - parsePPIfdef(); + parsePPIf(/*IfDef=*/true); break; case tok::pp_else: parsePPElse(); @@ -407,12 +440,20 @@ void UnwrappedLineParser::pushPPConditional() { PPStack.push_back(PP_Conditional); } -void UnwrappedLineParser::parsePPIf() { +void UnwrappedLineParser::parsePPIf(bool IfDef) { + ++PPBranchLevel; + assert(PPBranchLevel >= 0 && PPBranchLevel <= (int)PPLevelBranchIndex.size()); + if (PPBranchLevel == (int)PPLevelBranchIndex.size()) { + PPLevelBranchIndex.push_back(0); + PPLevelBranchCount.push_back(0); + } + PPChainBranchIndex.push(0); nextToken(); - if ((FormatTok->Tok.isLiteral() && - StringRef(FormatTok->Tok.getLiteralData(), FormatTok->Tok.getLength()) == - "0") || - FormatTok->Tok.is(tok::kw_false)) { + bool IsLiteralFalse = (FormatTok->Tok.isLiteral() && + StringRef(FormatTok->Tok.getLiteralData(), + FormatTok->Tok.getLength()) == "0") || + FormatTok->Tok.is(tok::kw_false); + if ((!IfDef && IsLiteralFalse) || PPLevelBranchIndex[PPBranchLevel] > 0) { PPStack.push_back(PP_Unreachable); } else { pushPPConditional(); @@ -420,21 +461,34 @@ void UnwrappedLineParser::parsePPIf() { parsePPUnknown(); } -void UnwrappedLineParser::parsePPIfdef() { - pushPPConditional(); - parsePPUnknown(); -} - void UnwrappedLineParser::parsePPElse() { if (!PPStack.empty()) PPStack.pop_back(); - pushPPConditional(); + assert(PPBranchLevel < (int)PPLevelBranchIndex.size()); + if (!PPChainBranchIndex.empty()) + ++PPChainBranchIndex.top(); + if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty() && + PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top()) { + PPStack.push_back(PP_Unreachable); + } else { + pushPPConditional(); + } parsePPUnknown(); } void UnwrappedLineParser::parsePPElIf() { parsePPElse(); } void UnwrappedLineParser::parsePPEndIf() { + assert(PPBranchLevel < (int)PPLevelBranchIndex.size()); + if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty()) { + if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel]) { + assert(PPLevelBranchCount[PPBranchLevel] == 0); + PPLevelBranchCount[PPBranchLevel] = PPChainBranchIndex.top() + 1; + } + } + --PPBranchLevel; + if (!PPChainBranchIndex.empty()) + PPChainBranchIndex.pop(); if (!PPStack.empty()) PPStack.pop_back(); parsePPUnknown(); diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index 3acdbd60a58..7a3993ed34d 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -52,6 +52,7 @@ class UnwrappedLineConsumer { public: virtual ~UnwrappedLineConsumer() {} virtual void consumeUnwrappedLine(const UnwrappedLine &Line) = 0; + virtual void finishRun() = 0; }; class FormatTokenSource; @@ -65,14 +66,14 @@ public: bool parse(); private: + void reset(); void parseFile(); void parseLevel(bool HasOpeningBrace); void parseBlock(bool MustBeDeclaration, bool AddLevel = true); void parseChildBlock(); void parsePPDirective(); void parsePPDefine(); - void parsePPIf(); - void parsePPIfdef(); + void parsePPIf(bool IfDef); void parsePPElIf(); void parsePPElse(); void parsePPEndIf(); @@ -161,6 +162,27 @@ private: // Keeps a stack of currently active preprocessor branching directives. SmallVector<PPBranchKind, 16> PPStack; + // The \c UnwrappedLineParser re-parses the code for each combination + // of preprocessor branches that can be taken. + // To that end, we take the same branch (#if, #else, or one of the #elif + // branches) for each nesting level of preprocessor branches. + // \c PPBranchLevel stores the current nesting level of preprocessor + // branches during one pass over the code. + int PPBranchLevel; + + // Contains the current branch (#if, #else or one of the #elif branches) + // for each nesting level. + SmallVector<int, 8> PPLevelBranchIndex; + + // Contains the maximum number of branches at each nesting level. + SmallVector<int, 8> PPLevelBranchCount; + + // Contains the number of branches per nesting level we are currently + // in while parsing a preprocessor branch sequence. + // This is used to update PPLevelBranchCount at the end of a branch + // sequence. + std::stack<int> PPChainBranchIndex; + friend class ScopedLineState; }; diff --git a/lib/Format/WhitespaceManager.cpp b/lib/Format/WhitespaceManager.cpp index 16d80ea429a..c24ccdfee4d 100644 --- a/lib/Format/WhitespaceManager.cpp +++ b/lib/Format/WhitespaceManager.cpp @@ -39,11 +39,18 @@ WhitespaceManager::Change::Change( ContinuesPPDirective(ContinuesPPDirective), IndentLevel(IndentLevel), Spaces(Spaces) {} -void WhitespaceManager::replaceWhitespace(const FormatToken &Tok, - unsigned Newlines, +void WhitespaceManager::reset() { + Changes.clear(); + Replaces.clear(); +} + +void WhitespaceManager::replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn, bool InPPDirective) { + if (Tok.Finalized) + return; + Tok.Decision = (Newlines > 0) ? FD_Break : FD_Continue; Changes.push_back(Change(true, Tok.WhitespaceRange, IndentLevel, Spaces, StartOfTokenColumn, Newlines, "", "", Tok.Tok.getKind(), InPPDirective && !Tok.IsFirst)); @@ -51,6 +58,8 @@ void WhitespaceManager::replaceWhitespace(const FormatToken &Tok, void WhitespaceManager::addUntouchableToken(const FormatToken &Tok, bool InPPDirective) { + if (Tok.Finalized) + return; Changes.push_back(Change(false, Tok.WhitespaceRange, /*IndentLevel=*/0, /*Spaces=*/0, Tok.OriginalColumn, Tok.NewlinesBefore, "", "", Tok.Tok.getKind(), @@ -61,6 +70,8 @@ void WhitespaceManager::replaceWhitespaceInToken( const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars, StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective, unsigned Newlines, unsigned IndentLevel, unsigned Spaces) { + if (Tok.Finalized) + return; Changes.push_back(Change( true, SourceRange(Tok.getStartOfNonWhitespace().getLocWithOffset(Offset), Tok.getStartOfNonWhitespace().getLocWithOffset( diff --git a/lib/Format/WhitespaceManager.h b/lib/Format/WhitespaceManager.h index 93d331e1251..ae6202395f6 100644 --- a/lib/Format/WhitespaceManager.h +++ b/lib/Format/WhitespaceManager.h @@ -41,9 +41,12 @@ public: bool UseCRLF) : SourceMgr(SourceMgr), Style(Style), UseCRLF(UseCRLF) {} + /// \brief Prepares the \c WhitespaceManager for another run. + void reset(); + /// \brief Replaces the whitespace in front of \p Tok. Only call once for /// each \c AnnotatedToken. - void replaceWhitespace(const FormatToken &Tok, unsigned Newlines, + void replaceWhitespace(FormatToken &Tok, unsigned Newlines, unsigned IndentLevel, unsigned Spaces, unsigned StartOfTokenColumn, bool InPPDirective = false); diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 59596bc5439..d49d49ffe3b 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -22,6 +22,7 @@ protected: std::string format(llvm::StringRef Code, unsigned Offset, unsigned Length, const FormatStyle &Style) { DEBUG(llvm::errs() << "---\n"); + DEBUG(llvm::errs() << Code << "\n\n"); std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length)); tooling::Replacements Replaces = reformat(Style, Code, Ranges); ReplacementCount = Replaces.size(); @@ -66,7 +67,14 @@ protected: JustReplacedNewline = false; } } - return MessedUp; + std::string WithoutWhitespace; + if (MessedUp[0] != ' ') + WithoutWhitespace.push_back(MessedUp[0]); + for (unsigned i = 1, e = MessedUp.size(); i != e; ++i) { + if (MessedUp[i] != ' ' || MessedUp[i - 1] != ' ') + WithoutWhitespace.push_back(MessedUp[i]); + } + return WithoutWhitespace; } FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) { @@ -103,7 +111,7 @@ TEST_F(FormatTest, MessUp) { EXPECT_EQ("1 2 3\n", messUp("1\n2\n3\n")); EXPECT_EQ("a\n//b\nc", messUp("a\n//b\nc")); EXPECT_EQ("a\n#b\nc", messUp("a\n#b\nc")); - EXPECT_EQ("a\n#b c d\ne", messUp("a\n#b\\\nc\\\nd\ne")); + EXPECT_EQ("a\n#b c d\ne", messUp("a\n#b\\\nc\\\nd\ne")); } //===----------------------------------------------------------------------===// @@ -2263,6 +2271,38 @@ TEST_F(FormatTest, LayoutStatementsAroundPreprocessorDirectives) { "#endif\n" "{\n" "}"); + verifyFormat("void f() {\n" + " if (true)\n" + "#ifdef A\n" + " f(42);\n" + " x();\n" + "#else\n" + " g();\n" + " x();\n" + "#endif\n" + "}"); + verifyFormat("void f(param1, param2,\n" + " param3,\n" + "#ifdef A\n" + " param4(param5,\n" + "#ifdef A1\n" + " param6,\n" + "#ifdef A2\n" + " param7),\n" + "#else\n" + " param8),\n" + " param9,\n" + "#endif\n" + " param10,\n" + "#endif\n" + " param11)\n" + "#else\n" + " param12)\n" + "#endif\n" + "{\n" + " x();\n" + "}", + getLLVMStyleWithColumns(28)); } TEST_F(FormatTest, LayoutBlockInsideParens) { @@ -3383,10 +3423,10 @@ TEST_F(FormatTest, AlignsPipes) { " << aaaaaaaaaaaaaaaaaaaaaaaaaaaaa;"); verifyFormat("return out << \"somepacket = {\\n\"\n" - " << \" aaaaaa = \" << pkt.aaaaaa << \"\\n\"\n" - " << \" bbbb = \" << pkt.bbbb << \"\\n\"\n" - " << \" cccccc = \" << pkt.cccccc << \"\\n\"\n" - " << \" ddd = [\" << pkt.ddd << \"]\\n\"\n" + " << \" aaaaaa = \" << pkt.aaaaaa << \"\\n\"\n" + " << \" bbbb = \" << pkt.bbbb << \"\\n\"\n" + " << \" cccccc = \" << pkt.cccccc << \"\\n\"\n" + " << \" ddd = [\" << pkt.ddd << \"]\\n\"\n" " << \"}\";"); verifyFormat("llvm::outs() << \"aaaaaaaaaaaaaaaa: \" << aaaaaaaaaaaaaaaa\n" @@ -4295,7 +4335,7 @@ TEST_F(FormatTest, IncorrectCodeMissingParens) { TEST_F(FormatTest, DoesNotTouchUnwrappedLinesWithErrors) { verifyFormat("namespace {\n" - "class Foo { Foo (\n" + "class Foo { Foo (\n" "};\n" "} // comment"); } @@ -4522,8 +4562,11 @@ TEST_F(FormatTest, UnderstandContextOfRecordTypeKeywords) { } TEST_F(FormatTest, DoNotInterfereWithErrorAndWarning) { - verifyFormat("#error Leave all white!!!!! space* alone!\n"); - verifyFormat("#warning Leave all white!!!!! space* alone!\n"); + EXPECT_EQ("#error Leave all white!!!!! space* alone!\n", + format("#error Leave all white!!!!! space* alone!\n")); + EXPECT_EQ( + "#warning Leave all white!!!!! space* alone!\n", + format("#warning Leave all white!!!!! space* alone!\n")); EXPECT_EQ("#error 1", format(" # error 1")); EXPECT_EQ("#warning 1", format(" # warning 1")); } @@ -4568,7 +4611,8 @@ TEST_F(FormatTest, MergeHandlingInTheFaceOfPreprocessorDirectives) { " if (true) continue;\n" "#endif\n" " // Comment\n" - " if (true) continue;", + " if (true) continue;\n" + "}", ShortMergedIf); } -- GitLab