From: Erik Verbruggen Date: Thu, 12 Apr 2012 10:11:59 +0000 (+0000) Subject: Added a flag to the parser to skip method bodies. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6a91d385618ea4d28236c496f540a26877c95525;p=clang Added a flag to the parser to skip method bodies. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154584 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index b297e54512..13ba6ba2ae 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -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 }; /** diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 2fd87c941e..5e4ecadd69 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -741,6 +741,7 @@ public: TranslationUnitKind TUKind = TU_Complete, bool CacheCodeCompletionResults = false, bool AllowPCHWithCompilerErrors = false, + bool SkipFunctionBodies = false, OwningPtr *ErrAST = 0); /// \brief Reparse the source files using the same command-line options that diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h index 49a9ec189d..a051d7ff62 100644 --- a/include/clang/Frontend/FrontendOptions.h +++ b/include/clang/Frontend/FrontendOptions.h @@ -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; } diff --git a/include/clang/Parse/ParseAST.h b/include/clang/Parse/ParseAST.h index 725387024e..2405a0ccd6 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 9d784c9e96..0e5e8c7d88 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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, diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 15500989e8..e32fa630a7 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1882,6 +1882,7 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool AllowPCHWithCompilerErrors, + bool SkipFunctionBodies, OwningPtr *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 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 diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 60273816d9..27cfc9d542 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -88,6 +88,7 @@ void CompilerInstance::setASTConsumer(ASTConsumer *Value) { void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { CompletionConsumer.reset(Value); + getFrontendOpts().SkipFunctionBodies = true; } // Diagnostics diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index fccee89e06..da4bdfabc0 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -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() { } diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index 236689184d..d1c2624f8c 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -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 S(new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer)); // Recover resources if we crash before exiting this method. - llvm::CrashRecoveryContextCleanupRegistrar CleaupSema(S.get()); + llvm::CrashRecoveryContextCleanupRegistrar 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 ParseOP(new Parser(S.getPreprocessor(), S)); + OwningPtr 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 - CleaupParser(ParseOP.get()); + CleanupParser(ParseOP.get()); S.getPreprocessor().EnterMainSourceFile(); P.Initialize(); diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 11417fb66f..789a8ae7a9 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -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()); diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index 9f6a3a03da..fdb9788667 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -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; } diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index bc515cab5d..054a8fd6a5 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/test/Parser/skip-function-bodies.mm b/test/Parser/skip-function-bodies.mm new file mode 100644 index 0000000000..8462f69f3a --- /dev/null +++ b/test/Parser/skip-function-bodies.mm @@ -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] diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 04e7a506e2..573e6dc314 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -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; } diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 808de3d253..ece91ce20e 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -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 @@ -2605,6 +2606,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) { TUKind, CacheCodeCompetionResults, /*AllowPCHWithCompilerErrors=*/true, + SkipFunctionBodies, &ErrUnit)); if (NumErrors != Diags->getClient()->getNumErrors()) {