* 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
};
/**
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
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,
ShowVersion = 0;
ARCMTAction = ARCMT_None;
ARCMTMigrateEmitARCErrors = 0;
+ SkipFunctionBodies = 0;
ObjCMTAction = ObjCMT_None;
}
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
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(); }
/// 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,
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
// Override the resources path.
CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath;
+ CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies;
+
// Create the AST unit.
OwningPtr<ASTUnit> AST;
AST.reset(new ASTUnit(false));
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
void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) {
CompletionConsumer.reset(Value);
+ getFrontendOpts().SkipFunctionBodies = true;
}
// Diagnostics
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() { }
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();
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();
// 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());
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,
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();
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;
}
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;
--- /dev/null
+// 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]
options |= CXTranslationUnit_CacheCompletionResults;
if (getenv("CINDEXTEST_COMPLETION_NO_CACHING"))
options &= ~CXTranslationUnit_CacheCompletionResults;
+ if (getenv("CINDEXTEST_SKIP_FUNCTION_BODIES"))
+ options |= CXTranslationUnit_SkipFunctionBodies;
return options;
}
= (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete;
bool CacheCodeCompetionResults
= options & CXTranslationUnit_CacheCompletionResults;
-
+ bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies;
+
// Configure the diagnostics.
DiagnosticOptions DiagOpts;
IntrusiveRefCntPtr<DiagnosticsEngine>
TUKind,
CacheCodeCompetionResults,
/*AllowPCHWithCompilerErrors=*/true,
+ SkipFunctionBodies,
&ErrUnit));
if (NumErrors != Diags->getClient()->getNumErrors()) {