From 96865fb14c773fbc314c0533e3286300d37ee406 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Thu, 17 May 2018 07:31:29 +0000 Subject: [PATCH] [libclang] Allow skipping function bodies in preamble only As an addition to CXTranslationUnit_SkipFunctionBodies, provide the new option CXTranslationUnit_LimitSkipFunctionBodiesToPreamble, which constraints the skipping of functions bodies to the preamble only. Function bodies in the main file are not affected if this option is set. Skipping function bodies only in the preamble is what clangd already does and the introduced flag implements it for libclang clients. Patch by Nikolai Kosjar. Differential Revision: https://reviews.llvm.org/D45815 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@332578 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang-c/Index.h | 22 +++++--- include/clang/Frontend/ASTUnit.h | 64 ++++++++++++---------- lib/Frontend/ASTUnit.cpp | 83 ++++++++++++++++------------- test/Parser/skip-function-bodies.h | 3 ++ test/Parser/skip-function-bodies.mm | 37 ++++++++----- tools/c-index-test/c-index-test.c | 14 ++--- tools/libclang/CIndex.cpp | 24 +++++---- 7 files changed, 148 insertions(+), 99 deletions(-) create mode 100644 test/Parser/skip-function-bodies.h diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 3fee13a40b..4e6fcce8ad 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -1321,13 +1321,21 @@ enum CXTranslationUnit_Flags { */ 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. * diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index af67dd1aed..8ce4492b37 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -78,12 +78,15 @@ class TargetInfo; 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 @@ private: 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 @@ private: 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 @@ public: 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. diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 9b672d9755..0ce7adb620 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1268,13 +1268,13 @@ makeStandaloneDiagnostic(const LangOptions &LangOpts, /// \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 @@ ASTUnit::getMainBufferWithPrecompiledPreamble( &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 @@ ASTUnit *ASTUnit::LoadFromCommandLine( 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 @@ ASTUnit *ASTUnit::LoadFromCommandLine( 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 @@ ASTUnit *ASTUnit::LoadFromCommandLine( 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; diff --git a/test/Parser/skip-function-bodies.h b/test/Parser/skip-function-bodies.h new file mode 100644 index 0000000000..250026cd62 --- /dev/null +++ b/test/Parser/skip-function-bodies.h @@ -0,0 +1,3 @@ +int header1(int t) { + return t; +} diff --git a/test/Parser/skip-function-bodies.mm b/test/Parser/skip-function-bodies.mm index e5b7b2adf8..b2fe485a1d 100644 --- a/test/Parser/skip-function-bodies.mm +++ b/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 @@ public: @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 @@ void J() { // 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] diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index d57ac4f9f6..828cb98c1f 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -79,12 +79,14 @@ static unsigned getDefaultParsingOptions() { 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 { diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index c348506545..9b682da71e 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -3377,15 +3377,21 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, = (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) -- 2.40.0