clang-format: Add support for SEH __try / __except / __finally blocks.
authorNico Weber <nicolasweber@gmx.de>
Wed, 4 Feb 2015 15:26:27 +0000 (15:26 +0000)
committerNico Weber <nicolasweber@gmx.de>
Wed, 4 Feb 2015 15:26:27 +0000 (15:26 +0000)
This lets clang-format format

    __try {
    } __except(0) {
    }

and

    __try {
    } __finally {
    }

correctly. __try and __finally are keywords if `LangOpts.MicrosoftExt` is set,
so this turns this on.  This also enables a few other keywords, but it
shouldn't overly perturb regular clang-format operation.  __except is a
context-sensitive keyword, so `AdditionalKeywords` needs to be passed around to
a few more places.

Fixes PR22321.

llvm-svn: 228148

clang/lib/Format/Format.cpp
clang/lib/Format/FormatToken.h
clang/lib/Format/TokenAnnotator.cpp
clang/lib/Format/UnwrappedLineFormatter.cpp
clang/lib/Format/UnwrappedLineFormatter.h
clang/lib/Format/UnwrappedLineParser.cpp
clang/unittests/Format/FormatTest.cpp

index 128a5a7..309b322 100644 (file)
@@ -1123,7 +1123,8 @@ public:
     ContinuationIndenter Indenter(Style, Tokens.getKeywords(), SourceMgr,
                                   Whitespaces, Encoding,
                                   BinPackInconclusiveFunctions);
-    UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style);
+    UnwrappedLineFormatter Formatter(&Indenter, &Whitespaces, Style,
+                                     Tokens.getKeywords());
     Formatter.format(AnnotatedLines, /*DryRun=*/false);
     return Whitespaces.generateReplacements();
   }
@@ -1399,6 +1400,7 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) {
   LangOpts.Bool = 1;
   LangOpts.ObjC1 = 1;
   LangOpts.ObjC2 = 1;
+  LangOpts.MicrosoftExt = 1; // To get kw___try, kw___finally.
   return LangOpts;
 }
 
index 4811e02..036e1ed 100644 (file)
@@ -555,6 +555,7 @@ struct AdditionalKeywords {
     kw_package = &IdentTable.get("package");
     kw_synchronized = &IdentTable.get("synchronized");
     kw_throws = &IdentTable.get("throws");
+    kw___except = &IdentTable.get("__except");
 
     kw_option = &IdentTable.get("option");
     kw_optional = &IdentTable.get("optional");
@@ -563,12 +564,13 @@ struct AdditionalKeywords {
     kw_returns = &IdentTable.get("returns");
   }
 
-  // ObjC context sensitive keywords.
+  // Context sensitive keywords.
   IdentifierInfo *kw_in;
   IdentifierInfo *kw_CF_ENUM;
   IdentifierInfo *kw_CF_OPTIONS;
   IdentifierInfo *kw_NS_ENUM;
   IdentifierInfo *kw_NS_OPTIONS;
+  IdentifierInfo *kw___except;
 
   // JavaScript keywords.
   IdentifierInfo *kw_finally;
index 02f80ae..e00db21 100644 (file)
@@ -1701,8 +1701,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line,
            (Style.SpaceBeforeParens != FormatStyle::SBPO_Never &&
             (Left.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while,
                           tok::kw_switch, tok::kw_case) ||
-             (Left.isOneOf(tok::kw_try, tok::kw_catch, tok::kw_new,
-                           tok::kw_delete) &&
+             (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch,
+                           tok::kw_new, tok::kw_delete) &&
               (!Left.Previous || Left.Previous->isNot(tok::period))) ||
              Left.IsForEachMacro)) ||
            (Style.SpaceBeforeParens == FormatStyle::SBPO_Always &&
index 4844b66..0c744e4 100644 (file)
@@ -27,7 +27,8 @@ bool startsExternCBlock(const AnnotatedLine &Line) {
 
 class LineJoiner {
 public:
-  LineJoiner(const FormatStyle &Style) : Style(Style) {}
+  LineJoiner(const FormatStyle &Style, const AdditionalKeywords &Keywords)
+      : Style(Style), Keywords(Keywords) {}
 
   /// \brief Calculates how many lines can be merged into 1 starting at \p I.
   unsigned
@@ -200,7 +201,9 @@ private:
     if (Line.First->isOneOf(tok::kw_else, tok::kw_case))
       return 0;
     if (Line.First->isOneOf(tok::kw_if, tok::kw_while, tok::kw_do, tok::kw_try,
-                            tok::kw_catch, tok::kw_for, tok::r_brace)) {
+                            tok::kw___try, tok::kw_catch, tok::kw___finally,
+                            tok::kw_for, tok::r_brace) ||
+        Line.First->is(Keywords.kw___except)) {
       if (!Style.AllowShortBlocksOnASingleLine)
         return 0;
       if (!Style.AllowShortIfStatementsOnASingleLine &&
@@ -211,7 +214,11 @@ private:
         return 0;
       // FIXME: Consider an option to allow short exception handling clauses on
       // a single line.
-      if (Line.First->isOneOf(tok::kw_try, tok::kw_catch))
+      // FIXME: This isn't covered by tests.
+      // FIXME: For catch, __except, __finally the first token on the line
+      // is '}', so this isn't correct here.
+      if (Line.First->isOneOf(tok::kw_try, tok::kw___try, tok::kw_catch,
+                              Keywords.kw___except, tok::kw___finally))
         return 0;
     }
 
@@ -286,6 +293,7 @@ private:
   }
 
   const FormatStyle &Style;
+  const AdditionalKeywords &Keywords;
 };
 
 class NoColumnLimitFormatter {
@@ -324,7 +332,7 @@ unsigned
 UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
                                bool DryRun, int AdditionalIndent,
                                bool FixBadIndentation) {
-  LineJoiner Joiner(Style);
+  LineJoiner Joiner(Style, Keywords);
 
   // Try to look up already computed penalty in DryRun-mode.
   std::pair<const SmallVectorImpl<AnnotatedLine *> *, unsigned> CacheKey(
index 3ae6dbc..5e02612 100644 (file)
@@ -32,8 +32,10 @@ class UnwrappedLineFormatter {
 public:
   UnwrappedLineFormatter(ContinuationIndenter *Indenter,
                          WhitespaceManager *Whitespaces,
-                         const FormatStyle &Style)
-      : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style) {}
+                         const FormatStyle &Style,
+                         const AdditionalKeywords &Keywords)
+      : Indenter(Indenter), Whitespaces(Whitespaces), Style(Style),
+        Keywords(Keywords) {}
 
   unsigned format(const SmallVectorImpl<AnnotatedLine *> &Lines, bool DryRun,
                   int AdditionalIndent = 0, bool FixBadIndentation = false);
@@ -153,6 +155,7 @@ private:
   ContinuationIndenter *Indenter;
   WhitespaceManager *Whitespaces;
   FormatStyle Style;
+  const AdditionalKeywords &Keywords;
 
   llvm::SpecificBumpPtrAllocator<StateNode> Allocator;
 
index 23b9d55..47b3b9c 100644 (file)
@@ -374,6 +374,7 @@ void UnwrappedLineParser::calculateBraceTypes() {
     case tok::kw_for:
     case tok::kw_switch:
     case tok::kw_try:
+    case tok::kw___try:
       if (!LBraceStack.empty())
         LBraceStack.back()->BlockKind = BK_Block;
       break;
@@ -713,6 +714,7 @@ void UnwrappedLineParser::parseStructuralElement() {
     parseCaseLabel();
     return;
   case tok::kw_try:
+  case tok::kw___try:
     parseTryCatch();
     return;
   case tok::kw_extern:
@@ -1149,7 +1151,7 @@ void UnwrappedLineParser::parseIfThenElse() {
 }
 
 void UnwrappedLineParser::parseTryCatch() {
-  assert(FormatTok->is(tok::kw_try) && "'try' expected");
+  assert(FormatTok->isOneOf(tok::kw_try, tok::kw___try) && "'try' expected");
   nextToken();
   bool NeedsUnwrappedLine = false;
   if (FormatTok->is(tok::colon)) {
@@ -1189,7 +1191,8 @@ void UnwrappedLineParser::parseTryCatch() {
     parseStructuralElement();
     --Line->Level;
   }
-  while (FormatTok->is(tok::kw_catch) ||
+  while (FormatTok->isOneOf(tok::kw_catch, Keywords.kw___except,
+                            tok::kw___finally) ||
          ((Style.Language == FormatStyle::LK_Java ||
            Style.Language == FormatStyle::LK_JavaScript) &&
           FormatTok->is(Keywords.kw_finally))) {
index f099f20..b88bdb9 100644 (file)
@@ -2244,6 +2244,26 @@ TEST_F(FormatTest, FormatTryCatch) {
   verifyFormat("try {} catch (");
 }
 
+TEST_F(FormatTest, FormatSEHTryCatch) {
+  verifyFormat("__try {\n"
+               "  int a = b * c;\n"
+               "} __except (EXCEPTION_EXECUTE_HANDLER) {\n"
+               "  // Do nothing.\n"
+               "}");
+
+  verifyFormat("__try {\n"
+               "  int a = b * c;\n"
+               "} __finally {\n"
+               "  // Do nothing.\n"
+               "}");
+
+  verifyFormat("DEBUG({\n"
+               "  __try {\n"
+               "  } __finally {\n"
+               "  }\n"
+               "});\n");
+}
+
 TEST_F(FormatTest, IncompleteTryCatchBlocks) {
   verifyFormat("try {\n"
                "  f();\n"
@@ -2276,6 +2296,13 @@ TEST_F(FormatTest, FormatTryCatchBraceStyles) {
                "  // something\n"
                "}",
                Style);
+  verifyFormat("__try {\n"
+               "  // something\n"
+               "}\n"
+               "__finally {\n"
+               "  // something\n"
+               "}",
+               Style);
   Style.BreakBeforeBraces = FormatStyle::BS_Allman;
   verifyFormat("try\n"
                "{\n"