diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -491,7 +491,11 @@ // Keep a stack of positions of lbrace tokens. We will // update information about whether an lbrace starts a // braced init list or a different block during the loop. - SmallVector LBraceStack; + struct StackEntry { + FormatToken *Tok; + const FormatToken *PrevTok; + }; + SmallVector LBraceStack; assert(Tok->is(tok::l_brace)); do { // Get next non-comment token. @@ -521,12 +525,12 @@ } else { Tok->setBlockKind(BK_Unknown); } - LBraceStack.push_back(Tok); + LBraceStack.push_back({Tok, PrevTok}); break; case tok::r_brace: if (LBraceStack.empty()) break; - if (LBraceStack.back()->is(BK_Unknown)) { + if (LBraceStack.back().Tok->is(BK_Unknown)) { bool ProbablyBracedList = false; if (Style.Language == FormatStyle::LK_Proto) { ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square); @@ -554,7 +558,7 @@ // If we already marked the opening brace as braced list, the closing // must also be part of it. - ProbablyBracedList = LBraceStack.back()->is(TT_BracedListLBrace); + ProbablyBracedList = LBraceStack.back().Tok->is(TT_BracedListLBrace); ProbablyBracedList = ProbablyBracedList || (Style.isJavaScript() && @@ -570,8 +574,14 @@ ProbablyBracedList = ProbablyBracedList || NextTok->isOneOf(tok::comma, tok::period, tok::colon, - tok::r_paren, tok::r_square, tok::l_brace, - tok::ellipsis); + tok::r_paren, tok::r_square, tok::ellipsis); + + // Distinguish between braced list in a constructor initializer list + // followed by constructor body, or just adjacent blocks. + ProbablyBracedList = + ProbablyBracedList || + (NextTok->is(tok::l_brace) && LBraceStack.back().PrevTok && + LBraceStack.back().PrevTok->is(tok::identifier)); ProbablyBracedList = ProbablyBracedList || @@ -595,10 +605,10 @@ } if (ProbablyBracedList) { Tok->setBlockKind(BK_BracedInit); - LBraceStack.back()->setBlockKind(BK_BracedInit); + LBraceStack.back().Tok->setBlockKind(BK_BracedInit); } else { Tok->setBlockKind(BK_Block); - LBraceStack.back()->setBlockKind(BK_Block); + LBraceStack.back().Tok->setBlockKind(BK_Block); } } LBraceStack.pop_back(); @@ -615,8 +625,8 @@ case tok::kw_switch: case tok::kw_try: case tok::kw___try: - if (!LBraceStack.empty() && LBraceStack.back()->is(BK_Unknown)) - LBraceStack.back()->setBlockKind(BK_Block); + if (!LBraceStack.empty() && LBraceStack.back().Tok->is(BK_Unknown)) + LBraceStack.back().Tok->setBlockKind(BK_Block); break; default: break; @@ -626,9 +636,9 @@ } while (Tok->isNot(tok::eof) && !LBraceStack.empty()); // Assume other blocks for all unclosed opening braces. - for (FormatToken *LBrace : LBraceStack) - if (LBrace->is(BK_Unknown)) - LBrace->setBlockKind(BK_Block); + for (const auto &Entry : LBraceStack) + if (Entry.Tok->is(BK_Unknown)) + Entry.Tok->setBlockKind(BK_Block); FormatTok = Tokens->setPosition(StoredPosition); } diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -13732,6 +13732,26 @@ " struct Dummy {};\n" " f(v);\n" "}"); + verifyFormat("void foo() {\n" + " { // asdf\n" + " { int a; }\n" + " }\n" + " {\n" + " { int b; }\n" + " }\n" + "}"); + verifyFormat("namespace n {\n" + "void foo() {\n" + " {\n" + " {\n" + " statement();\n" + " if (false) {\n" + " }\n" + " }\n" + " }\n" + " {}\n" + "}\n" + "} // namespace n"); // Long lists should be formatted in columns even if they are nested. verifyFormat( diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -40,6 +40,8 @@ EXPECT_EQ((FormatTok)->getType(), Type) << *(FormatTok) #define EXPECT_TOKEN_PRECEDENCE(FormatTok, Prec) \ EXPECT_EQ((FormatTok)->getPrecedence(), Prec) << *(FormatTok) +#define EXPECT_BRACE_KIND(FormatTok, Kind) \ + EXPECT_EQ(FormatTok->getBlockKind(), Kind) << *(FormatTok) #define EXPECT_TOKEN(FormatTok, Kind, Type) \ do { \ EXPECT_TOKEN_KIND(FormatTok, Kind); \ @@ -1800,6 +1802,22 @@ EXPECT_TOKEN(Tokens[3], tok::colon, TT_CaseLabelColon); } +TEST_F(TokenAnnotatorTest, UnderstandsNestedBlocks) { + // The closing braces are not annotated. It doesn't seem to cause a problem. + // So we only test for the opening braces. + auto Tokens = annotate("{\n" + " {\n" + " { int a = 0; }\n" + " }\n" + " {}\n" + "}"); + ASSERT_EQ(Tokens.size(), 14u) << Tokens; + EXPECT_BRACE_KIND(Tokens[0], BK_Block); + EXPECT_BRACE_KIND(Tokens[1], BK_Block); + EXPECT_BRACE_KIND(Tokens[2], BK_Block); + EXPECT_BRACE_KIND(Tokens[10], BK_Block); +} + } // namespace } // namespace format } // namespace clang