aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang-c/Index.h11
-rw-r--r--include/clang/Frontend/ASTUnit.h1
-rw-r--r--include/clang/Frontend/FrontendOptions.h5
-rw-r--r--include/clang/Parse/ParseAST.h6
-rw-r--r--include/clang/Parse/Parser.h6
-rw-r--r--lib/Frontend/ASTUnit.cpp5
-rw-r--r--lib/Frontend/CompilerInstance.cpp1
-rw-r--r--lib/Frontend/FrontendAction.cpp3
-rw-r--r--lib/Parse/ParseAST.cpp14
-rw-r--r--lib/Parse/ParseObjc.cpp8
-rw-r--r--lib/Parse/ParseStmt.cpp24
-rw-r--r--lib/Parse/Parser.cpp5
-rw-r--r--test/Parser/skip-function-bodies.mm45
-rw-r--r--tools/c-index-test/c-index-test.c2
-rw-r--r--tools/libclang/CIndex.cpp4
15 files changed, 106 insertions, 34 deletions
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<ASTUnit> *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<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
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<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();
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<DiagnosticsEngine>
@@ -2605,6 +2606,7 @@ static void clang_parseTranslationUnit_Impl(void *UserData) {
TUKind,
CacheCodeCompetionResults,
/*AllowPCHWithCompilerErrors=*/true,
+ SkipFunctionBodies,
&ErrUnit));
if (NumErrors != Diags->getClient()->getNumErrors()) {