]> granicus.if.org Git - clang/commitdiff
Added a flag to the parser to skip method bodies.
authorErik Verbruggen <erikjv@me.com>
Thu, 12 Apr 2012 10:11:59 +0000 (10:11 +0000)
committerErik Verbruggen <erikjv@me.com>
Thu, 12 Apr 2012 10:11:59 +0000 (10:11 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154584 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/clang-c/Index.h
include/clang/Frontend/ASTUnit.h
include/clang/Frontend/FrontendOptions.h
include/clang/Parse/ParseAST.h
include/clang/Parse/Parser.h
lib/Frontend/ASTUnit.cpp
lib/Frontend/CompilerInstance.cpp
lib/Frontend/FrontendAction.cpp
lib/Parse/ParseAST.cpp
lib/Parse/ParseObjc.cpp
lib/Parse/ParseStmt.cpp
lib/Parse/Parser.cpp
test/Parser/skip-function-bodies.mm [new file with mode: 0644]
tools/c-index-test/c-index-test.c
tools/libclang/CIndex.cpp

index b297e545122993de91edc10f31fea486e7993c2e..13ba6ba2ae167ff8006533700f7d887516d7c5d1 100644 (file)
@@ -1069,7 +1069,16 @@ enum CXTranslationUnit_Flags {
    * Note: this is a *temporary* option that is available only while
    * we are testing C++ precompiled preamble support. It is deprecated.
    */
-  CXTranslationUnit_CXXChainedPCH = 0x20
+  CXTranslationUnit_CXXChainedPCH = 0x20,
+
+  /**
+   * \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 = 0x40
 };
 
 /**
index 2fd87c941e1f41c098e581e9ff1ec9646af5a761..5e4ecadd6900985d5451320a20856c084631fb57 100644 (file)
@@ -741,6 +741,7 @@ public:
                                       TranslationUnitKind TUKind = TU_Complete,
                                       bool CacheCodeCompletionResults = false,
                                       bool AllowPCHWithCompilerErrors = false,
+                                      bool SkipFunctionBodies = false,
                                       OwningPtr<ASTUnit> *ErrAST = 0);
   
   /// \brief Reparse the source files using the same command-line options that
index 49a9ec189d646e9144ba45d9d117ecb940d3671d..a051d7ff629edf7b27ca95699108410dbbe86a3b 100644 (file)
@@ -112,6 +112,10 @@ public:
   unsigned FixToTemporaries : 1;           ///< Apply fixes to temporary files.
   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,
@@ -188,6 +192,7 @@ public:
     ShowVersion = 0;
     ARCMTAction = ARCMT_None;
     ARCMTMigrateEmitARCErrors = 0;
+    SkipFunctionBodies = 0;
     ObjCMTAction = ObjCMT_None;
   }
 
index 725387024e1ffe167a9527ed9bd2c55869dabae8..2405a0ccd6536236da3e521418a4db712590c777 100644 (file)
@@ -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
 
index 9d784c9e9637a450906fb0d85558f14b14b78b07..0e5e8c7d88c2c827cf6124226688cb848be4252f 100644 (file)
@@ -198,8 +198,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 &getLangOpts() const { return PP.getLangOpts(); }
@@ -1671,7 +1673,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,
index 15500989e87f89c268d2de3eca1b343202e2f5d1..e32fa630a737fa7ee2e1759d5b91cc28551bc107 100644 (file)
@@ -1882,6 +1882,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
                                       TranslationUnitKind TUKind,
                                       bool CacheCodeCompletionResults,
                                       bool AllowPCHWithCompilerErrors,
+                                      bool SkipFunctionBodies,
                                       OwningPtr<ASTUnit> *ErrAST) {
   if (!Diags.getPtr()) {
     // No diagnostics engine was provided, so create our own diagnostics object
@@ -1925,6 +1926,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin,
   // Override the resources path.
   CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
 
+  CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies;
+
   // Create the AST unit.
   OwningPtr<ASTUnit> AST;
   AST.reset(new ASTUnit(false));
@@ -2365,6 +2368,8 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column,
                                 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
   // point is within the main file, after the end of the precompiled
index 60273816d910c0c0f31d8ac37f0a3a2d5cdef7bf..27cfc9d54256bfd9ac717e073b2c5ffb2fc13c96 100644 (file)
@@ -88,6 +88,7 @@ void CompilerInstance::setASTConsumer(ASTConsumer *Value) {
 
 void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
   CompletionConsumer.reset(Value);
+  getFrontendOpts().SkipFunctionBodies = true;
 }
 
 // Diagnostics
index fccee89e06f58ca716edf3c26db2e13c3e522903..da4bdfabc067276a200063a1cee0a792a797fa7b 100644 (file)
@@ -412,7 +412,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);
 }
 
 void PluginASTAction::anchor() { }
index 236689184df77e623a000024a48c73ed28e4b081..d1c2624f8cb3e00dc2cc44cbed5da4fd47ef6aa6 100644 (file)
@@ -38,19 +38,20 @@ using namespace clang;
 void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
                      ASTContext &Ctx, bool PrintStats,
                      TranslationUnitKind TUKind,
-                     CodeCompleteConsumer *CompletionConsumer) {
+                     CodeCompleteConsumer *CompletionConsumer,
+                     bool SkipFunctionBodies) {
 
   OwningPtr<Sema> S(new Sema(PP, Ctx, *Consumer,
                                    TUKind,
                                    CompletionConsumer));
 
   // Recover resources if we crash before exiting this method.
-  llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleaupSema(S.get());
+  llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(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::EnableStatistics();
@@ -63,14 +64,15 @@ void clang::ParseAST(Sema &S, bool PrintStats) {
 
   ASTConsumer *Consumer = &S.getASTConsumer();
 
-  OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S));
+  OwningPtr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
+                                       SkipFunctionBodies));
   Parser &P = *ParseOP.get();
 
   PrettyStackTraceParserEntry CrashInfo(P);
 
   // Recover resources if we crash before exiting this method.
   llvm::CrashRecoveryContextCleanupRegistrar<Parser>
-    CleaupParser(ParseOP.get());
+    CleanupParser(ParseOP.get());
 
   S.getPreprocessor().EnterMainSourceFile();
   P.Initialize();
index 11417fb66f350e28161e6e2c68c3eb317e23dd82..789a8ae7a93a6ce2339ea69acd5f9da442bf8a01 100644 (file)
@@ -2811,11 +2811,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());
index 9f6a3a03daaae640906ee58b57eda6ab0aa169e2..fdb9788667622e5bd5431e44f87fc24f0d7b4ba6 100644 (file)
@@ -1958,11 +1958,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,
@@ -2002,11 +2000,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();
@@ -2023,17 +2019,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;
   }
index bc515cab5d537547bf2c04552382de50f2430c83..054a8fd6a55fcc46ad8c69f8e0ff5c1a0c4eec19 100644 (file)
@@ -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/test/Parser/skip-function-bodies.mm b/test/Parser/skip-function-bodies.mm
new file mode 100644 (file)
index 0000000..8462f69
--- /dev/null
@@ -0,0 +1,45 @@
+// RUN: env CINDEXTEST_SKIP_FUNCTION_BODIES=1 c-index-test -test-load-source all %s | FileCheck %s
+
+class A {
+  class B {};
+
+public:
+  A() {
+    struct C {
+      void d() {}
+    };
+  }
+
+  typedef B E;
+};
+
+@interface F
+- (void) G;
+@end
+@implementation F
+- (void) G {
+  typedef A H;
+  class I {};
+}
+@end
+
+void J() {
+  class K {};
+}
+
+// CHECK: skip-function-bodies.mm:3:7: ClassDecl=A:3:7 (Definition) Extent=[3:1 - 14:2]
+// CHECK: skip-function-bodies.mm:4:9: ClassDecl=B:4:9 (Definition) Extent=[4:3 - 4:13]
+// CHECK: skip-function-bodies.mm:6:1: CXXAccessSpecifier=:6:1 (Definition) Extent=[6:1 - 6:8]
+// CHECK: skip-function-bodies.mm:7:3: CXXConstructor=A:7:3 Extent=[7:3 - 7:6]
+// CHECK-NOT: skip-function-bodies.mm:8:12: StructDecl=C:8:12 (Definition) Extent=[8:5 - 10:6]
+// CHECK-NOT: skip-function-bodies.mm:9:12: CXXMethod=d:9:12 (Definition) Extent=[9:7 - 9:18]
+// CHECK: skip-function-bodies.mm:13:13: TypedefDecl=E:13:13 (Definition) Extent=[13:3 - 13:14]
+// CHECK: skip-function-bodies.mm:13:11: TypeRef=class A::B:4:9 Extent=[13:11 - 13:12]
+// CHECK: skip-function-bodies.mm:16:12: ObjCInterfaceDecl=F:16:12 Extent=[16:1 - 18:5]
+// CHECK: skip-function-bodies.mm:17:10: ObjCInstanceMethodDecl=G:17:10 Extent=[17:1 - 17:12]
+// CHECK: skip-function-bodies.mm:19:17: ObjCImplementationDecl=F:19:17 (Definition) Extent=[19:1 - 24:2]
+// CHECK: skip-function-bodies.mm:20:10: ObjCInstanceMethodDecl=G:20:10 Extent=[20:1 - 20:13]
+// CHECK-NOT: skip-function-bodies.mm:21:13: TypedefDecl=H:21:13 (Definition) Extent=[21:3 - 21:14]
+// CHECK-NOT: skip-function-bodies.mm:21:11: TypeRef=class A:3:7 Extent=[21:11 - 21:12]
+// CHECK: skip-function-bodies.mm:26:6: FunctionDecl=J:26:6 Extent=[26:1 - 26:9]
+// CHECK-NOT: skip-function-bodies.mm:27:9: ClassDecl=K:27:9 (Definition) Extent=[27:3 - 27:13]
index 04e7a506e2386ec13df6c066f6c6b47ae6bb71d0..573e6dc3141f8e1726df2b6a42b73e457608ab5f 100644 (file)
@@ -39,6 +39,8 @@ static unsigned getDefaultParsingOptions() {
     options |= CXTranslationUnit_CacheCompletionResults;
   if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
     options &= ~CXTranslationUnit_CacheCompletionResults;
+  if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
+    options |= CXTranslationUnit_SkipFunctionBodies;
   
   return options;
 }
index 808de3d253ced5e67dd377036e4dccf6f3fe60a1..ece91ce20e837aba8ab24b1e7e62197f3575ebf3 100644 (file)
@@ -2521,7 +2521,8 @@ 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;
   IntrusiveRefCntPtr<DiagnosticsEngine>
@@ -2605,6 +2606,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
                                  TUKind,
                                  CacheCodeCompetionResults,
                                  /*AllowPCHWithCompilerErrors=*/true,
+                                 SkipFunctionBodies,
                                  &ErrUnit));
 
   if (NumErrors != Diags->getClient()->getNumErrors()) {