From 426bfa0c4555cc2b415f1a607252c373a69f3197 Mon Sep 17 00:00:00 2001 From: Ben Langmuir <blangmuir@apple.com> Date: Tue, 15 Apr 2014 18:16:25 +0000 Subject: [PATCH] Honour -ivfsoverlay in ASTUnit to match clang This allows code indexing, etc. to use the VFS in the same way as the compiler. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206309 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Frontend/ASTUnit.h | 2 +- include/clang/Frontend/CompilerInvocation.h | 8 +++++ lib/Frontend/ASTUnit.cpp | 35 ++++++++++++++++----- lib/Frontend/CompilerInvocation.cpp | 29 ++++++++++++++++- lib/Frontend/FrontendAction.cpp | 31 +++++------------- test/Index/Inputs/base_module_needs_vfs.h | 1 + test/Index/Inputs/module.map | 6 ++++ test/Index/Inputs/module_needs_vfs.h | 4 +++ test/Index/Inputs/vfsoverlay.yaml | 18 +++++++++++ test/Index/index-module-with-vfs.m | 26 +++++++++++++++ tools/libclang/CIndexCodeCompletion.cpp | 31 +++++++----------- tools/libclang/Indexing.cpp | 5 +++ 12 files changed, 143 insertions(+), 53 deletions(-) create mode 100644 test/Index/Inputs/base_module_needs_vfs.h create mode 100644 test/Index/Inputs/module.map create mode 100644 test/Index/Inputs/module_needs_vfs.h create mode 100644 test/Index/Inputs/vfsoverlay.yaml create mode 100644 test/Index/index-module-with-vfs.m diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index 3a26df3ef32..f8cb14e29d1 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -499,7 +499,7 @@ public: bool hasSema() const { return (bool)TheSema; } Sema &getSema() const { assert(TheSema && "ASTUnit does not have a Sema object!"); - return *TheSema; + return *TheSema; } const FileManager &getFileManager() const { return *FileMgr; } diff --git a/include/clang/Frontend/CompilerInvocation.h b/include/clang/Frontend/CompilerInvocation.h index f64773c2c4b..7258dbeb2ab 100644 --- a/include/clang/Frontend/CompilerInvocation.h +++ b/include/clang/Frontend/CompilerInvocation.h @@ -204,6 +204,14 @@ public: /// @} }; +namespace vfs { + class FileSystem; +} + +IntrusiveRefCntPtr<vfs::FileSystem> +createVFSFromCompilerInvocation(const CompilerInvocation &CI, + DiagnosticsEngine &Diags); + } // end namespace clang #endif diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index c4f7596e003..5035dac53cf 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -692,7 +692,8 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; AST->Diagnostics = Diags; - AST->FileMgr = new FileManager(FileSystemOpts); + IntrusiveRefCntPtr<vfs::FileSystem> VFS = vfs::getRealFileSystem(); + AST->FileMgr = new FileManager(FileSystemOpts, VFS); AST->UserFilesAreVolatile = UserFilesAreVolatile; AST->SourceMgr = new SourceManager(AST->getDiagnostics(), AST->getFileManager(), @@ -1093,10 +1094,9 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { "IR inputs not support here!"); // Configure the various subsystems. - // FIXME: Should we retain the previous file manager? LangOpts = &Clang->getLangOpts(); FileSystemOpts = Clang->getFileSystemOpts(); - FileMgr = new FileManager(FileSystemOpts); + // Re-use the existing FileManager SourceMgr = new SourceManager(getDiagnostics(), *FileMgr, UserFilesAreVolatile); TheSema.reset(); @@ -1598,9 +1598,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( TopLevelDecls.clear(); TopLevelDeclsInPreamble.clear(); PreambleDiagnostics.clear(); - + + IntrusiveRefCntPtr<vfs::FileSystem> VFS = + createVFSFromCompilerInvocation(Clang->getInvocation(), getDiagnostics()); + if (!VFS) + return nullptr; + // Create a file manager object to provide access to and cache the filesystem. - Clang->setFileManager(new FileManager(Clang->getFileSystemOpts())); + Clang->setFileManager(new FileManager(Clang->getFileSystemOpts(), VFS)); // Create the source manager. Clang->setSourceManager(new SourceManager(getDiagnostics(), @@ -1758,7 +1763,11 @@ ASTUnit *ASTUnit::create(CompilerInvocation *CI, AST->Diagnostics = Diags; AST->Invocation = CI; AST->FileSystemOpts = CI->getFileSystemOpts(); - AST->FileMgr = new FileManager(AST->FileSystemOpts); + IntrusiveRefCntPtr<vfs::FileSystem> VFS = + createVFSFromCompilerInvocation(*CI, *Diags); + if (!VFS) + return nullptr; + AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); AST->UserFilesAreVolatile = UserFilesAreVolatile; AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr, UserFilesAreVolatile); @@ -1781,6 +1790,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( // Create the AST unit. OwnAST.reset(create(CI, Diags, CaptureDiagnostics, UserFilesAreVolatile)); AST = OwnAST.get(); + if (!AST) + return nullptr; } if (!ResourceFilesPath.empty()) { @@ -1950,7 +1961,11 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocation(CompilerInvocation *CI, = IncludeBriefCommentsInCodeCompletion; AST->Invocation = CI; AST->FileSystemOpts = CI->getFileSystemOpts(); - AST->FileMgr = new FileManager(AST->FileSystemOpts); + IntrusiveRefCntPtr<vfs::FileSystem> VFS = + createVFSFromCompilerInvocation(*CI, *Diags); + if (!VFS) + return nullptr; + AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); AST->UserFilesAreVolatile = UserFilesAreVolatile; // Recover resources if we crash before exiting this method. @@ -2017,7 +2032,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine( AST->Diagnostics = Diags; Diags = 0; // Zero out now to ease cleanup during crash recovery. AST->FileSystemOpts = CI->getFileSystemOpts(); - AST->FileMgr = new FileManager(AST->FileSystemOpts); + IntrusiveRefCntPtr<vfs::FileSystem> VFS = + createVFSFromCompilerInvocation(*CI, *Diags); + if (!VFS) + return nullptr; + AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; AST->TUKind = TUKind; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index b22ea9a07f6..6177a96fa7b 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -8,12 +8,12 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/CompilerInvocation.h" -#include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/Version.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/Util.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/LangStandard.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/HeaderSearchOptions.h" @@ -1907,4 +1907,31 @@ void BuryPointer(const void *Ptr) { return; GraveYard[Idx] = Ptr; } + +IntrusiveRefCntPtr<vfs::FileSystem> +createVFSFromCompilerInvocation(const CompilerInvocation &CI, + DiagnosticsEngine &Diags) { + if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) + return vfs::getRealFileSystem(); + + IntrusiveRefCntPtr<vfs::OverlayFileSystem> + Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem())); + // earlier vfs files are on the bottom + for (const std::string &File : CI.getHeaderSearchOpts().VFSOverlayFiles) { + std::unique_ptr<llvm::MemoryBuffer> Buffer; + if (llvm::errc::success != llvm::MemoryBuffer::getFile(File, Buffer)) { + Diags.Report(diag::err_missing_vfs_overlay_file) << File; + return IntrusiveRefCntPtr<vfs::FileSystem>(); + } + + IntrusiveRefCntPtr<vfs::FileSystem> FS = + vfs::getVFSFromYAML(Buffer.release(), /*DiagHandler*/0); + if (!FS.getPtr()) { + Diags.Report(diag::err_invalid_vfs_overlay) << File; + return IntrusiveRefCntPtr<vfs::FileSystem>(); + } + Overlay->pushOverlay(FS); + } + return Overlay; } +} // end namespace clang diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index dc4dd89371a..dfe3d85ba73 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -211,30 +211,13 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, return true; } - if (!CI.getHeaderSearchOpts().VFSOverlayFiles.empty()) { - IntrusiveRefCntPtr<vfs::OverlayFileSystem> - Overlay(new vfs::OverlayFileSystem(vfs::getRealFileSystem())); - // earlier vfs files are on the bottom - const std::vector<std::string> &Files = - CI.getHeaderSearchOpts().VFSOverlayFiles; - for (std::vector<std::string>::const_iterator I = Files.begin(), - E = Files.end(); - I != E; ++I) { - std::unique_ptr<llvm::MemoryBuffer> Buffer; - if (llvm::errc::success != llvm::MemoryBuffer::getFile(*I, Buffer)) { - CI.getDiagnostics().Report(diag::err_missing_vfs_overlay_file) << *I; - goto failure; - } - - IntrusiveRefCntPtr<vfs::FileSystem> FS = - vfs::getVFSFromYAML(Buffer.release(), /*DiagHandler*/ 0); - if (!FS.getPtr()) { - CI.getDiagnostics().Report(diag::err_invalid_vfs_overlay) << *I; - goto failure; - } - Overlay->pushOverlay(FS); - } - CI.setVirtualFileSystem(Overlay); + if (!CI.hasVirtualFileSystem()) { + if (IntrusiveRefCntPtr<vfs::FileSystem> VFS = + createVFSFromCompilerInvocation(CI.getInvocation(), + CI.getDiagnostics())) + CI.setVirtualFileSystem(VFS); + else + goto failure; } // Set up the file and source managers, if needed. diff --git a/test/Index/Inputs/base_module_needs_vfs.h b/test/Index/Inputs/base_module_needs_vfs.h new file mode 100644 index 00000000000..9a7a2445a86 --- /dev/null +++ b/test/Index/Inputs/base_module_needs_vfs.h @@ -0,0 +1 @@ +void base_module_needs_vfs(void); diff --git a/test/Index/Inputs/module.map b/test/Index/Inputs/module.map new file mode 100644 index 00000000000..8f24840c81f --- /dev/null +++ b/test/Index/Inputs/module.map @@ -0,0 +1,6 @@ +// See vfsoverlay.yaml +module ModuleNeedsVFS { + header "ModuleNeedsVFS.h" + export * +} +framework module * { } diff --git a/test/Index/Inputs/module_needs_vfs.h b/test/Index/Inputs/module_needs_vfs.h new file mode 100644 index 00000000000..d79cc3f0d3a --- /dev/null +++ b/test/Index/Inputs/module_needs_vfs.h @@ -0,0 +1,4 @@ +@import BaseModuleNeedsVFS; +inline void module_needs_vfs(void) { + base_module_needs_vfs(); +} diff --git a/test/Index/Inputs/vfsoverlay.yaml b/test/Index/Inputs/vfsoverlay.yaml new file mode 100644 index 00000000000..95b00bef7d0 --- /dev/null +++ b/test/Index/Inputs/vfsoverlay.yaml @@ -0,0 +1,18 @@ +{ + 'version': 0, + 'roots': [ + { 'name': 'OUT_DIR', 'type': 'directory', + 'contents': [ + { 'name': 'module.map', 'type': 'file', + 'external-contents': 'INPUT_DIR/module.map' + }, + { 'name': 'ModuleNeedsVFS.h', 'type': 'file', + 'external-contents': 'INPUT_DIR/module_needs_vfs.h' + }, + { 'name': 'BaseModuleNeedsVFS.framework/Headers/BaseModuleNeedsVFS.h', 'type': 'file', + 'external-contents': 'INPUT_DIR/base_module_needs_vfs.h' + }, + ] + } + ] +} diff --git a/test/Index/index-module-with-vfs.m b/test/Index/index-module-with-vfs.m new file mode 100644 index 00000000000..f3ca60cf941 --- /dev/null +++ b/test/Index/index-module-with-vfs.m @@ -0,0 +1,26 @@ +// REQUIRES: shell +@import ModuleNeedsVFS; + +void foo() { + module_needs_vfs(); + base_module_needs_vfs(); +} + +// RUN: rm -rf %t.cache +// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay.yaml > %t.yaml +// RUN: c-index-test -index-file %s -fmodules-cache-path=%t.cache -fmodules -F %t -I %t \ +// RUN: -ivfsoverlay %t.yaml -Xclang -fdisable-module-hash | FileCheck %s + +// CHECK: [importedASTFile]: {{.*}}ModuleNeedsVFS.pcm | loc: 2:1 | name: "ModuleNeedsVFS" | isImplicit: 0 +// CHECK: [indexEntityReference]: kind: function | name: module_needs_vfs +// CHECK: [indexEntityReference]: kind: function | name: base_module_needs_vfs + +// RUN: c-index-test -index-tu %t.cache/ModuleNeedsVFS.pcm | FileCheck %s -check-prefix=CHECK-MOD + +// CHECK-MOD: [ppIncludedFile]: {{.*}}module_needs_vfs.h +// CHECK-MOD: [importedASTFile]: {{.*}}BaseModuleNeedsVFS.pcm +// CHECK-MOD: [indexEntityReference]: kind: function | name: base_module_needs_vfs + +// RUN: c-index-test -index-tu %t.cache/BaseModuleNeedsVFS.pcm | FileCheck %s -check-prefix=CHECK-MOD2 + +// CHECK-MOD2: [ppIncludedFile]: {{.*}}base_module_needs_vfs.h diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp index 591294599dc..23fdf93b76f 100644 --- a/tools/libclang/CIndexCodeCompletion.cpp +++ b/tools/libclang/CIndexCodeCompletion.cpp @@ -249,7 +249,7 @@ namespace { /// AllocatedCXCodeCompleteResults outlives the CXTranslationUnit, so we can /// not rely on the StringPool in the TU. struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { - AllocatedCXCodeCompleteResults(const FileSystemOptions& FileSystemOpts); + AllocatedCXCodeCompleteResults(IntrusiveRefCntPtr<FileManager> FileMgr); ~AllocatedCXCodeCompleteResults(); /// \brief Diagnostics produced while performing code completion. @@ -263,8 +263,6 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { /// \brief Language options used to adjust source locations. LangOptions LangOpts; - FileSystemOptions FileSystemOpts; - /// \brief File manager, used for diagnostics. IntrusiveRefCntPtr<FileManager> FileMgr; @@ -318,20 +316,15 @@ struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults { static std::atomic<unsigned> CodeCompletionResultObjects; AllocatedCXCodeCompleteResults::AllocatedCXCodeCompleteResults( - const FileSystemOptions& FileSystemOpts) - : CXCodeCompleteResults(), - DiagOpts(new DiagnosticOptions), - Diag(new DiagnosticsEngine( - IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), - &*DiagOpts)), - FileSystemOpts(FileSystemOpts), - FileMgr(new FileManager(FileSystemOpts)), - SourceMgr(new SourceManager(*Diag, *FileMgr)), - CodeCompletionAllocator(new clang::GlobalCodeCompletionAllocator), - Contexts(CXCompletionContext_Unknown), - ContainerKind(CXCursor_InvalidCode), - ContainerIsIncomplete(1) -{ + IntrusiveRefCntPtr<FileManager> FileMgr) + : CXCodeCompleteResults(), + DiagOpts(new DiagnosticOptions), + Diag(new DiagnosticsEngine( + IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts)), + FileMgr(FileMgr), SourceMgr(new SourceManager(*Diag, *FileMgr)), + CodeCompletionAllocator(new clang::GlobalCodeCompletionAllocator), + Contexts(CXCompletionContext_Unknown), + ContainerKind(CXCursor_InvalidCode), ContainerIsIncomplete(1) { if (getenv("LIBCLANG_OBJTRACKING")) fprintf(stderr, "+++ %u completion results\n", ++CodeCompletionResultObjects); @@ -709,8 +702,8 @@ void clang_codeCompleteAt_Impl(void *UserData) { } // Parse the resulting source file to find code-completion results. - AllocatedCXCodeCompleteResults *Results = - new AllocatedCXCodeCompleteResults(AST->getFileSystemOpts()); + AllocatedCXCodeCompleteResults *Results = new AllocatedCXCodeCompleteResults( + &AST->getFileManager()); Results->Results = 0; Results->NumResults = 0; diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp index 55e6e798737..47ba97bd9a6 100644 --- a/tools/libclang/Indexing.cpp +++ b/tools/libclang/Indexing.cpp @@ -610,6 +610,11 @@ static void clang_indexSourceFile_Impl(void *UserData) { ASTUnit *Unit = ASTUnit::create(CInvok.getPtr(), Diags, CaptureDiagnostics, /*UserFilesAreVolatile=*/true); + if (!Unit) { + ITUI->result = CXError_InvalidArguments; + return; + } + std::unique_ptr<CXTUOwner> CXTU( new CXTUOwner(MakeCXTranslationUnit(CXXIdx, Unit))); -- GitLab