diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index f58ee823032d..c780fdb566da 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -346,6 +346,20 @@ void UnwrappedLineParser::parseBlock(bool MustBeDeclaration, bool AddLevel) { Line->Level = InitialLevel; } +void UnwrappedLineParser::parseChildBlock() { + FormatTok->BlockKind = BK_Block; + nextToken(); + { + ScopedLineState LineState(*this); + ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, + /*MustBeDeclaration=*/false); + Line->Level += 1; + parseLevel(/*HasOpeningBrace=*/true); + Line->Level -= 1; + } + nextToken(); +} + void UnwrappedLineParser::parsePPDirective() { assert(FormatTok->Tok.is(tok::hash) && "'#' expected"); ScopedMacroState MacroState(*Line, Tokens, FormatTok, StructuralError); @@ -591,6 +605,12 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::l_paren: parseParens(); break; + case tok::caret: + nextToken(); + if (FormatTok->is(tok::l_brace)) { + parseChildBlock(); + } + break; case tok::l_brace: if (!tryToParseBracedList()) { // A block outside of parentheses must be the last part of a @@ -674,17 +694,7 @@ void UnwrappedLineParser::tryToParseLambda() { break; } } - FormatTok->BlockKind = BK_Block; - nextToken(); - { - ScopedLineState LineState(*this); - ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, - /*MustBeDeclaration=*/false); - Line->Level += 1; - parseLevel(/*HasOpeningBrace=*/true); - Line->Level -= 1; - } - nextToken(); + parseChildBlock(); } bool UnwrappedLineParser::tryToParseLambdaIntroducer() { @@ -741,9 +751,15 @@ void UnwrappedLineParser::parseBracedList() { // here, otherwise our bail-out scenarios below break. The better solution // might be to just implement a more or less complete expression parser. switch (FormatTok->Tok.getKind()) { - case tok::l_square: - tryToParseLambda(); - break; + case tok::caret: + nextToken(); + if (FormatTok->is(tok::l_brace)) { + parseChildBlock(); + } + break; + case tok::l_square: + tryToParseLambda(); + break; case tok::l_brace: // Assume there are no blocks inside a braced init list apart // from the ones we explicitly parse out (like lambdas). diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h index 4660b1dbac25..5c59da3bebc3 100644 --- a/clang/lib/Format/UnwrappedLineParser.h +++ b/clang/lib/Format/UnwrappedLineParser.h @@ -66,6 +66,7 @@ private: void parseFile(); void parseLevel(bool HasOpeningBrace); void parseBlock(bool MustBeDeclaration, bool AddLevel = true); + void parseChildBlock(); void parsePPDirective(); void parsePPDefine(); void parsePPIf(); diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index d2b2dfd99b3e..32226fc501e3 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -6311,5 +6311,16 @@ TEST_F(FormatTest, FormatsLambdas) { "}\n"); } +TEST_F(FormatTest, FormatsBlocks) { + // FIXME: Make whitespace formatting consistent. Ask a ObjC dev how + // it would ideally look. + verifyFormat("[operation setCompletionBlock:^{\n" + " [self onOperationDone];\n" + "}];\n"); + verifyFormat("int i = {[operation setCompletionBlock : ^{\n" + " [self onOperationDone];\n" + "}] };\n"); +} + } // end namespace tooling } // end namespace clang