ogoffart updated this revision to Diff 59197.
ogoffart added a comment.

Right, i forgot about the C++11 initializer list syntax.  I hope I got it right 
now.


http://reviews.llvm.org/D20821

Files:
  lib/Parse/ParseCXXInlineMethods.cpp
  lib/Parse/ParseObjc.cpp
  lib/Parse/ParseStmt.cpp
  lib/Parse/Parser.cpp
  lib/Sema/SemaDecl.cpp
  unittests/Tooling/ToolingTest.cpp

Index: unittests/Tooling/ToolingTest.cpp
===================================================================
--- unittests/Tooling/ToolingTest.cpp
+++ unittests/Tooling/ToolingTest.cpp
@@ -241,7 +241,7 @@
 struct SkipBodyConsumer : public clang::ASTConsumer {
   /// Skip the 'skipMe' function.
   bool shouldSkipFunctionBody(Decl *D) override {
-    FunctionDecl *F = dyn_cast<FunctionDecl>(D);
+    NamedDecl *F = dyn_cast<NamedDecl>(D);
     return F && F->getNameAsString() == "skipMe";
   }
 };
@@ -259,6 +259,56 @@
                             "int skipMe() { an_error_here }"));
   EXPECT_FALSE(runToolOnCode(new SkipBodyAction,
                              "int skipMeNot() { an_error_here }"));
+
+  // Test constructors with initializers
+  EXPECT_TRUE(
+      runToolOnCode(new SkipBodyAction,
+                    "struct skipMe { skipMe() : an_error() { more error } };"));
+  EXPECT_TRUE(
+      runToolOnCode(new SkipBodyAction,
+                    "struct skipMe { skipMe(); };"
+                    "skipMe::skipMe() : an_error([](){;}) { more error }"));
+  EXPECT_TRUE(
+      runToolOnCode(new SkipBodyAction,
+                    "struct skipMe { skipMe(); };"
+                    "skipMe::skipMe() : an_error{[](){;}} { more error }"));
+  EXPECT_TRUE(
+      runToolOnCode(new SkipBodyAction,
+                    "struct skipMe { skipMe(); };"
+                    "skipMe::skipMe() : a<b<c>(e)>>(), f{}, g() { error }"));
+  EXPECT_TRUE(
+      runToolOnCode(new SkipBodyAction,
+                    "struct skipMe { skipMe() : bases()... { error } };"));
+
+  EXPECT_FALSE(
+      runToolOnCode(new SkipBodyAction,
+                    "struct skipMeNot { skipMeNot() : an_error() { } };"));
+  EXPECT_FALSE(runToolOnCode(new SkipBodyAction,
+                             "struct skipMeNot { skipMeNot(); };"
+                             "skipMeNot::skipMeNot() : an_error() { }"));
+
+  // Try/catch
+  EXPECT_TRUE(runToolOnCode(
+      new SkipBodyAction,
+      "void skipMe() try { an_error() } catch(error) { error };"));
+  EXPECT_TRUE(runToolOnCode(
+      new SkipBodyAction,
+      "struct S { void skipMe() try { an_error() } catch(error) { error } };"));
+  EXPECT_TRUE(
+      runToolOnCode(new SkipBodyAction,
+                    "void skipMe() try { an_error() } catch(error) { error; }"
+                    "catch(error) { error } catch (error) { }"));
+  EXPECT_FALSE(runToolOnCode(
+      new SkipBodyAction,
+      "void skipMe() try something;")); // don't crash while parsing
+
+  // Template
+  EXPECT_TRUE(runToolOnCode(
+      new SkipBodyAction, "template<typename T> int skipMe() { an_error_here }"
+                          "int x = skipMe<int>();"));
+  EXPECT_FALSE(
+      runToolOnCode(new SkipBodyAction,
+                    "template<typename T> int skipMeNot() { an_error_here }"));
 }
 
 TEST(runToolOnCodeWithArgs, TestNoDepFile) {
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11378,7 +11378,7 @@
     FD->setHasSkippedBody();
   else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(Decl))
     MD->setHasSkippedBody();
-  return ActOnFinishFunctionBody(Decl, nullptr);
+  return Decl;
 }
 
 Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -1044,6 +1044,12 @@
     D.complete(DP);
     D.getMutableDeclSpec().abort();
 
+    if (SkipFunctionBodies && (!DP || Actions.canSkipFunctionBody(DP)) &&
+        trySkippingFunctionBody()) {
+      BodyScope.Exit();
+      return Actions.ActOnSkippedFunctionBody(DP);
+    }
+
     CachedTokens Toks;
     LexTemplateFunctionForLateParsing(Toks);
 
@@ -1136,6 +1142,13 @@
     return Res;
   }
 
+  if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) &&
+      trySkippingFunctionBody()) {
+    BodyScope.Exit();
+    Actions.ActOnSkippedFunctionBody(Res);
+    return Actions.ActOnFinishFunctionBody(Res, nullptr, false);
+  }
+
   if (Tok.is(tok::kw_try))
     return ParseFunctionTryBlock(Res, BodyScope);
 
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp
+++ lib/Parse/ParseStmt.cpp
@@ -1916,12 +1916,6 @@
   assert(Tok.is(tok::l_brace));
   SourceLocation LBraceLoc = Tok.getLocation();
 
-  if (SkipFunctionBodies && (!Decl || Actions.canSkipFunctionBody(Decl)) &&
-      trySkippingFunctionBody()) {
-    BodyScope.Exit();
-    return Actions.ActOnSkippedFunctionBody(Decl);
-  }
-
   PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
                                       "parsing function body");
 
@@ -1964,12 +1958,6 @@
   else
     Actions.ActOnDefaultCtorInitializers(Decl);
 
-  if (SkipFunctionBodies && Actions.canSkipFunctionBody(Decl) &&
-      trySkippingFunctionBody()) {
-    BodyScope.Exit();
-    return Actions.ActOnSkippedFunctionBody(Decl);
-  }
-
   // Save and reset current vtordisp stack if we have entered a C++ method body.
   bool IsCXXMethod =
       getLangOpts().CPlusPlus && Decl && isa<CXXMethodDecl>(Decl);
@@ -1990,27 +1978,85 @@
 }
 
 bool Parser::trySkippingFunctionBody() {
-  assert(Tok.is(tok::l_brace));
   assert(SkipFunctionBodies &&
          "Should only be called when SkipFunctionBodies is enabled");
+  bool IsTryCatch = Tok.is(tok::kw_try);
 
   if (!PP.isCodeCompletionEnabled()) {
+    if (IsTryCatch)
+      ConsumeToken();
+    if (Tok.is(tok::colon)) {
+      // Skip constructor initializer list.
+      do {
+        if (!SkipUntil(tok::l_brace, tok::l_paren, StopAtSemi))
+          return true;
+        if (!SkipUntil(tok::r_brace, tok::r_paren))
+          return true;
+        TryConsumeToken(tok::ellipsis);
+      } while (!Tok.is(tok::l_brace));
+    } else if (!Tok.is(tok::l_brace))
+      return true;
     ConsumeBrace();
-    SkipUntil(tok::r_brace);
+    if (!SkipUntil(tok::r_brace))
+      return true;
+    if (IsTryCatch) {
+      if ((Tok.is(tok::identifier) &&
+           Tok.getIdentifierInfo() == getSEHExceptKeyword()) ||
+          Tok.is(tok::kw___finally))
+        ConsumeToken();
+      while (Tok.is(tok::kw_catch) && SkipUntil(tok::l_brace, StopAtSemi)) {
+        SkipUntil(tok::r_brace);
+      }
+    }
     return true;
   }
 
   // We're in code-completion mode. Skip parsing for all function bodies unless
   // the body contains the code-completion point.
   TentativeParsingAction PA(*this);
+  if (IsTryCatch)
+    ConsumeToken();
+  if (Tok.is(tok::colon)) {
+    // Skip constructor initializer list.
+    do {
+      if (!SkipUntil(tok::l_brace, tok::l_paren,
+                     StopAtSemi | StopAtCodeCompletion) ||
+          !SkipUntil(tok::r_brace, tok::r_paren, StopAtCodeCompletion)) {
+        PA.Revert();
+        return false;
+      }
+      TryConsumeToken(tok::ellipsis);
+    } while (!Tok.is(tok::l_brace));
+  } else if (!Tok.is(tok::l_brace)) {
+    PA.Revert();
+    return false;
+  }
   ConsumeBrace();
-  if (SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
-    PA.Commit();
-    return true;
+  if (!SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
+    PA.Revert();
+    return false;
   }
-
-  PA.Revert();
-  return false;
+  if (IsTryCatch) {
+    if ((Tok.is(tok::identifier) &&
+         Tok.getIdentifierInfo() == getSEHExceptKeyword()) ||
+        Tok.is(tok::kw___finally))
+      ConsumeToken();
+    while (Tok.is(tok::kw_catch)) {
+      SkipUntil(tok::l_brace,
+                StopAtSemi | StopBeforeMatch | StopAtCodeCompletion);
+      if (!Tok.is(tok::l_brace)) {
+        PA.Revert();
+        return false;
+      }
+      ConsumeBrace();
+      if (!SkipUntil(tok::r_brace, StopAtCodeCompletion)) {
+        PA.Revert();
+        return false;
+      }
+    }
+  }
+  PA.Commit();
+  return true;
 }
 
 /// ParseCXXTryBlock - Parse a C++ try-block.
Index: lib/Parse/ParseObjc.cpp
===================================================================
--- lib/Parse/ParseObjc.cpp
+++ lib/Parse/ParseObjc.cpp
@@ -2657,6 +2657,12 @@
 /// StashAwayMethodOrFunctionBodyTokens -  Consume the tokens and store them 
 /// for later parsing.
 void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) {
+  if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) &&
+      trySkippingFunctionBody()) {
+    Actions.ActOnSkippedFunctionBody(MDecl);
+    return;
+  }
+
   LexedMethod* LM = new LexedMethod(this, MDecl);
   CurParsedObjCImpl->LateParsedObjCMethods.push_back(LM);
   CachedTokens &Toks = LM->Toks;
Index: lib/Parse/ParseCXXInlineMethods.cpp
===================================================================
--- lib/Parse/ParseCXXInlineMethods.cpp
+++ lib/Parse/ParseCXXInlineMethods.cpp
@@ -101,6 +101,12 @@
     return FnD;
   }
 
+  if (SkipFunctionBodies && (!FnD || Actions.canSkipFunctionBody(FnD)) &&
+      trySkippingFunctionBody()) {
+    Actions.ActOnSkippedFunctionBody(FnD);
+    return FnD;
+  }
+
   // In delayed template parsing mode, if we are within a class template
   // or if we are about to parse function member template then consume
   // the tokens and store them for parsing at the end of the translation unit.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to