Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -1321,13 +1321,21 @@ */ CXTranslationUnit_KeepGoing = 0x200, - /** - * Sets the preprocessor in a mode for parsing a single file only. - */ - CXTranslationUnit_SingleFileParse = 0x400 -}; - -/** + /** + * Sets the preprocessor in a mode for parsing a single file only. + */ + 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, +}; + +/** * Returns the set of flags that is suitable for parsing a translation * unit that is being edited. * Index: include/clang/Frontend/ASTUnit.h =================================================================== --- include/clang/Frontend/ASTUnit.h +++ include/clang/Frontend/ASTUnit.h @@ -78,12 +78,15 @@ namespace vfs { class FileSystem; - -} // namespace vfs - -/// Utility class for loading a ASTContext from an AST file. -class ASTUnit { -public: + +} // namespace vfs + +/// \brief Enumerates the available scopes for skipping function bodies. +enum class SkipFunctionBodiesScope { None, Preamble, PreambleAndMainFile }; + +/// Utility class for loading a ASTContext from an AST file. +class ASTUnit { +public: struct StandaloneFixIt { std::pair RemoveRange; std::pair InsertFromRange; @@ -345,12 +348,15 @@ unsigned CurrentTopLevelHashValue = 0; /// Bit used by CIndex to mark when a translation unit may be in an - /// inconsistent state, and is not safe to free. - unsigned UnsafeToFree : 1; - - /// Cache any "global" code-completion results, so that we can avoid - /// recomputing them with each completion. - void CacheCodeCompletionResults(); + /// inconsistent state, and is not safe to free. + unsigned UnsafeToFree : 1; + + /// \brief Enumerator specifying the scope for skipping function bodies. + SkipFunctionBodiesScope SkipFunctionBodies = SkipFunctionBodiesScope::None; + + /// Cache any "global" code-completion results, so that we can avoid + /// recomputing them with each completion. + void CacheCodeCompletionResults(); /// Clear out and deallocate void ClearCachedCompletionResults(); @@ -360,13 +366,13 @@ bool Parse(std::shared_ptr PCHContainerOps, std::unique_ptr OverrideMainBuffer, IntrusiveRefCntPtr VFS); - - std::unique_ptr getMainBufferWithPrecompiledPreamble( - std::shared_ptr PCHContainerOps, - const CompilerInvocation &PreambleInvocationIn, - IntrusiveRefCntPtr VFS, bool AllowRebuild = true, - unsigned MaxLines = 0); - void RealizeTopLevelDeclsFromPreamble(); + + std::unique_ptr getMainBufferWithPrecompiledPreamble( + std::shared_ptr PCHContainerOps, + CompilerInvocation &PreambleInvocationIn, + IntrusiveRefCntPtr VFS, bool AllowRebuild = true, + unsigned MaxLines = 0); + void RealizeTopLevelDeclsFromPreamble(); /// Transfers ownership of the objects (like SourceManager) from /// \param CI to this ASTUnit. @@ -798,15 +804,17 @@ ArrayRef RemappedFiles = None, bool RemappedFilesKeepOriginalName = true, unsigned PrecompilePreambleAfterNParses = 0, - 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, - llvm::Optional ModuleFormat = llvm::None, - std::unique_ptr *ErrAST = nullptr, - IntrusiveRefCntPtr VFS = nullptr); + TranslationUnitKind TUKind = TU_Complete, + bool CacheCodeCompletionResults = false, + bool IncludeBriefCommentsInCodeCompletion = false, + bool AllowPCHWithCompilerErrors = false, + SkipFunctionBodiesScope SkipFunctionBodies = + SkipFunctionBodiesScope::None, + bool SingleFileParse = false, bool UserFilesAreVolatile = false, + bool ForSerialization = false, + llvm::Optional ModuleFormat = llvm::None, + std::unique_ptr *ErrAST = nullptr, + IntrusiveRefCntPtr VFS = nullptr); /// Reparse the source files using the same command-line options that /// were originally used to produce this translation unit. Index: lib/Frontend/ASTUnit.cpp =================================================================== --- lib/Frontend/ASTUnit.cpp +++ lib/Frontend/ASTUnit.cpp @@ -1268,13 +1268,13 @@ /// \returns If the precompiled preamble can be used, returns a newly-allocated /// buffer that should be used in place of the main file when doing so. /// Otherwise, returns a NULL pointer. -std::unique_ptr -ASTUnit::getMainBufferWithPrecompiledPreamble( - std::shared_ptr PCHContainerOps, - const CompilerInvocation &PreambleInvocationIn, - IntrusiveRefCntPtr VFS, bool AllowRebuild, - unsigned MaxLines) { - auto MainFilePath = +std::unique_ptr +ASTUnit::getMainBufferWithPrecompiledPreamble( + std::shared_ptr PCHContainerOps, + CompilerInvocation &PreambleInvocationIn, + IntrusiveRefCntPtr VFS, bool AllowRebuild, + unsigned MaxLines) { + auto MainFilePath = PreambleInvocationIn.getFrontendOpts().Inputs[0].getFile(); std::unique_ptr MainFileBuffer = getBufferForFileHandlingRemapping(PreambleInvocationIn, VFS.get(), @@ -1335,15 +1335,24 @@ &NewPreambleDiagsStandalone); // We did not previously compute a preamble, or it can't be reused anyway. - SimpleTimer PreambleTimer(WantTiming); - PreambleTimer.setOutput("Precompiling preamble"); - - llvm::ErrorOr NewPreamble = PrecompiledPreamble::Build( - PreambleInvocationIn, MainFileBuffer.get(), Bounds, *Diagnostics, VFS, - PCHContainerOps, /*StoreInMemory=*/false, Callbacks); - if (NewPreamble) { - Preamble = std::move(*NewPreamble); - PreambleRebuildCounter = 1; + SimpleTimer PreambleTimer(WantTiming); + PreambleTimer.setOutput("Precompiling preamble"); + + const bool PreviousSkipFunctionBodies = + PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies; + if (SkipFunctionBodies == SkipFunctionBodiesScope::Preamble) + PreambleInvocationIn.getFrontendOpts().SkipFunctionBodies = true; + + 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; } else { switch (static_cast(NewPreamble.getError().value())) { case BuildPreambleError::CouldntCreateTempFile: @@ -1688,13 +1697,13 @@ std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, bool OnlyLocalDecls, bool CaptureDiagnostics, - ArrayRef RemappedFiles, bool RemappedFilesKeepOriginalName, - unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, - bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, - bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies, - bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization, - llvm::Optional ModuleFormat, std::unique_ptr *ErrAST, - IntrusiveRefCntPtr VFS) { + ArrayRef RemappedFiles, bool RemappedFilesKeepOriginalName, + unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, + bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, + bool AllowPCHWithCompilerErrors, SkipFunctionBodiesScope SkipFunctionBodies, + bool SingleFileParse, bool UserFilesAreVolatile, bool ForSerialization, + llvm::Optional ModuleFormat, std::unique_ptr *ErrAST, + IntrusiveRefCntPtr VFS) { assert(Diags.get() && "no DiagnosticsEngine was provided"); SmallVector StoredDiagnostics; @@ -1721,13 +1730,14 @@ PPOpts.AllowPCHWithCompilerErrors = AllowPCHWithCompilerErrors; PPOpts.SingleFileParseMode = SingleFileParse; - // Override the resources path. - CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; - - CI->getFrontendOpts().SkipFunctionBodies = SkipFunctionBodies; - - if (ModuleFormat) - CI->getHeaderSearchOpts().ModuleFormat = ModuleFormat.getValue(); + // Override the resources path. + CI->getHeaderSearchOpts().ResourceDir = ResourceFilesPath; + + CI->getFrontendOpts().SkipFunctionBodies = + SkipFunctionBodies == SkipFunctionBodiesScope::PreambleAndMainFile; + + if (ModuleFormat) + CI->getHeaderSearchOpts().ModuleFormat = ModuleFormat.getValue(); // Create the AST unit. std::unique_ptr AST; @@ -1747,12 +1757,13 @@ AST->TUKind = TUKind; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->IncludeBriefCommentsInCodeCompletion - = IncludeBriefCommentsInCodeCompletion; - AST->UserFilesAreVolatile = UserFilesAreVolatile; - AST->Invocation = CI; - if (ForSerialization) - AST->WriterData.reset(new ASTWriterData(*AST->PCMCache)); - // Zero out now to ease cleanup during crash recovery. + = IncludeBriefCommentsInCodeCompletion; + AST->UserFilesAreVolatile = UserFilesAreVolatile; + AST->Invocation = CI; + AST->SkipFunctionBodies = SkipFunctionBodies; + if (ForSerialization) + AST->WriterData.reset(new ASTWriterData(*AST->PCMCache)); + // Zero out now to ease cleanup during crash recovery. CI = nullptr; Diags = nullptr; Index: test/Parser/skip-function-bodies.h =================================================================== --- test/Parser/skip-function-bodies.h +++ test/Parser/skip-function-bodies.h @@ -0,0 +1,3 @@ +int header1(int t) { + return t; +} Index: test/Parser/skip-function-bodies.mm =================================================================== --- test/Parser/skip-function-bodies.mm +++ test/Parser/skip-function-bodies.mm @@ -1,7 +1,7 @@ -// RUN: env CINDEXTEST_SKIP_FUNCTION_BODIES=1 c-index-test -test-load-source all %s | FileCheck %s - -class A { - class B {}; +#include "skip-function-bodies.h" + +class A { + class B {}; public: A() { @@ -24,12 +24,13 @@ @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] + class K {}; +} + +// 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] // CHECK: skip-function-bodies.mm:7:3: CXXConstructor=A:7:3 (default constructor) 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] @@ -40,6 +41,16 @@ // 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] +// 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] + +// 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-PREAMBLE %s +// CHECK-PREAMBLE: skip-function-bodies.h:1:5: FunctionDecl=header1:1:5 Extent=[1:1 - 1:19] +// CHECK-PREAMBLE-NOT: skip-function-bodies.h:2:3: ReturnStmt= Extent=[2:3 - 2:11] +// CHECK-PREAMBLE: skip-function-bodies.mm:8:12: StructDecl=C:8:12 (Definition) Extent=[8:5 - 10:6] +// CHECK-PREAMBLE: 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 @@ -79,12 +79,14 @@ if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS")) options |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; if (getenv("CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE")) - options |= CXTranslationUnit_CreatePreambleOnFirstParse; - if (getenv("CINDEXTEST_KEEP_GOING")) - options |= CXTranslationUnit_KeepGoing; - - return options; -} + options |= CXTranslationUnit_CreatePreambleOnFirstParse; + if (getenv("CINDEXTEST_KEEP_GOING")) + options |= CXTranslationUnit_KeepGoing; + if (getenv("CINDEXTEST_LIMIT_SKIP_FUNCTION_BODIES_TO_PREAMBLE")) + options |= CXTranslationUnit_LimitSkipFunctionBodiesToPreamble; + + return options; +} static void ModifyPrintingPolicyAccordingToEnv(CXPrintingPolicy Policy) { struct Mapping { Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -3377,15 +3377,21 @@ = (options & (CXTranslationUnit_Incomplete | CXTranslationUnit_SingleFileParse))? TU_Prefix : TU_Complete; bool CacheCodeCompletionResults - = options & CXTranslationUnit_CacheCompletionResults; - bool IncludeBriefCommentsInCodeCompletion - = options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; - bool SkipFunctionBodies = options & CXTranslationUnit_SkipFunctionBodies; - bool SingleFileParse = options & CXTranslationUnit_SingleFileParse; - bool ForSerialization = options & CXTranslationUnit_ForSerialization; - - // Configure the diagnostics. - IntrusiveRefCntPtr + = options & CXTranslationUnit_CacheCompletionResults; + bool IncludeBriefCommentsInCodeCompletion + = options & CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; + bool SingleFileParse = options & CXTranslationUnit_SingleFileParse; + bool ForSerialization = options & CXTranslationUnit_ForSerialization; + SkipFunctionBodiesScope SkipFunctionBodies = SkipFunctionBodiesScope::None; + if (options & CXTranslationUnit_SkipFunctionBodies) { + SkipFunctionBodies = + (options & CXTranslationUnit_LimitSkipFunctionBodiesToPreamble) + ? SkipFunctionBodiesScope::Preamble + : SkipFunctionBodiesScope::PreambleAndMainFile; + } + + // Configure the diagnostics. + IntrusiveRefCntPtr Diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); if (options & CXTranslationUnit_KeepGoing)