>From 70b1148750822c1c472e6603023d81cecfb350f5 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erikjv@me.com>
Date: Wed, 14 Dec 2011 10:04:34 +0100
Subject: [PATCH] Added flag to the parser to skip method bodies.

---
 include/clang-c/Index.h                  |   11 ++++++++++-
 include/clang/Frontend/ASTUnit.h         |    3 ++-
 include/clang/Frontend/FrontendOptions.h |    5 +++++
 include/clang/Parse/ParseAST.h           |    6 ++++--
 include/clang/Parse/Parser.h             |    6 ++++--
 lib/Frontend/ASTUnit.cpp                 |    6 +++++-
 lib/Frontend/FrontendAction.cpp          |    3 ++-
 lib/Parse/ParseAST.cpp                   |   10 ++++++----
 lib/Parse/ParseObjc.cpp                  |    8 +++-----
 lib/Parse/ParseStmt.cpp                  |   24 ++++++++++--------------
 lib/Parse/Parser.cpp                     |    5 +++--
 tools/libclang/CIndex.cpp                |    4 +++-
 12 files changed, 57 insertions(+), 34 deletions(-)

diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 9da6b23..07e77fa 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -1014,7 +1014,16 @@ enum CXTranslationUnit_Flags {
    * value, and its semantics. This is just an alias.
    */
   CXTranslationUnit_NestedMacroInstantiations =
-    CXTranslationUnit_NestedMacroExpansions
+    CXTranslationUnit_NestedMacroExpansions,
+
+  /**
+   * \brief Used to indicate that function/method bodies should be skipped while
+   * parsing.
+   *
+   * This option can be used to search for declarations/definitions while
+   * ignoring the usages.
+   */
+  CXTranslationUnit_SkipFunctionBodies = 0x80
 };
 
 /**
diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h
index 8feab30..45b34e2 100644
--- a/include/clang/Frontend/ASTUnit.h
+++ b/include/clang/Frontend/ASTUnit.h
@@ -735,7 +735,8 @@ public:
                                       bool PrecompilePreamble = false,
                                       TranslationUnitKind TUKind = TU_Complete,
                                       bool CacheCodeCompletionResults = false,
-                                      bool NestedMacroExpansions = true);
+                                      bool NestedMacroExpansions = true,
+                                      bool SkipFunctionBodies = false);
   
   /// \brief Reparse the source files using the same command-line options that
   /// were originally used to produce this translation unit.
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index fa6d044..d827cc1 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -74,6 +74,10 @@ public:
                                            /// unfixable errors.
   unsigned ARCMTMigrateEmitARCErrors : 1;  /// Emit ARC errors even if the
                                            /// migrator can fix them
+  unsigned SkipFunctionBodies : 1;         ///< Skip over function bodies to
+                                           /// speed up parsing in cases you do
+                                           /// not need them (e.g. with code
+                                           /// completion).
 
   enum {
     ARCMT_None,
@@ -137,6 +141,7 @@ public:
     ShowVersion = 0;
     ARCMTAction = ARCMT_None;
     ARCMTMigrateEmitARCErrors = 0;
+    SkipFunctionBodies = 0;
   }
 
   /// getInputKindForExtension - Return the appropriate input kind for a file
diff --git a/include/clang/Parse/ParseAST.h b/include/clang/Parse/ParseAST.h
index 7253870..2405a0c 100644
--- a/include/clang/Parse/ParseAST.h
+++ b/include/clang/Parse/ParseAST.h
@@ -36,11 +36,13 @@ namespace clang {
   void ParseAST(Preprocessor &pp, ASTConsumer *C,
                 ASTContext &Ctx, bool PrintStats = false,
                 TranslationUnitKind TUKind = TU_Complete,
-                CodeCompleteConsumer *CompletionConsumer = 0);
+                CodeCompleteConsumer *CompletionConsumer = 0,
+                bool SkipFunctionBodies = false);
 
   /// \brief Parse the main file known to the preprocessor, producing an 
   /// abstract syntax tree.
-  void ParseAST(Sema &S, bool PrintStats = false);
+  void ParseAST(Sema &S, bool PrintStats = false,
+                bool SkipFunctionBodies = false);
   
 }  // end namespace clang
 
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 07d21bf..df014bc 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -196,8 +196,10 @@ class Parser : public CodeCompletionHandler {
 
   IdentifierInfo *getSEHExceptKeyword();
 
+  bool SkipFunctionBodies;
+
 public:
-  Parser(Preprocessor &PP, Sema &Actions);
+  Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies);
   ~Parser();
 
   const LangOptions &getLang() const { return PP.getLangOptions(); }
@@ -1626,7 +1628,7 @@ private:
   /// unless the body contains the code-completion point.
   ///
   /// \returns true if the function body was skipped.
-  bool trySkippingFunctionBodyForCodeCompletion();
+  bool trySkippingFunctionBody();
 
   bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
                         const ParsedTemplateInfo &TemplateInfo,
diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp
index 62c557a..83bcaed 100644
--- a/lib/Frontend/ASTUnit.cpp
+++ b/lib/Frontend/ASTUnit.cpp
@@ -1858,7 +1858,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
                                       bool PrecompilePreamble,
                                       TranslationUnitKind TUKind,
                                       bool CacheCodeCompletionResults,
-                                      bool NestedMacroExpansions) {
+                                      bool NestedMacroExpansions,
+                                      bool SkipFunctionBodies) {
   if (!Diags.getPtr()) {
     // No diagnostics engine was provided, so create our own diagnostics object
     // with the default options.
@@ -1900,6 +1901,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
   // Override the resources path.
   CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
 
+  CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies;
+
   // Create the AST unit.
   llvm::OwningPtr<ASTUnit> AST;
   AST.reset(new ASTUnit(false));
@@ -2326,6 +2329,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
                                 FrontendOpts.ShowCodePatternsInCodeCompletion,
                                 FrontendOpts.ShowGlobalSymbolsInCodeCompletion);
   Clang->setCodeCompletionConsumer(AugmentedConsumer);
+  Clang->getFrontendOpts().SkipFunctionBodies = true;
 
   // If we have a precompiled preamble, try to use it. We only allow
   // the use of the precompiled preamble if we're if the completion
diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp
index 439a124..c36448f 100644
--- a/lib/Frontend/FrontendAction.cpp
+++ b/lib/Frontend/FrontendAction.cpp
@@ -408,7 +408,8 @@ void ASTFrontendAction::ExecuteAction() {
   if (!CI.hasSema())
     CI.createSema(getTranslationUnitKind(), CompletionConsumer);
 
-  ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats);
+  ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats,
+           CI.getFrontendOpts().SkipFunctionBodies);
 }
 
 ASTConsumer *
diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp
index a5c345a..bcaf789 100644
--- a/lib/Parse/ParseAST.cpp
+++ b/lib/Parse/ParseAST.cpp
@@ -38,7 +38,8 @@ using namespace clang;
 void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
                      ASTContext &Ctx, bool PrintStats,
                      TranslationUnitKind TUKind,
-                     CodeCompleteConsumer *CompletionConsumer) {
+                     CodeCompleteConsumer *CompletionConsumer,
+                     bool SkipFunctionBodies) {
 
   llvm::OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer,
                                    TUKind,
@@ -47,10 +48,10 @@ void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
   // Recover resources if we crash before exiting this method.
   llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleaupSema(S.get());
   
-  ParseAST(*S.get(), PrintStats);
+  ParseAST(*S.get(), PrintStats, SkipFunctionBodies);
 }
 
-void clang::ParseAST(Sema &S, bool PrintStats) {
+void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
   // Collect global stats on Decls/Stmts (until we have a module streamer).
   if (PrintStats) {
     Decl::CollectingStats(true);
@@ -63,7 +64,8 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
 
   ASTConsumer *Consumer = &S.getASTConsumer();
 
-  llvm::OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S));
+  llvm::OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
+                                             SkipFunctionBodies));
   Parser &P = *ParseOP.get();
 
   PrettyStackTraceParserEntry CrashInfo(P);
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index 5ac1d6c..74f26eb 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -2586,11 +2586,9 @@ Decl *Parser::ParseLexedObjCMethodDefs(LexedMethod &LM) {
   // specified Declarator for the method.
   Actions.ActOnStartOfObjCMethodDef(getCurScope(), MDecl);
     
-  if (PP.isCodeCompletionEnabled()) {
-      if (trySkippingFunctionBodyForCodeCompletion()) {
-          BodyScope.Exit();
-          return Actions.ActOnFinishFunctionBody(MDecl, 0);
-      }
+  if (SkipFunctionBodies && trySkippingFunctionBody()) {
+    BodyScope.Exit();
+    return Actions.ActOnFinishFunctionBody(MDecl, 0);
   }
     
   StmtResult FnBody(ParseCompoundStatementBody());
diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp
index da0e865..bbee9ed 100644
--- a/lib/Parse/ParseStmt.cpp
+++ b/lib/Parse/ParseStmt.cpp
@@ -1922,11 +1922,9 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) {
   assert(Tok.is(tok::l_brace));
   SourceLocation LBraceLoc = Tok.getLocation();
 
-  if (PP.isCodeCompletionEnabled()) {
-    if (trySkippingFunctionBodyForCodeCompletion()) {
-      BodyScope.Exit();
-      return Actions.ActOnFinishFunctionBody(Decl, 0);
-    }
+  if (SkipFunctionBodies && trySkippingFunctionBody()) {
+    BodyScope.Exit();
+    return Actions.ActOnFinishFunctionBody(Decl, 0);
   }
 
   PrettyDeclStackTraceEntry CrashInfo(Actions, Decl, LBraceLoc,
@@ -1964,11 +1962,9 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
   else
     Actions.ActOnDefaultCtorInitializers(Decl);
 
-  if (PP.isCodeCompletionEnabled()) {
-    if (trySkippingFunctionBodyForCodeCompletion()) {
-      BodyScope.Exit();
-      return Actions.ActOnFinishFunctionBody(Decl, 0);
-    }
+  if (SkipFunctionBodies && trySkippingFunctionBody()) {
+    BodyScope.Exit();
+    return Actions.ActOnFinishFunctionBody(Decl, 0);
   }
 
   SourceLocation LBraceLoc = Tok.getLocation();
@@ -1983,17 +1979,17 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) {
   return Actions.ActOnFinishFunctionBody(Decl, FnBody.take());
 }
 
-bool Parser::trySkippingFunctionBodyForCodeCompletion() {
+bool Parser::trySkippingFunctionBody() {
   assert(Tok.is(tok::l_brace));
-  assert(PP.isCodeCompletionEnabled() &&
-         "Should only be called when in code-completion mode");
+  assert(SkipFunctionBodies &&
+         "Should only be called when SkipFunctionBodies is enabled");
 
   // We're in code-completion mode. Skip parsing for all function bodies unless
   // the body contains the code-completion point.
   TentativeParsingAction PA(*this);
   ConsumeBrace();
   if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false,
-                /*StopAtCodeCompletion=*/true)) {
+                /*StopAtCodeCompletion=*/PP.isCodeCompletionEnabled())) {
     PA.Commit();
     return true;
   }
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 95ce065..1dcf85e 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -31,10 +31,11 @@ IdentifierInfo *Parser::getSEHExceptKeyword() {
   return Ident__except;
 }
 
-Parser::Parser(Preprocessor &pp, Sema &actions)
+Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies)
   : PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
     GreaterThanIsOperator(true), ColonIsSacred(false), 
-    InMessageExpression(false), TemplateParameterDepth(0) {
+    InMessageExpression(false), TemplateParameterDepth(0),
+    SkipFunctionBodies(SkipFunctionBodies) {
   Tok.setKind(tok::eof);
   Actions.CurScope = 0;
   NumCachedScopes = 0;
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index a0f6f68..e085c1f 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -2445,6 +2445,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
     = (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete;
   bool CacheCodeCompetionResults
     = options & CXTranslationUnit_CacheCompletionResults;
+  bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
   
   // Configure the diagnostics.
   DiagnosticOptions DiagOpts;
@@ -2530,7 +2531,8 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
                                  PrecompilePreamble,
                                  TUKind,
                                  CacheCodeCompetionResults,
-                                 NestedMacroExpansions));
+                                 NestedMacroExpansions,
+                                 SkipFunctionBodies));
 
   if (NumErrors != Diags->getClient()->getNumErrors()) {
     // Make sure to check that 'Unit' is non-NULL.
-- 
1.7.5.4

