Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -1157,7 +1157,8 @@ encoding::Encoding Encoding) : FormatTok(NULL), IsFirstToken(true), GreaterStashed(false), Column(0), TrailingWhitespace(0), Lex(Lex), SourceMgr(SourceMgr), Style(Style), - IdentTable(getFormattingLangOpts()), Encoding(Encoding) { + IdentTable(getFormattingLangOpts()), Encoding(Encoding), + FirstInLineIndex(0) { Lex.SetKeepWhitespaceMode(true); for (const std::string& ForEachMacro : Style.ForEachMacros) @@ -1167,9 +1168,12 @@ ArrayRef lex() { assert(Tokens.empty()); + assert(FirstInLineIndex == 0); do { Tokens.push_back(getNextToken()); tryMergePreviousTokens(); + if (Tokens.back()->NewlinesBefore > 0) + FirstInLineIndex = Tokens.size() - 1; } while (Tokens.back()->Tok.isNot(tok::eof)); return Tokens; } @@ -1180,6 +1184,8 @@ void tryMergePreviousTokens() { if (tryMerge_TMacro()) return; + if (tryMergeConflictMarkers()) + return; if (Style.Language == FormatStyle::LK_JavaScript) { static tok::TokenKind JSIdentity[] = { tok::equalequal, tok::equal }; @@ -1254,6 +1260,63 @@ return true; } + bool tryMergeConflictMarkers() { + if (Tokens.back()->NewlinesBefore == 0 && Tokens.back()->isNot(tok::eof)) + return false; + + FileID ID; + unsigned offset; + std::tie(ID, offset) = SourceMgr.getDecomposedLoc( + Tokens[FirstInLineIndex]->getStartOfNonWhitespace()); + StringRef Buffer = SourceMgr.getBuffer(ID)->getBuffer(); + auto LineOffset = Buffer.rfind('\n', offset); + if (LineOffset == StringRef::npos) { + LineOffset = 0; + } else { + ++LineOffset; + } + + // We only look at the first 8 characters of the line, as the longest + // markers are 7 characters long. + StringRef Line = Buffer.substr(LineOffset, 8); + + // Git markers are 7 characters long - either the line ends afterwards, or + // we expect a space. + bool GitMarkerSize = Line.size() <= 7 || Line[7] == ' ' || Line[7] == '\n'; + // Perforce markers are 4 characters long. + bool PerforceMarkerSize = + Line.size() <= 4 || Line[4] == ' ' || Line[4] == '\n'; + + TokenType Type = TT_Unknown; + if ((GitMarkerSize && Line.startswith("<<<<<<<")) || + (PerforceMarkerSize && Line.startswith(">>>>"))) { + Type = TT_ConflictStart; + } else if ((GitMarkerSize && + (Line.startswith("|||||||") || Line.startswith("======="))) || + (PerforceMarkerSize && Line.startswith("===="))) { + Type = TT_ConflictAlternative; + } else if ((GitMarkerSize && Line.startswith(">>>>>>>")) || + (PerforceMarkerSize && Line.startswith("<<<<"))) { + Type = TT_ConflictEnd; + } + + if (Type != TT_Unknown) { + FormatToken *Next = Tokens.back(); + + Tokens.resize(FirstInLineIndex + 1); + // We do not need to build a complete token here, as we will skip it + // during parsing anyway (as we must not touch whitespace around conflict + // markers). + Tokens.back()->Type = Type; + Tokens.back()->Tok.setKind(tok::kw___unknown_anytype); + + Tokens.push_back(Next); + return true; + } + + return false; + } + FormatToken *getNextToken() { if (GreaterStashed) { // Create a synthesized second '>' token. @@ -1389,7 +1452,6 @@ return FormatTok; } - FormatToken *FormatTok; bool IsFirstToken; bool GreaterStashed; @@ -1401,6 +1463,8 @@ IdentifierTable IdentTable; encoding::Encoding Encoding; llvm::SpecificBumpPtrAllocator Allocator; + // Index of the last token that starts a new line in 'Tokens'. + unsigned FirstInLineIndex; SmallVector Tokens; SmallVector ForEachMacros; Index: lib/Format/FormatToken.h =================================================================== --- lib/Format/FormatToken.h +++ lib/Format/FormatToken.h @@ -64,6 +64,9 @@ TT_TrailingReturnArrow, TT_TrailingUnaryOperator, TT_UnaryOperator, + TT_ConflictStart, + TT_ConflictAlternative, + TT_ConflictEnd, TT_Unknown }; Index: lib/Format/UnwrappedLineParser.h =================================================================== --- lib/Format/UnwrappedLineParser.h +++ lib/Format/UnwrappedLineParser.h @@ -107,7 +107,10 @@ void flushComments(bool NewlineBeforeNext); void pushToken(FormatToken *Tok); void calculateBraceTypes(); - void pushPPConditional(); + void conditionalCompilationStart(bool Unreachable); + void conditionalCompilationAlternative(); + void conditionalCompilationCondition(bool Unreachable); + void conditionalCompilationEnd(); bool isOnNewLine(const FormatToken& FormatTok); // FIXME: We are constantly running into bugs where Line.Level is incorrectly Index: lib/Format/UnwrappedLineParser.cpp =================================================================== --- lib/Format/UnwrappedLineParser.cpp +++ lib/Format/UnwrappedLineParser.cpp @@ -465,14 +465,7 @@ } } -void UnwrappedLineParser::pushPPConditional() { - if (!PPStack.empty() && PPStack.back() == PP_Unreachable) - PPStack.push_back(PP_Unreachable); - else - PPStack.push_back(PP_Conditional); -} - -void UnwrappedLineParser::parsePPIf(bool IfDef) { +void UnwrappedLineParser::conditionalCompilationStart(bool Unreachable) { ++PPBranchLevel; assert(PPBranchLevel >= 0 && PPBranchLevel <= (int)PPLevelBranchIndex.size()); if (PPBranchLevel == (int)PPLevelBranchIndex.size()) { @@ -480,37 +473,29 @@ PPLevelBranchCount.push_back(0); } PPChainBranchIndex.push(0); - nextToken(); - 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(); - } - parsePPUnknown(); + bool Skip = PPLevelBranchIndex[PPBranchLevel] > 0; + conditionalCompilationCondition(Unreachable || Skip); } -void UnwrappedLineParser::parsePPElse() { +void UnwrappedLineParser::conditionalCompilationAlternative() { if (!PPStack.empty()) PPStack.pop_back(); 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(); + conditionalCompilationCondition( + PPBranchLevel >= 0 && !PPChainBranchIndex.empty() && + PPLevelBranchIndex[PPBranchLevel] != PPChainBranchIndex.top()); } -void UnwrappedLineParser::parsePPElIf() { parsePPElse(); } +void UnwrappedLineParser::conditionalCompilationCondition(bool Unreachable) { + if (Unreachable || (!PPStack.empty() && PPStack.back() == PP_Unreachable)) + PPStack.push_back(PP_Unreachable); + else + PPStack.push_back(PP_Conditional); +} -void UnwrappedLineParser::parsePPEndIf() { +void UnwrappedLineParser::conditionalCompilationEnd() { assert(PPBranchLevel < (int)PPLevelBranchIndex.size()); if (PPBranchLevel >= 0 && !PPChainBranchIndex.empty()) { if (PPChainBranchIndex.top() + 1 > PPLevelBranchCount[PPBranchLevel]) { @@ -524,6 +509,27 @@ PPChainBranchIndex.pop(); if (!PPStack.empty()) PPStack.pop_back(); +} + +void UnwrappedLineParser::parsePPIf(bool IfDef) { + nextToken(); + bool IsLiteralFalse = (FormatTok->Tok.isLiteral() && + StringRef(FormatTok->Tok.getLiteralData(), + FormatTok->Tok.getLength()) == "0") || + FormatTok->Tok.is(tok::kw_false); + conditionalCompilationStart(!IfDef && IsLiteralFalse); + parsePPUnknown(); +} + +void UnwrappedLineParser::parsePPElse() { + conditionalCompilationAlternative(); + parsePPUnknown(); +} + +void UnwrappedLineParser::parsePPElIf() { parsePPElse(); } + +void UnwrappedLineParser::parsePPEndIf() { + conditionalCompilationEnd(); parsePPUnknown(); } @@ -1406,6 +1412,26 @@ flushComments(isOnNewLine(*FormatTok)); parsePPDirective(); } + while (FormatTok->Type == TT_ConflictStart || + FormatTok->Type == TT_ConflictEnd || + FormatTok->Type == TT_ConflictAlternative) { + switch (FormatTok->Type) { + case TT_ConflictStart: + conditionalCompilationStart(/*Unreachable=*/false); + break; + case TT_ConflictAlternative: + conditionalCompilationAlternative(); + break; + case TT_ConflictEnd: + conditionalCompilationEnd(); + break; + default: + llvm_unreachable("Unexpected token type."); + break; + } + FormatTok = Tokens->getNextToken(); + FormatTok->MustBreakBefore = true; + } if (!PPStack.empty() && (PPStack.back() == PP_Unreachable) && !Line->InPPDirective) { Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -12,6 +12,7 @@ #include "FormatTestUtils.h" #include "clang/Format/Format.h" #include "llvm/Support/Debug.h" +#include "llvm/ADT/Twine.h" #include "gtest/gtest.h" namespace clang {