Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -1324,7 +1324,24 @@ /** * \brief Sets the preprocessor in a mode for parsing a single file only. */ - CXTranslationUnit_SingleFileParse = 0x400 + CXTranslationUnit_SingleFileParse = 0x400, + + /** + * \brief Used in combination with CXTranslationUnit_SkipFunctionBodies to + * constrain the skipping of function bodies to the preamble. + * + * The function bodies of the main file are not skipped. + */ + CXTranslationUnit_LimitSkipFunctionBodiesToPreamble = 0x800, + + /** + * \brief Used in combination with CXTranslationUnit_SkipFunctionBodies to + * exclude template function bodies from being skipped. + * + * Parsing template function bodies allows diagnostics for wrong/incomplete + * template instantiations. + */ + CXTranslationUnit_LimitSkipFunctionBodiesToNonTemplates = 0x1000, }; /** Index: include/clang/Frontend/ASTUnit.h =================================================================== --- include/clang/Frontend/ASTUnit.h +++ include/clang/Frontend/ASTUnit.h @@ -101,6 +101,12 @@ std::vector FixIts; }; + struct SkipFunctionBodiesOptions { + SkipFunctionBodiesOptions() {} + enum { None, MainFileAndPreamble, Preamble } Scope = None; + bool LimitToNonTemplateFunctions = false; + }; + private: std::shared_ptr LangOpts; IntrusiveRefCntPtr Diagnostics; @@ -363,9 +369,11 @@ std::unique_ptr getMainBufferWithPrecompiledPreamble( std::shared_ptr PCHContainerOps, - const CompilerInvocation &PreambleInvocationIn, - IntrusiveRefCntPtr VFS, bool AllowRebuild = true, - unsigned MaxLines = 0); + CompilerInvocation &PreambleInvocationIn, + IntrusiveRefCntPtr VFS, + SkipFunctionBodiesOptions SkipFunctionBodiesOpts = + SkipFunctionBodiesOptions(), + bool AllowRebuild = true, unsigned MaxLines = 0); void RealizeTopLevelDeclsFromPreamble(); /// \brief Transfers ownership of the objects (like SourceManager) from @@ -693,6 +701,7 @@ bool LoadFromCompilerInvocation( std::shared_ptr PCHContainerOps, unsigned PrecompilePreambleAfterNParses, + SkipFunctionBodiesOptions SkipFunctionBodiesOpts, IntrusiveRefCntPtr VFS); public: @@ -801,9 +810,11 @@ TranslationUnitKind TUKind = TU_Complete, bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, - bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false, - bool SingleFileParse = false, - bool UserFilesAreVolatile = false, bool ForSerialization = false, + bool AllowPCHWithCompilerErrors = false, + SkipFunctionBodiesOptions SkipFunctionBodiesOpts = + SkipFunctionBodiesOptions(), + bool SingleFileParse = false, bool UserFilesAreVolatile = false, + bool ForSerialization = false, llvm::Optional ModuleFormat = llvm::None, std::unique_ptr *ErrAST = nullptr, IntrusiveRefCntPtr VFS = nullptr); @@ -821,6 +832,8 @@ /// contain any translation-unit information, false otherwise. bool Reparse(std::shared_ptr PCHContainerOps, ArrayRef RemappedFiles = None, + SkipFunctionBodiesOptions SkipFunctionBodiesOpts = + SkipFunctionBodiesOptions(), IntrusiveRefCntPtr VFS = nullptr); /// \brief Free data that will be re-generated on the next parse. Index: include/clang/Frontend/FrontendOptions.h =================================================================== --- include/clang/Frontend/FrontendOptions.h +++ include/clang/Frontend/FrontendOptions.h @@ -11,6 +11,7 @@ #define LLVM_CLANG_FRONTEND_FRONTENDOPTIONS_H #include "clang/Frontend/CommandLineSourceLoc.h" +#include "clang/Frontend/SkipFunctionBodies.h" #include "clang/Serialization/ModuleFileExtension.h" #include "clang/Sema/CodeCompleteOptions.h" #include "llvm/ADT/StringRef.h" @@ -274,10 +275,6 @@ /// Emit ARC errors even if the migrator can fix them. unsigned ARCMTMigrateEmitARCErrors : 1; - /// Skip over function bodies to speed up parsing in cases you do not need - /// them (e.g. with code completion). - unsigned SkipFunctionBodies : 1; - /// Whether we can use the global module index if available. unsigned UseGlobalModuleIndex : 1; @@ -302,6 +299,8 @@ /// Whether timestamps should be written to the produced PCH file. unsigned IncludeTimestamps : 1; + SkipFunctionBodiesKind SkipFunctionBodies; + CodeCompleteOptions CodeCompleteOpts; enum { @@ -444,10 +443,11 @@ ShowStats(false), ShowTimers(false), ShowVersion(false), FixWhatYouCan(false), FixOnlyWarnings(false), FixAndRecompile(false), FixToTemporaries(false), ARCMTMigrateEmitARCErrors(false), - SkipFunctionBodies(false), UseGlobalModuleIndex(true), - GenerateGlobalModuleIndex(true), ASTDumpDecls(false), - ASTDumpLookups(false), BuildingImplicitModule(false), - ModulesEmbedAllFiles(false), IncludeTimestamps(true) {} + UseGlobalModuleIndex(true), GenerateGlobalModuleIndex(true), + ASTDumpDecls(false), ASTDumpLookups(false), + BuildingImplicitModule(false), ModulesEmbedAllFiles(false), + IncludeTimestamps(true), + SkipFunctionBodies(SkipFunctionBodiesKind::None) {} /// getInputKindForExtension - Return the appropriate input kind for a file /// extension. For example, "c" would return InputKind::C. Index: include/clang/Frontend/SkipFunctionBodies.h =================================================================== --- /dev/null +++ include/clang/Frontend/SkipFunctionBodies.h @@ -0,0 +1,25 @@ +//===--- FrontendOptions.h --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_FRONTEND_SKIPFUNCTIONBODIES_H +#define LLVM_CLANG_FRONTEND_SKIPFUNCTIONBODIES_H + +namespace clang { + +/// Skip over function bodies to speed up parsing in cases you do not need +/// them (e.g. with code completion). +enum class SkipFunctionBodiesKind { + None, + All, + AllExceptTemplates, +}; + +} // end namespace clang + +#endif Index: include/clang/Parse/ParseAST.h =================================================================== --- include/clang/Parse/ParseAST.h +++ include/clang/Parse/ParseAST.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_PARSE_PARSEAST_H #include "clang/Basic/LangOptions.h" +#include "clang/Frontend/SkipFunctionBodies.h" namespace clang { class Preprocessor; @@ -36,16 +37,17 @@ /// \param SkipFunctionBodies Whether to skip parsing of function bodies. /// This option can be used, for example, to speed up searches for /// declarations/definitions when indexing. - void ParseAST(Preprocessor &pp, ASTConsumer *C, - ASTContext &Ctx, bool PrintStats = false, - TranslationUnitKind TUKind = TU_Complete, - CodeCompleteConsumer *CompletionConsumer = nullptr, - bool SkipFunctionBodies = false); + void ParseAST( + Preprocessor &pp, ASTConsumer *C, ASTContext &Ctx, + bool PrintStats = false, TranslationUnitKind TUKind = TU_Complete, + CodeCompleteConsumer *CompletionConsumer = nullptr, + SkipFunctionBodiesKind SkipFunctionBodies = SkipFunctionBodiesKind::None); /// \brief Parse the main file known to the preprocessor, producing an /// abstract syntax tree. - void ParseAST(Sema &S, bool PrintStats = false, - bool SkipFunctionBodies = false); + void ParseAST( + Sema &S, bool PrintStats = false, + SkipFunctionBodiesKind SkipFunctionBodies = SkipFunctionBodiesKind::None); } // end namespace clang Index: include/clang/Parse/Parser.h =================================================================== --- include/clang/Parse/Parser.h +++ include/clang/Parse/Parser.h @@ -18,6 +18,7 @@ #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/OperatorPrecedence.h" #include "clang/Basic/Specifiers.h" +#include "clang/Frontend/SkipFunctionBodies.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" @@ -261,7 +262,7 @@ /// /// This option can be used, for example, to speed up searches for /// declarations/definitions when indexing. - bool SkipFunctionBodies; + SkipFunctionBodiesKind SkipFunctionBodies; /// The location of the expression statement that is being parsed right now. /// Used to determine if an expression that is being parsed is a statement or @@ -269,7 +270,8 @@ SourceLocation ExprStatementTokLoc; public: - Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies); + Parser(Preprocessor &PP, Sema &Actions, + SkipFunctionBodiesKind SkipFunctionBodies); ~Parser() override; const LangOptions &getLangOpts() const { return PP.getLangOpts(); } Index: lib/Frontend/ASTUnit.cpp =================================================================== --- lib/Frontend/ASTUnit.cpp +++ lib/Frontend/ASTUnit.cpp @@ -1271,8 +1271,9 @@ std::unique_ptr ASTUnit::getMainBufferWithPrecompiledPreamble( std::shared_ptr PCHContainerOps, - const CompilerInvocation &PreambleInvocationIn, - IntrusiveRefCntPtr VFS, bool AllowRebuild, + CompilerInvocation &PreambleInvocationIn, + IntrusiveRefCntPtr VFS, + SkipFunctionBodiesOptions SkipFunctionBodiesOpts, bool AllowRebuild, unsigned MaxLines) { auto MainFilePath = PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile(); @@ -1338,9 +1339,22 @@ SimpleTimer PreambleTimer(WantTiming); PreambleTimer.setOutput("Precompiling preamble"); + const SkipFunctionBodiesKind PreviousSkipFunctionBodies = + PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies; + if (SkipFunctionBodiesOpts.Scope == SkipFunctionBodiesOptions::Preamble) { + PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies = + SkipFunctionBodiesOpts.LimitToNonTemplateFunctions + ? SkipFunctionBodiesKind::AllExceptTemplates + : SkipFunctionBodiesKind::All; + } + llvm::ErrorOr NewPreamble = PrecompiledPreamble::Build( PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS, PCHContainerOps, /*StoreInMemory=*/false, Callbacks); + + PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies = + PreviousSkipFunctionBodies; + if (NewPreamble) { Preamble = std::move(*NewPreamble); PreambleRebuildCounter = 1; @@ -1615,6 +1629,7 @@ bool ASTUnit::LoadFromCompilerInvocation( std::shared_ptr PCHContainerOps, unsigned PrecompilePreambleAfterNParses, + SkipFunctionBodiesOptions SkipFunctionBodiesOpts, IntrusiveRefCntPtr VFS) { if (!Invocation) return true; @@ -1630,8 +1645,8 @@ std::unique_ptr OverrideMainBuffer; if (PrecompilePreambleAfterNParses > 0) { PreambleRebuildCounter = PrecompilePreambleAfterNParses; - OverrideMainBuffer = - getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS); + OverrideMainBuffer = getMainBufferWithPrecompiledPreamble( + PCHContainerOps, *Invocation, VFS, SkipFunctionBodiesOpts); getDiagnostics().Reset(); ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); } @@ -1678,6 +1693,7 @@ if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), PrecompilePreambleAfterNParses, + SkipFunctionBodiesOptions(), AST->FileMgr->getVirtualFileSystem())) return nullptr; return AST; @@ -1691,8 +1707,9 @@ ArrayRef RemappedFiles, bool RemappedFilesKeepOriginalName, unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, - bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies, - bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization, + bool AllowPCHWithCompilerErrors, + SkipFunctionBodiesOptions SkipFunctionBodiesOpts, bool SingleFileParse, + bool UserFilesAreVolatile, bool ForSerialization, llvm::Optional ModuleFormat, std::unique_ptr *ErrAST, IntrusiveRefCntPtr VFS) { assert(Diags.get() && "no DiagnosticsEngine was provided"); @@ -1724,7 +1741,14 @@ // Override the resources path. CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; - CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies; + if (SkipFunctionBodiesOpts.Scope == SkipFunctionBodiesOptions::MainFileAndPreamble) { + CI->getFrontendOpts().SkipFunctionBodies = + SkipFunctionBodiesOpts.LimitToNonTemplateFunctions + ? SkipFunctionBodiesKind::AllExceptTemplates + : SkipFunctionBodiesKind::All; + } else { + CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodiesKind::None; + } if (ModuleFormat) CI->getHeaderSearchOpts().ModuleFormat = ModuleFormat.getValue(); @@ -1762,6 +1786,7 @@ if (AST->LoadFromCompilerInvocation(std::move(PCHContainerOps), PrecompilePreambleAfterNParses, + SkipFunctionBodiesOpts, VFS)) { // Some error occurred, if caller wants to examine diagnostics, pass it the // ASTUnit. @@ -1777,6 +1802,7 @@ bool ASTUnit::Reparse(std::shared_ptr PCHContainerOps, ArrayRef RemappedFiles, + SkipFunctionBodiesOptions SkipFunBodiesOpts, IntrusiveRefCntPtr VFS) { if (!Invocation) return true; @@ -1806,8 +1832,8 @@ // build a precompiled preamble, do so now. std::unique_ptr OverrideMainBuffer; if (Preamble || PreambleRebuildCounter > 0) - OverrideMainBuffer = - getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation, VFS); + OverrideMainBuffer = getMainBufferWithPrecompiledPreamble( + PCHContainerOps, *Invocation, VFS, SkipFunBodiesOpts); // Clear out the diagnostics state. FileMgr.reset(); @@ -2203,7 +2229,8 @@ llvm::sys::fs::UniqueID MainID = MainStatus->getUniqueID(); if (CompleteFileID == MainID && Line > 1) OverrideMainBuffer = getMainBufferWithPrecompiledPreamble( - PCHContainerOps, Inv, VFS, false, Line - 1); + PCHContainerOps, Inv, VFS, SkipFunctionBodiesOptions(), false, + Line - 1); } } } Index: lib/Parse/ParseAST.cpp =================================================================== --- lib/Parse/ParseAST.cpp +++ lib/Parse/ParseAST.cpp @@ -100,7 +100,7 @@ ASTContext &Ctx, bool PrintStats, TranslationUnitKind TUKind, CodeCompleteConsumer *CompletionConsumer, - bool SkipFunctionBodies) { + SkipFunctionBodiesKind SkipFunctionBodies) { std::unique_ptr S( new Sema(PP, Ctx, *Consumer, TUKind, CompletionConsumer)); @@ -111,7 +111,8 @@ ParseAST(*S.get(), PrintStats, SkipFunctionBodies); } -void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { +void clang::ParseAST(Sema &S, bool PrintStats, + SkipFunctionBodiesKind SkipFunctionBodies) { // Collect global stats on Decls/Stmts (until we have a module streamer). if (PrintStats) { Decl::EnableStatistics(); Index: lib/Parse/ParseCXXInlineMethods.cpp =================================================================== --- lib/Parse/ParseCXXInlineMethods.cpp +++ lib/Parse/ParseCXXInlineMethods.cpp @@ -101,8 +101,8 @@ return FnD; } - if (SkipFunctionBodies && (!FnD || Actions.canSkipFunctionBody(FnD)) && - trySkippingFunctionBody()) { + if (SkipFunctionBodies != SkipFunctionBodiesKind::None && + (!FnD || Actions.canSkipFunctionBody(FnD)) && trySkippingFunctionBody()) { Actions.ActOnSkippedFunctionBody(FnD); return FnD; } Index: lib/Parse/ParseObjc.cpp =================================================================== --- lib/Parse/ParseObjc.cpp +++ lib/Parse/ParseObjc.cpp @@ -2634,7 +2634,8 @@ /// StashAwayMethodOrFunctionBodyTokens - Consume the tokens and store them /// for later parsing. void Parser::StashAwayMethodOrFunctionBodyTokens(Decl *MDecl) { - if (SkipFunctionBodies && (!MDecl || Actions.canSkipFunctionBody(MDecl)) && + if (SkipFunctionBodies != SkipFunctionBodiesKind::None && + (!MDecl || Actions.canSkipFunctionBody(MDecl)) && trySkippingFunctionBody()) { Actions.ActOnSkippedFunctionBody(MDecl); return; Index: lib/Parse/Parser.cpp =================================================================== --- lib/Parse/Parser.cpp +++ lib/Parse/Parser.cpp @@ -47,12 +47,17 @@ return Ident__except; } -Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) - : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), - GreaterThanIsOperator(true), ColonIsSacred(false), - InMessageExpression(false), TemplateParameterDepth(0), - ParsingInObjCContainer(false) { - SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies; +Parser::Parser(Preprocessor &pp, Sema &actions, + SkipFunctionBodiesKind skipFunctionBodies) + : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), + GreaterThanIsOperator(true), ColonIsSacred(false), + InMessageExpression(false), TemplateParameterDepth(0), + ParsingInObjCContainer(false) { + + if (pp.isCodeCompletionEnabled()) + SkipFunctionBodies = SkipFunctionBodiesKind::All; + else + SkipFunctionBodies = skipFunctionBodies; Tok.startToken(); Tok.setKind(tok::eof); Actions.CurScope = nullptr; @@ -1100,6 +1105,19 @@ } } + bool ShouldSkipFunctionBody = false; + switch (SkipFunctionBodies) { + case SkipFunctionBodiesKind::All: + ShouldSkipFunctionBody = true; + break; + case SkipFunctionBodiesKind::AllExceptTemplates: + ShouldSkipFunctionBody = TemplateInfo.Kind != ParsedTemplateInfo::Template; + break; + case SkipFunctionBodiesKind::None: + default: + ShouldSkipFunctionBody = false; + } + // In delayed template parsing mode, for function template we consume the // tokens and store them for late parsing at the end of the translation unit. if (getLangOpts().DelayedTemplateParsing && Tok.isNot(tok::equal) && @@ -1117,7 +1135,7 @@ D.complete(DP); D.getMutableDeclSpec().abort(); - if (SkipFunctionBodies && (!DP || Actions.canSkipFunctionBody(DP)) && + if (ShouldSkipFunctionBody && (!DP || Actions.canSkipFunctionBody(DP)) && trySkippingFunctionBody()) { BodyScope.Exit(); return Actions.ActOnSkippedFunctionBody(DP); @@ -1217,7 +1235,7 @@ return Res; } - if (SkipFunctionBodies && (!Res || Actions.canSkipFunctionBody(Res)) && + if (ShouldSkipFunctionBody && (!Res || Actions.canSkipFunctionBody(Res)) && trySkippingFunctionBody()) { BodyScope.Exit(); Actions.ActOnSkippedFunctionBody(Res); Index: test/Parser/skip-function-bodies.h =================================================================== --- /dev/null +++ test/Parser/skip-function-bodies.h @@ -0,0 +1,8 @@ +int header1(int t) { + return t; +} + +template +T header2(T t) { + return t; +} Index: test/Parser/skip-function-bodies.mm =================================================================== --- test/Parser/skip-function-bodies.mm +++ test/Parser/skip-function-bodies.mm @@ -1,4 +1,4 @@ -// RUN: env CINDEXTEST_SKIP_FUNCTION_BODIES=1 c-index-test -test-load-source all %s | FileCheck %s +#include "skip-function-bodies.h" class A { class B {}; @@ -27,6 +27,12 @@ class K {}; } +template +T g(T t) { + return t; +} + +// RUN: env CINDEXTEST_SKIP_FUNCTION_BODIES=1 c-index-test -test-load-source all %s | FileCheck %s // 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] @@ -43,3 +49,48 @@ // 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] +// CHECK: skip-function-bodies.mm:31:3: FunctionTemplate=g:31:3 Extent=[30:1 - 31:9] +// CHECK: skip-function-bodies.mm:30:20: TemplateTypeParameter=T:30:20 (Definition) Extent=[30:11 - 30:21] [access=public] +// CHECK: skip-function-bodies.mm:31:1: TypeRef=T:30:20 Extent=[31:1 - 31:2] +// CHECK: skip-function-bodies.mm:31:7: ParmDecl=t:31:7 (Definition) Extent=[31:5 - 31:8] +// CHECK: skip-function-bodies.mm:31:5: TypeRef=T:30:20 Extent=[31:5 - 31:6] +// CHECK-NOT: skip-function-bodies.mm:31:10: CompoundStmt= Extent=[31:10 - 33:2] +// CHECK-NOT: skip-function-bodies.mm:32:3: ReturnStmt= Extent=[32:3 - 32:11] +// CHECK-NOT: skip-function-bodies.mm:32:10: DeclRefExpr=t:31:7 Extent=[32:10 - 32:11] + +// RUN: env CINDEXTEST_SKIP_FUNCTION_BODIES=1 \ +// RUN: CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_NON_TEMPLATES=1 \ +// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-TEMPLATES %s +// CHECK-TEMPLATES-NOT: skip-function-bodies.mm:8:12: StructDecl=C:8:12 (Definition) Extent=[8:5 - 10:6] +// CHECK-TEMPLATES-NOT: skip-function-bodies.mm:9:12: CXXMethod=d:9:12 (Definition) Extent=[9:7 - 9:18] +// CHECK-TEMPLATES: skip-function-bodies.mm:31:3: FunctionTemplate=g:31:3 (Definition) Extent=[30:1 - 33:2] +// CHECK-TEMPLATES: skip-function-bodies.mm:30:20: TemplateTypeParameter=T:30:20 (Definition) Extent=[30:11 - 30:21] [access=public] +// CHECK-TEMPLATES: skip-function-bodies.mm:31:1: TypeRef=T:30:20 Extent=[31:1 - 31:2] +// CHECK-TEMPLATES: skip-function-bodies.mm:31:7: ParmDecl=t:31:7 (Definition) Extent=[31:5 - 31:8] +// CHECK-TEMPLATES: skip-function-bodies.mm:31:5: TypeRef=T:30:20 Extent=[31:5 - 31:6] +// CHECK-TEMPLATES: skip-function-bodies.mm:31:10: CompoundStmt= Extent=[31:10 - 33:2] +// CHECK-TEMPLATES: skip-function-bodies.mm:32:3: ReturnStmt= Extent=[32:3 - 32:11] +// CHECK-TEMPLATES: skip-function-bodies.mm:32:10: DeclRefExpr=t:31:7 Extent=[32:10 - 32:11] + +// RUN: env CINDEXTEST_EDITING=1 \ +// RUN: CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE=1 \ +// RUN: CINDEXTEST_SKIP_FUNCTION_BODIES=1 \ +// RUN: CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE=1 \ +// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-PREAMBLE1 %s +// CHECK-PREAMBLE1: skip-function-bodies.h:1:5: FunctionDecl=header1:1:5 Extent=[1:1 - 1:19] +// CHECK-PREAMBLE1-NOT: skip-function-bodies.h:2:3: ReturnStmt= Extent=[2:3 - 2:11] +// CHECK-PREAMBLE1: skip-function-bodies.mm:8:12: StructDecl=C:8:12 (Definition) Extent=[8:5 - 10:6] +// CHECK-PREAMBLE1: skip-function-bodies.mm:9:12: CXXMethod=d:9:12 (Definition) Extent=[9:7 - 9:18] + +// RUN: env CINDEXTEST_EDITING=1 \ +// RUN: CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE=1 \ +// RUN: CINDEXTEST_SKIP_FUNCTION_BODIES=1 \ +// RUN: CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE=1 \ +// RUN: CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_NON_TEMPLATES=1 \ +// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-PREAMBLE2 %s +// CHECK-PREAMBLE2: skip-function-bodies.h:1:5: FunctionDecl=header1:1:5 Extent=[1:1 - 1:19] +// CHECK-PREAMBLE2-NOT: skip-function-bodies.h:2:3: ReturnStmt= Extent=[2:3 - 2:11] +// CHECK-PREAMBLE2: skip-function-bodies.h:6:3: FunctionTemplate=header2:6:3 (Definition) Extent=[5:1 - 8:2] +// CHECK-PREAMBLE2: skip-function-bodies.h:7:3: ReturnStmt= Extent=[7:3 - 7:11] +// CHECK-PREAMBLE2: skip-function-bodies.mm:8:12: StructDecl=C:8:12 (Definition) Extent=[8:5 - 10:6] +// CHECK-PREAMBLE2: skip-function-bodies.mm:9:12: CXXMethod=d:9:12 (Definition) Extent=[9:7 - 9:18] Index: tools/c-index-test/c-index-test.c =================================================================== --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -82,6 +82,10 @@ options |= CXTranslationUnit_CreatePreambleOnFirstParse; if (getenv("CINDEXTEST_KEEP_GOING")) options |= CXTranslationUnit_KeepGoing; + if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE")) + options |= CXTranslationUnit_LimitSkipFunctionBodiesToPreamble; + if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_NON_TEMPLATES")) + options |= CXTranslationUnit_LimitSkipFunctionBodiesToNonTemplates; return options; } Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -3346,6 +3346,20 @@ Options); } +static ASTUnit::SkipFunctionBodiesOptions +skipFunctionBodiesOptionsFromParseOptions(unsigned options) { + ASTUnit::SkipFunctionBodiesOptions SkipFunctionBodiesOpts; + if (options & CXTranslationUnit_SkipFunctionBodies) { + if (options & CXTranslationUnit_LimitSkipFunctionBodiesToNonTemplates) + SkipFunctionBodiesOpts.LimitToNonTemplateFunctions = true; + SkipFunctionBodiesOpts.Scope = + (options & CXTranslationUnit_LimitSkipFunctionBodiesToPreamble) + ? ASTUnit::SkipFunctionBodiesOptions::Preamble + : ASTUnit::SkipFunctionBodiesOptions::MainFileAndPreamble; + } + return SkipFunctionBodiesOpts; +} + static CXErrorCode clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, const char *const *command_line_args, @@ -3376,9 +3390,10 @@ = options & CXTranslationUnit_CacheCompletionResults; bool IncludeBriefCommentsInCodeCompletion = options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; - bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies; bool SingleFileParse = options & CXTranslationUnit_SingleFileParse; bool ForSerialization = options & CXTranslationUnit_ForSerialization; + ASTUnit::SkipFunctionBodiesOptions SkipFunctionBodiesOpts = + skipFunctionBodiesOptionsFromParseOptions(options); // Configure the diagnostics. IntrusiveRefCntPtr @@ -3467,7 +3482,7 @@ /*CaptureDiagnostics=*/true, *RemappedFiles.get(), /*RemappedFilesKeepOriginalName=*/true, PrecompilePreambleAfterNParses, TUKind, CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion, - /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies, SingleFileParse, + /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodiesOpts, SingleFileParse, /*UserFilesAreVolatile=*/true, ForSerialization, CXXIdx->getPCHContainerOperations()->getRawReader().getFormat(), &ErrUnit)); @@ -4055,7 +4070,8 @@ } if (!CXXUnit->Reparse(CXXIdx->getPCHContainerOperations(), - *RemappedFiles.get())) + *RemappedFiles.get(), + skipFunctionBodiesOptionsFromParseOptions(TU->ParsingOptions))) return CXError_Success; if (isASTReadError(CXXUnit)) return CXError_ASTReadError; Index: tools/libclang/Indexing.cpp =================================================================== --- tools/libclang/Indexing.cpp +++ tools/libclang/Indexing.cpp @@ -540,7 +540,7 @@ bool SkipBodies = (index_options & CXIndexOpt_SkipParsedBodiesInSession) && CInvok->getLangOpts()->CPlusPlus; if (SkipBodies) - CInvok->getFrontendOpts().SkipFunctionBodies = true; + CInvok->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodiesKind::All; auto DataConsumer = std::make_shared(client_data, CB, index_options, Index: unittests/CodeGen/BufferSourceTest.cpp =================================================================== --- unittests/CodeGen/BufferSourceTest.cpp +++ unittests/CodeGen/BufferSourceTest.cpp @@ -74,7 +74,7 @@ sm.setMainFileID(sm.createFileID( llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User)); - clang::ParseAST(compiler.getSema(), false, false); + clang::ParseAST(compiler.getSema(), false, clang::SkipFunctionBodiesKind::None); } } // end anonymous namespace Index: unittests/CodeGen/CodeGenExternalTest.cpp =================================================================== --- unittests/CodeGen/CodeGenExternalTest.cpp +++ unittests/CodeGen/CodeGenExternalTest.cpp @@ -294,7 +294,7 @@ sm.setMainFileID(sm.createFileID( llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User)); - clang::ParseAST(compiler.getSema(), false, false); + clang::ParseAST(compiler.getSema(), false, clang::SkipFunctionBodiesKind::None); ASSERT_TRUE(test_codegen_fns_ran); } Index: unittests/CodeGen/IncrementalProcessingTest.cpp =================================================================== --- unittests/CodeGen/IncrementalProcessingTest.cpp +++ unittests/CodeGen/IncrementalProcessingTest.cpp @@ -143,7 +143,7 @@ Sema& S = compiler.getSema(); std::unique_ptr ParseOP(new Parser(S.getPreprocessor(), S, - /*SkipFunctionBodies*/ false)); + SkipFunctionBodiesKind::None)); Parser &P = *ParseOP.get(); std::array, 3> M; Index: unittests/CodeGen/TBAAMetadataTest.cpp =================================================================== --- unittests/CodeGen/TBAAMetadataTest.cpp +++ unittests/CodeGen/TBAAMetadataTest.cpp @@ -73,7 +73,7 @@ } const BasicBlock *compile() { - clang::ParseAST(compiler.getSema(), false, false); + clang::ParseAST(compiler.getSema(), false, clang::SkipFunctionBodiesKind::None); M = CG->GetModule(); // Do not expect more than one function definition. Index: unittests/Frontend/PCHPreambleTest.cpp =================================================================== --- unittests/Frontend/PCHPreambleTest.cpp +++ unittests/Frontend/PCHPreambleTest.cpp @@ -103,7 +103,9 @@ } bool ReparseAST(const std::unique_ptr &AST) { - bool reparseFailed = AST->Reparse(PCHContainerOpts, GetRemappedFiles(), VFS); + bool reparseFailed = + AST->Reparse(PCHContainerOpts, GetRemappedFiles(), + ASTUnit::SkipFunctionBodiesOptions(), VFS); return !reparseFailed; } Index: unittests/Lex/PPCallbacksTest.cpp =================================================================== --- unittests/Lex/PPCallbacksTest.cpp +++ unittests/Lex/PPCallbacksTest.cpp @@ -201,7 +201,7 @@ ASTConsumer Consumer; Sema S(PP, Context, Consumer); - Parser P(PP, S, false); + Parser P(PP, S, SkipFunctionBodiesKind::None); PragmaOpenCLExtensionCallbacks* Callbacks = new PragmaOpenCLExtensionCallbacks; PP.addPPCallbacks(std::unique_ptr(Callbacks)); Index: unittests/Tooling/ToolingTest.cpp =================================================================== --- unittests/Tooling/ToolingTest.cpp +++ unittests/Tooling/ToolingTest.cpp @@ -250,7 +250,7 @@ struct SkipBodyAction : public clang::ASTFrontendAction { std::unique_ptr CreateASTConsumer(CompilerInstance &Compiler, StringRef) override { - Compiler.getFrontendOpts().SkipFunctionBodies = true; + Compiler.getFrontendOpts().SkipFunctionBodies = SkipFunctionBodiesKind::All; return llvm::make_unique(); } };