From 70b10474b6bc87d79c71efa6b0aea1bd78b3bab6 Mon Sep 17 00:00:00 2001 From: Daniel Jasper <djasper@google.com> Date: Thu, 8 May 2014 11:58:24 +0000 Subject: [PATCH] clang-format: Initial support for try-catch. Most of this patch was created by Alexander Rojas in http://reviews.llvm.org/D2555 Thank you! Synced and addressed review comments. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@208302 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Format/UnwrappedLineParser.cpp | 73 ++++++++++++++++++++++++++++ lib/Format/UnwrappedLineParser.h | 1 + unittests/Format/FormatTest.cpp | 78 ++++++++++++++++++++++++------ unittests/Format/FormatTestJS.cpp | 10 ++++ 4 files changed, 146 insertions(+), 16 deletions(-) diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index 940fcc8ae2f..e229ff02f5b 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -675,6 +675,9 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::kw_case: parseCaseLabel(); return; + case tok::kw_try: + parseTryCatch(); + return; case tok::kw_extern: nextToken(); if (FormatTok->Tok.is(tok::string_literal)) { @@ -755,6 +758,10 @@ void UnwrappedLineParser::parseStructuralElement() { // Otherwise this was a braced init list, and the structural // element continues. break; + case tok::kw_try: + // We arrive here when parsing function-try blocks. + parseTryCatch(); + return; case tok::identifier: { StringRef Text = FormatTok->TokenText; nextToken(); @@ -1071,6 +1078,72 @@ void UnwrappedLineParser::parseIfThenElse() { } } +void UnwrappedLineParser::parseTryCatch() { + assert(FormatTok->is(tok::kw_try) && "'try' expected"); + nextToken(); + bool NeedsUnwrappedLine = false; + if (FormatTok->is(tok::colon)) { + // We are in a function try block, what comes is an initializer list. + nextToken(); + while (FormatTok->is(tok::identifier)) { + nextToken(); + if (FormatTok->is(tok::l_paren)) + parseParens(); + else + StructuralError = true; + if (FormatTok->is(tok::comma)) + nextToken(); + } + } + if (FormatTok->is(tok::l_brace)) { + CompoundStatementIndenter Indenter(this, Style, Line->Level); + parseBlock(/*MustBeDeclaration=*/false); + if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_GNU || + Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) { + addUnwrappedLine(); + } else { + NeedsUnwrappedLine = true; + } + } else if (!FormatTok->is(tok::kw_catch)) { + // The C++ standard requires a compound-statement after a try. + // If there's none, we try to assume there's a structuralElement + // and try to continue. + StructuralError = true; + addUnwrappedLine(); + ++Line->Level; + parseStructuralElement(); + --Line->Level; + } + while (FormatTok->is(tok::kw_catch) || + (Style.Language == FormatStyle::LK_JavaScript && + FormatTok->TokenText == "finally")) { + nextToken(); + while (FormatTok->isNot(tok::l_brace)) { + if (FormatTok->is(tok::l_paren)) { + parseParens(); + continue; + } + if (FormatTok->isOneOf(tok::semi, tok::r_brace)) + return; + nextToken(); + } + NeedsUnwrappedLine = false; + CompoundStatementIndenter Indenter(this, Style, Line->Level); + parseBlock(/*MustBeDeclaration=*/false); + if (Style.BreakBeforeBraces == FormatStyle::BS_Allman || + Style.BreakBeforeBraces == FormatStyle::BS_GNU || + Style.BreakBeforeBraces == FormatStyle::BS_Stroustrup) { + addUnwrappedLine(); + } else { + NeedsUnwrappedLine = true; + } + } + if (NeedsUnwrappedLine) { + addUnwrappedLine(); + } +} + void UnwrappedLineParser::parseNamespace() { assert(FormatTok->Tok.is(tok::kw_namespace) && "'namespace' expected"); nextToken(); diff --git a/lib/Format/UnwrappedLineParser.h b/lib/Format/UnwrappedLineParser.h index 9eb56011629..63898539b27 100644 --- a/lib/Format/UnwrappedLineParser.h +++ b/lib/Format/UnwrappedLineParser.h @@ -85,6 +85,7 @@ private: void parseParens(); void parseSquare(); void parseIfThenElse(); + void parseTryCatch(); void parseForOrWhileLoop(); void parseDoWhile(); void parseLabel(); diff --git a/unittests/Format/FormatTest.cpp b/unittests/Format/FormatTest.cpp index 3ec1ea50848..75b5c6b518e 100644 --- a/unittests/Format/FormatTest.cpp +++ b/unittests/Format/FormatTest.cpp @@ -2000,32 +2000,81 @@ TEST_F(FormatTest, FormatsInlineASM) { } TEST_F(FormatTest, FormatTryCatch) { - // FIXME: Handle try-catch explicitly in the UnwrappedLineParser, then we'll - // also not create single-line-blocks. verifyFormat("try {\n" " throw a * b;\n" - "}\n" - "catch (int a) {\n" + "} catch (int a) {\n" " // Do nothing.\n" - "}\n" - "catch (...) {\n" + "} catch (...) {\n" " exit(42);\n" "}"); // Function-level try statements. - verifyFormat("int f() try { return 4; }\n" - "catch (...) {\n" + verifyFormat("int f() try { return 4; } catch (...) {\n" " return 5;\n" "}"); verifyFormat("class A {\n" " int a;\n" - " A() try : a(0) {}\n" - " catch (...) {\n" + " A() try : a(0) {\n" + " } catch (...) {\n" " throw;\n" " }\n" "};\n"); } +TEST_F(FormatTest, IncompleteTryCatchBlocks) { + verifyFormat("try {\n" + " f();\n" + "} catch {\n" + " g();\n" + "}"); + verifyFormat("try {\n" + " f();\n" + "} catch (A a) MACRO(x) {\n" + " g();\n" + "} catch (B b) MACRO(x) {\n" + " g();\n" + "}"); +} + +TEST_F(FormatTest, FormatTryCatchBraceStyles) { + FormatStyle Style = getLLVMStyle(); + Style.BreakBeforeBraces = FormatStyle::BS_Attach; + verifyFormat("try {\n" + " // something\n" + "} catch (...) {\n" + " // something\n" + "}", + Style); + Style.BreakBeforeBraces = FormatStyle::BS_Stroustrup; + verifyFormat("try {\n" + " // something\n" + "}\n" + "catch (...) {\n" + " // something\n" + "}", + Style); + Style.BreakBeforeBraces = FormatStyle::BS_Allman; + verifyFormat("try\n" + "{\n" + " // something\n" + "}\n" + "catch (...)\n" + "{\n" + " // something\n" + "}", + Style); + Style.BreakBeforeBraces = FormatStyle::BS_GNU; + verifyFormat("try\n" + " {\n" + " // something\n" + " }\n" + "catch (...)\n" + " {\n" + " // something\n" + " }", + Style); +} + TEST_F(FormatTest, FormatObjCTryCatch) { verifyFormat("@try {\n" " f();\n" @@ -2453,8 +2502,7 @@ TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) { " F(x)\n" " try {\n" " Q();\n" - " }\n" - " catch (...) {\n" + " } catch (...) {\n" " }\n" "}\n", format("int q() {\n" @@ -2471,8 +2519,7 @@ TEST_F(FormatTest, MacroCallsWithoutTrailingSemicolon) { " A() : t(0) {}\n" " A(X x)\n" // FIXME: function-level try blocks are broken. " try : t(0) {\n" - " }\n" - " catch (...) {\n" + " } catch (...) {\n" " }\n" "};", format("class A {\n" @@ -7752,8 +7799,7 @@ TEST_F(FormatTest, GNUBraceBreaking) { TEST_F(FormatTest, CatchExceptionReferenceBinding) { verifyFormat("void f() {\n" " try {\n" - " }\n" - " catch (const Exception &e) {\n" + " } catch (const Exception &e) {\n" " }\n" "}\n", getLLVMStyle()); diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp index 2dfd10faf1b..73e050d6f4f 100644 --- a/unittests/Format/FormatTestJS.cpp +++ b/unittests/Format/FormatTestJS.cpp @@ -118,6 +118,16 @@ TEST_F(FormatTestJS, ClosureStyleComments) { verifyFormat("var x = /** @type {foo} */ (bar);"); } +TEST_F(FormatTestJS, TryCatch) { + verifyFormat("try {\n" + " f();\n" + "} catch (e) {\n" + " g();\n" + "} finally {\n" + " h();\n" + "}"); +} + TEST_F(FormatTestJS, RegexLiteralClassification) { // Regex literals. verifyFormat("var regex = /abc/;"); -- GitLab