Index: lib/Format/Format.cpp =================================================================== --- lib/Format/Format.cpp +++ lib/Format/Format.cpp @@ -600,10 +600,10 @@ FormatTokenLexer(SourceManager &SourceMgr, FileID ID, FormatStyle &Style, encoding::Encoding Encoding) : FormatTok(nullptr), IsFirstToken(true), GreaterStashed(false), - Column(0), TrailingWhitespace(0), SourceMgr(SourceMgr), ID(ID), - Style(Style), IdentTable(getFormattingLangOpts(Style)), - Keywords(IdentTable), Encoding(Encoding), FirstInLineIndex(0), - FormattingDisabled(false) { + LessStashed(false), Column(0), TrailingWhitespace(0), + SourceMgr(SourceMgr), ID(ID), Style(Style), + IdentTable(getFormattingLangOpts(Style)), Keywords(IdentTable), + Encoding(Encoding), FirstInLineIndex(0), FormattingDisabled(false) { Lex.reset(new Lexer(ID, SourceMgr.getBuffer(ID), SourceMgr, getFormattingLangOpts(Style))); Lex->SetKeepWhitespaceMode(true); @@ -633,6 +633,8 @@ return; if (tryMergeConflictMarkers()) return; + if (tryMergeLessLess()) + return; if (Style.Language == FormatStyle::LK_JavaScript) { if (tryMergeJSRegexLiteral()) @@ -658,6 +660,30 @@ } } + bool tryMergeLessLess() { + // Merge X,less,less,Y into X,lessless,Y unless X or Y is less. + if (Tokens.size() < 4) + return false; + SmallVectorImpl::const_iterator First = Tokens.end() - 4; + if (First[3]->is(tok::less) || + First[2]->isNot(tok::less) || + First[1]->isNot(tok::less) || + First[0]->is(tok::less)) + return false; + + // Check for whitespace between less and less + if (First[2]->WhitespaceRange.getBegin() != + First[2]->WhitespaceRange.getEnd()) + return false; + + // Merge X,less,less,Y into X,lessless,Y + First[1]->Tok.setKind(tok::lessless); + First[1]->TokenText = "<<"; + First[1]->ColumnWidth += 1; + Tokens.erase(Tokens.end() - 2); + return true; + } + bool tryMergeTokens(ArrayRef Kinds) { if (Tokens.size() < Kinds.size()) return false; @@ -842,22 +868,32 @@ return false; } + FormatToken *getStashedToken() { + // Create a synthesized second '>' or '<' token. + Token Tok = FormatTok->Tok; + StringRef TokenText = FormatTok->TokenText; + + unsigned OriginalColumn = FormatTok->OriginalColumn; + FormatTok = new (Allocator.Allocate()) FormatToken; + FormatTok->Tok = Tok; + SourceLocation TokLocation = + FormatTok->Tok.getLocation().getLocWithOffset(1); + FormatTok->WhitespaceRange = + SourceRange(TokLocation, TokLocation); + FormatTok->TokenText = TokenText; + FormatTok->ColumnWidth = 1; + FormatTok->OriginalColumn = OriginalColumn; + return FormatTok; + } + FormatToken *getNextToken() { if (GreaterStashed) { - // Create a synthesized second '>' token. - Token Greater = FormatTok->Tok; - unsigned OriginalColumn = FormatTok->OriginalColumn; - FormatTok = new (Allocator.Allocate()) FormatToken; - FormatTok->Tok = Greater; - SourceLocation GreaterLocation = - FormatTok->Tok.getLocation().getLocWithOffset(1); - FormatTok->WhitespaceRange = - SourceRange(GreaterLocation, GreaterLocation); - FormatTok->TokenText = ">"; - FormatTok->ColumnWidth = 1; - FormatTok->OriginalColumn = OriginalColumn; GreaterStashed = false; - return FormatTok; + return getStashedToken(); + } + if (LessStashed) { + LessStashed = false; + return getStashedToken(); } FormatTok = new (Allocator.Allocate()) FormatToken; @@ -952,6 +988,10 @@ FormatTok->Tok.setKind(tok::greater); FormatTok->TokenText = FormatTok->TokenText.substr(0, 1); GreaterStashed = true; + } else if (FormatTok->Tok.is(tok::lessless)) { + FormatTok->Tok.setKind(tok::less); + FormatTok->TokenText = FormatTok->TokenText.substr(0, 1); + LessStashed = true; } // Now FormatTok is the next non-whitespace token. @@ -988,7 +1028,7 @@ FormatToken *FormatTok; bool IsFirstToken; - bool GreaterStashed; + bool GreaterStashed, LessStashed; unsigned Column; unsigned TrailingWhitespace; std::unique_ptr Lex; Index: lib/Format/TokenAnnotator.cpp =================================================================== --- lib/Format/TokenAnnotator.cpp +++ lib/Format/TokenAnnotator.cpp @@ -2039,6 +2039,9 @@ return true; if (Right.is(tok::kw_typename) && Left.isNot(tok::kw_const)) return true; + if ((Left.is(TT_TemplateOpener) && Right.is(TT_TemplateOpener)) || + (Left.is(TT_TemplateCloser) && Right.is(TT_TemplateCloser))) + return false; if (Left.isBinaryOperator() && !Left.isOneOf(tok::arrowstar, tok::lessless) && Style.BreakBeforeBinaryOperators != FormatStyle::BOS_All && (Style.BreakBeforeBinaryOperators == FormatStyle::BOS_None || Index: unittests/Format/FormatTest.cpp =================================================================== --- unittests/Format/FormatTest.cpp +++ unittests/Format/FormatTest.cpp @@ -9735,6 +9735,20 @@ verifyFormat("A>();", Spaces); } +TEST_F(FormatTest, TripleAngleBrackets) { + verifyFormat("f<<<1, 1>>>();"); + verifyFormat("f<<<1, 1, 1, s>>>();"); + verifyFormat("f<<>>();"); + EXPECT_EQ("f<<<1, 1>>>();", + format("f <<< 1, 1 >>> ();")); + verifyFormat("f<<<1, 1>>>();"); + verifyFormat("f<1><<<1, 1>>>();"); + EXPECT_EQ("f<<<1, 1>>>();", + format("f< param > <<< 1, 1 >>> ();")); + verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaa<<<\n 1, 1>>>();"); +} + TEST_F(FormatTest, HandleUnbalancedImplicitBracesAcrossPPBranches) { std::string code = "#if A\n" "#if B\n"