diff --git a/clang-tools-extra/clang-include-fixer/IncludeFixer.h b/clang-tools-extra/clang-include-fixer/IncludeFixer.h --- a/clang-tools-extra/clang-include-fixer/IncludeFixer.h +++ b/clang-tools-extra/clang-include-fixer/IncludeFixer.h @@ -42,7 +42,7 @@ bool runInvocation(std::shared_ptr Invocation, - clang::FileManager *Files, + clang::tooling::ToolFileManager *Files, std::shared_ptr PCHContainerOps, clang::DiagnosticConsumer *Diagnostics) override; diff --git a/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp b/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp --- a/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp +++ b/clang-tools-extra/clang-include-fixer/IncludeFixer.cpp @@ -82,7 +82,7 @@ bool IncludeFixerActionFactory::runInvocation( std::shared_ptr Invocation, - clang::FileManager *Files, + clang::tooling::ToolFileManager *Files, std::shared_ptr PCHContainerOps, clang::DiagnosticConsumer *Diagnostics) { assert(Invocation->getFrontendOpts().Inputs.size() == 1); @@ -90,13 +90,13 @@ // Set up Clang. clang::CompilerInstance Compiler(PCHContainerOps); Compiler.setInvocation(std::move(Invocation)); - Compiler.setFileManager(Files); + Compiler.setFileManager(Files->getOrCreateFileManager().get()); // Create the compiler's actual diagnostics engine. We want to drop all // diagnostics here. Compiler.createDiagnostics(new clang::IgnoringDiagConsumer, /*ShouldOwnClient=*/true); - Compiler.createSourceManager(*Files); + Compiler.createSourceManager(*Files->getOrCreateFileManager()); // We abort on fatal errors so don't let a large number of errors become // fatal. A missing #include can cause thousands of errors. diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -554,7 +554,7 @@ } bool runInvocation(std::shared_ptr Invocation, - FileManager *Files, + ToolFileManager *Files, std::shared_ptr PCHContainerOps, DiagnosticConsumer *DiagConsumer) override { // Explicitly ask to define __clang_analyzer__ macro. diff --git a/clang-tools-extra/clangd/indexer/IndexerMain.cpp b/clang-tools-extra/clangd/indexer/IndexerMain.cpp --- a/clang-tools-extra/clangd/indexer/IndexerMain.cpp +++ b/clang-tools-extra/clangd/indexer/IndexerMain.cpp @@ -85,7 +85,7 @@ } bool runInvocation(std::shared_ptr Invocation, - FileManager *Files, + tooling::ToolFileManager *Files, std::shared_ptr PCHContainerOps, DiagnosticConsumer *DiagConsumer) override { disableUnsupportedOptions(*Invocation); diff --git a/clang-tools-extra/clangd/unittests/IndexActionTests.cpp b/clang-tools-extra/clangd/unittests/IndexActionTests.cpp --- a/clang-tools-extra/clangd/unittests/IndexActionTests.cpp +++ b/clang-tools-extra/clangd/unittests/IndexActionTests.cpp @@ -73,8 +73,9 @@ runIndexingAction(llvm::StringRef MainFilePath, const std::vector &ExtraArgs = {}) { IndexFileIn IndexFile; - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), InMemoryFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new clang::tooling::ToolFileManager(FileSystemOptions(), + InMemoryFileSystem)); auto Action = createStaticIndexingAction( Opts, [&](SymbolSlab S) { IndexFile.Symbols = std::move(S); }, diff --git a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp --- a/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp +++ b/clang-tools-extra/clangd/unittests/SymbolCollectorTests.cpp @@ -286,8 +286,9 @@ // HeaderCode should start with #pragma once to be treated as modular. bool runSymbolCollector(llvm::StringRef HeaderCode, llvm::StringRef MainCode, const std::vector &ExtraArgs = {}) { - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), InMemoryFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new clang::tooling::ToolFileManager(FileSystemOptions(), + InMemoryFileSystem)); auto Factory = std::make_unique( CollectorOpts, PragmaHandler.get()); diff --git a/clang-tools-extra/unittests/clang-include-fixer/IncludeFixerTest.cpp b/clang-tools-extra/unittests/clang-include-fixer/IncludeFixerTest.cpp --- a/clang-tools-extra/unittests/clang-include-fixer/IncludeFixerTest.cpp +++ b/clang-tools-extra/unittests/clang-include-fixer/IncludeFixerTest.cpp @@ -25,8 +25,9 @@ const std::vector &ExtraArgs) { llvm::IntrusiveRefCntPtr InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), InMemoryFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new clang::tooling::ToolFileManager(FileSystemOptions(), + InMemoryFileSystem)); // FIXME: Investigate why -fms-compatibility breaks tests. std::vector Args = {"include_fixer", "-fsyntax-only", "-fno-ms-compatibility", diff --git a/clang-tools-extra/unittests/clang-include-fixer/find-all-symbols/FindAllSymbolsTests.cpp b/clang-tools-extra/unittests/clang-include-fixer/find-all-symbols/FindAllSymbolsTests.cpp --- a/clang-tools-extra/unittests/clang-include-fixer/find-all-symbols/FindAllSymbolsTests.cpp +++ b/clang-tools-extra/unittests/clang-include-fixer/find-all-symbols/FindAllSymbolsTests.cpp @@ -64,8 +64,9 @@ bool runFindAllSymbols(StringRef HeaderCode, StringRef MainCode) { llvm::IntrusiveRefCntPtr InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), InMemoryFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new clang::tooling::ToolFileManager(FileSystemOptions(), + InMemoryFileSystem)); std::string FileName = "symbol.cc"; diff --git a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h --- a/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h +++ b/clang-tools-extra/unittests/clang-tidy/ClangTidyTest.h @@ -119,8 +119,9 @@ ast_matchers::MatchFinder Finder; llvm::IntrusiveRefCntPtr InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), InMemoryFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new clang::tooling::ToolFileManager(FileSystemOptions(), + InMemoryFileSystem)); SmallVector, sizeof...(CheckTypes)> Checks; tooling::ToolInvocation Invocation( diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h @@ -16,6 +16,7 @@ #include "clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h" #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" +#include "clang/Tooling/Tooling.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include @@ -79,9 +80,9 @@ /// dependencies. This filesystem persists across multiple compiler /// invocations. llvm::IntrusiveRefCntPtr DepFS; - /// The file manager that is reused across multiple invocations by this - /// worker. If null, the file manager will not be reused. - llvm::IntrusiveRefCntPtr Files; + /// The container of file managers that is reused across multiple invocations + /// by this worker. If null, the file manager will not be reused. + llvm::IntrusiveRefCntPtr Files; ScanningOutputFormat Format; /// Whether to optimize the modules' command-line arguments. bool OptimizeArgs; diff --git a/clang/include/clang/Tooling/Tooling.h b/clang/include/clang/Tooling/Tooling.h --- a/clang/include/clang/Tooling/Tooling.h +++ b/clang/include/clang/Tooling/Tooling.h @@ -65,6 +65,65 @@ class CompilationDatabase; +class ToolFileManager : public RefCountedBase { + // ToolFileManager is a container who stores file managers for each CWD + std::map> fileManagers; + FileSystemOptions FSO; + IntrusiveRefCntPtr FS; + IntrusiveRefCntPtr BaseFS; + +public: + ToolFileManager(const FileSystemOptions &FileSystemOpts, + IntrusiveRefCntPtr FS = nullptr, + IntrusiveRefCntPtr BaseFS = nullptr) + : FSO(FileSystemOpts), FS(FS), BaseFS(BaseFS) { + if (!this->FS) + this->FS = llvm::vfs::getRealFileSystem(); + if (!this->BaseFS) + this->BaseFS = this->FS; + }; + + ~ToolFileManager() = default; + + llvm::IntrusiveRefCntPtr + getOrCreateFileManager(llvm::StringRef WorkingDir = "") { + std::string Cwd; + if (WorkingDir != "") { + Cwd = WorkingDir.str(); + } else { + auto Success = FS->getCurrentWorkingDirectory(); + if (!Success) + llvm::report_fatal_error("Cannot get current working directory!\n"); + Cwd = Success.get(); + } + if (!fileManagers.count(Cwd)) { + fileManagers[Cwd] = new FileManager(FSO, FS); + } + if (WorkingDir != "") { // Set Working Dir if explicitly provided + fileManagers[Cwd]->getFileSystemOpts().WorkingDir = Cwd; + } + return fileManagers[Cwd]; + } + + void setVirtualFileSystem( + IntrusiveRefCntPtr NewFS, + IntrusiveRefCntPtr BaseFS = nullptr) { + for (auto it = fileManagers.begin(); it != fileManagers.end(); it++) + it->second->setVirtualFileSystem(NewFS); + this->FS = std::move(NewFS); + // To call FileManager::setVirtualFileSystem() directly might be unsound + // unless the BaseFS is not changed. If BaseFS is not provided, use NewFS + // instead. + if (BaseFS == nullptr) { + BaseFS = NewFS; + } + if (this->BaseFS != BaseFS) { + fileManagers.clear(); + this->BaseFS = std::move(BaseFS); + } + } +}; + /// Retrieves the flags of the `-cc1` job in `Compilation` that has only source /// files as its inputs. /// Returns nullptr if there are no such jobs or multiple of them. Note that @@ -84,7 +143,7 @@ /// Perform an action for an invocation. virtual bool runInvocation(std::shared_ptr Invocation, - FileManager *Files, + ToolFileManager *Files, std::shared_ptr PCHContainerOps, DiagnosticConsumer *DiagConsumer) = 0; }; @@ -101,7 +160,7 @@ /// Invokes the compiler with a FrontendAction created by create(). bool runInvocation(std::shared_ptr Invocation, - FileManager *Files, + ToolFileManager *Files, std::shared_ptr PCHContainerOps, DiagnosticConsumer *DiagConsumer) override; @@ -245,12 +304,13 @@ /// Callers have to ensure that they are installed in a compatible location /// (see clang driver implementation) or mapped in via mapVirtualFile. /// \param FAction The action to be executed. - /// \param Files The FileManager used for the execution. Class does not take - /// ownership. + /// \param Files The ToolFileManager used for the execution. Class does not + /// take ownership. /// \param PCHContainerOps The PCHContainerOperations for loading and creating /// clang modules. ToolInvocation(std::vector CommandLine, - std::unique_ptr FAction, FileManager *Files, + std::unique_ptr FAction, + ToolFileManager *Files, std::shared_ptr PCHContainerOps = std::make_shared()); @@ -258,11 +318,11 @@ /// /// \param CommandLine The command line arguments to clang. /// \param Action The action to be executed. - /// \param Files The FileManager used for the execution. + /// \param Files The ToolFileManager used for the execution. /// \param PCHContainerOps The PCHContainerOperations for loading and creating /// clang modules. ToolInvocation(std::vector CommandLine, ToolAction *Action, - FileManager *Files, + ToolFileManager *Files, std::shared_ptr PCHContainerOps); ~ToolInvocation(); @@ -292,7 +352,7 @@ std::vector CommandLine; ToolAction *Action; bool OwnsAction; - FileManager *Files; + ToolFileManager *Files; std::shared_ptr PCHContainerOps; DiagnosticConsumer *DiagConsumer = nullptr; DiagnosticOptions *DiagOpts = nullptr; @@ -317,15 +377,15 @@ /// clang modules. /// \param BaseFS VFS used for all underlying file accesses when running the /// tool. - /// \param Files The file manager to use for underlying file operations when - /// running the tool. + /// \param Files The container of file managers to use for underlying file + /// operations when running the tool. ClangTool(const CompilationDatabase &Compilations, ArrayRef SourcePaths, std::shared_ptr PCHContainerOps = std::make_shared(), IntrusiveRefCntPtr BaseFS = llvm::vfs::getRealFileSystem(), - IntrusiveRefCntPtr Files = nullptr); + IntrusiveRefCntPtr Files = nullptr); ~ClangTool(); @@ -373,7 +433,7 @@ /// Returns the file manager used in the tool. /// /// The file manager is shared between all translation units. - FileManager &getFiles() { return *Files; } + FileManager &getFiles() { return *Files->getOrCreateFileManager(); } llvm::ArrayRef getSourcePaths() const { return SourcePaths; } @@ -384,7 +444,7 @@ llvm::IntrusiveRefCntPtr OverlayFileSystem; llvm::IntrusiveRefCntPtr InMemoryFileSystem; - llvm::IntrusiveRefCntPtr Files; + llvm::IntrusiveRefCntPtr Files; // Contains a list of pairs (, ). std::vector> MappedFileContents; diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -146,7 +146,7 @@ OptimizeArgs(OptimizeArgs), ModuleName(ModuleName) {} bool runInvocation(std::shared_ptr Invocation, - FileManager *FileMgr, + ToolFileManager *ToolFileMgr, std::shared_ptr PCHContainerOps, DiagnosticConsumer *DiagConsumer) override { // Make a deep copy of the original Clang invocation. @@ -167,8 +167,7 @@ ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false; ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false; - - FileMgr->getFileSystemOpts().WorkingDir = std::string(WorkingDirectory); + auto *FileMgr = ToolFileMgr->getOrCreateFileManager(WorkingDirectory).get(); ScanInstance.setFileManager(FileMgr); ScanInstance.createSourceManager(*FileMgr); @@ -296,7 +295,7 @@ DepFS = new DependencyScanningWorkerFilesystem(Service.getSharedCache(), RealFS, PPSkipMappings); if (Service.canReuseFileManager()) - Files = new FileManager(FileSystemOptions(), RealFS); + Files = new ToolFileManager(FileSystemOptions(), RealFS); } static llvm::Error @@ -325,8 +324,8 @@ if (Files) Files->setVirtualFileSystem(RealFS); - llvm::IntrusiveRefCntPtr CurrentFiles = - Files ? Files : new FileManager(FileSystemOptions(), RealFS); + llvm::IntrusiveRefCntPtr CurrentFiles = + Files ? Files : new ToolFileManager(FileSystemOptions(), RealFS); Optional> ModifiedCommandLine; if (ModuleName.hasValue()) { diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -207,8 +207,8 @@ SmallString<16> FileNameStorage; StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), VFS)); + llvm::IntrusiveRefCntPtr Files( + new ToolFileManager(FileSystemOptions(), VFS)); ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster(); ToolInvocation Invocation( getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef), @@ -320,13 +320,14 @@ ToolInvocation::ToolInvocation( std::vector CommandLine, ToolAction *Action, - FileManager *Files, std::shared_ptr PCHContainerOps) + ToolFileManager *Files, + std::shared_ptr PCHContainerOps) : CommandLine(std::move(CommandLine)), Action(Action), OwnsAction(false), Files(Files), PCHContainerOps(std::move(PCHContainerOps)) {} ToolInvocation::ToolInvocation( std::vector CommandLine, - std::unique_ptr FAction, FileManager *Files, + std::unique_ptr FAction, ToolFileManager *Files, std::shared_ptr PCHContainerOps) : CommandLine(std::move(CommandLine)), Action(new SingleFrontendActionFactory(std::move(FAction))), @@ -359,16 +360,17 @@ &*DiagOpts, DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false); // Although `Diagnostics` are used only for command-line parsing, the custom // `DiagConsumer` might expect a `SourceManager` to be present. - SourceManager SrcMgr(*Diagnostics, *Files); + SourceManager SrcMgr(*Diagnostics, *Files->getOrCreateFileManager()); Diagnostics->setSourceManager(&SrcMgr); const std::unique_ptr Driver( - newDriver(&*Diagnostics, BinaryName, &Files->getVirtualFileSystem())); + newDriver(&*Diagnostics, BinaryName, + &Files->getOrCreateFileManager()->getVirtualFileSystem())); // The "input file not found" diagnostics from the driver are useful. // The driver is only aware of the VFS working directory, but some clients // change this at the FileManager level instead. // In this case the checks have false positives, so skip them. - if (!Files->getFileSystemOpts().WorkingDir.empty()) + if (!Files->getOrCreateFileManager()->getFileSystemOpts().WorkingDir.empty()) Driver->setCheckInputsExist(false); const std::unique_ptr Compilation( Driver->BuildCompilation(llvm::makeArrayRef(Argv))); @@ -400,13 +402,13 @@ } bool FrontendActionFactory::runInvocation( - std::shared_ptr Invocation, FileManager *Files, + std::shared_ptr Invocation, ToolFileManager *Files, std::shared_ptr PCHContainerOps, DiagnosticConsumer *DiagConsumer) { // Create a compiler instance to handle the actual work. CompilerInstance Compiler(std::move(PCHContainerOps)); Compiler.setInvocation(std::move(Invocation)); - Compiler.setFileManager(Files); + Compiler.setFileManager(Files->getOrCreateFileManager().get()); // The FrontendAction can have lifetime requirements for Compiler or its // members, and we need to ensure it's deleted earlier than Compiler. So we @@ -418,11 +420,11 @@ if (!Compiler.hasDiagnostics()) return false; - Compiler.createSourceManager(*Files); + Compiler.createSourceManager(*Files->getOrCreateFileManager()); const bool Success = Compiler.ExecuteAction(*ScopedToolAction); - Files->clearStatCache(); + Files->getOrCreateFileManager()->clearStatCache(); return Success; } @@ -430,19 +432,20 @@ ArrayRef SourcePaths, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr BaseFS, - IntrusiveRefCntPtr Files) + IntrusiveRefCntPtr Files) : Compilations(Compilations), SourcePaths(SourcePaths), PCHContainerOps(std::move(PCHContainerOps)), OverlayFileSystem(new llvm::vfs::OverlayFileSystem(std::move(BaseFS))), InMemoryFileSystem(new llvm::vfs::InMemoryFileSystem), Files(Files ? Files - : new FileManager(FileSystemOptions(), OverlayFileSystem)) { + : new clang::tooling::ToolFileManager( + FileSystemOptions(), OverlayFileSystem, BaseFS)) { OverlayFileSystem->pushOverlay(InMemoryFileSystem); appendArgumentsAdjuster(getClangStripOutputAdjuster()); appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster()); appendArgumentsAdjuster(getClangStripDependencyFileAdjuster()); if (Files) - Files->setVirtualFileSystem(OverlayFileSystem); + Files->setVirtualFileSystem(OverlayFileSystem, BaseFS); } ClangTool::~ClangTool() = default; @@ -601,7 +604,7 @@ ASTBuilderAction(std::vector> &ASTs) : ASTs(ASTs) {} bool runInvocation(std::shared_ptr Invocation, - FileManager *Files, + ToolFileManager *Files, std::shared_ptr PCHContainerOps, DiagnosticConsumer *DiagConsumer) override { std::unique_ptr AST = ASTUnit::LoadFromCompilerInvocation( @@ -609,7 +612,7 @@ CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts(), DiagConsumer, /*ShouldOwnClient=*/false), - Files); + Files->getOrCreateFileManager().get()); if (!AST) return false; @@ -655,8 +658,8 @@ llvm::IntrusiveRefCntPtr InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); OverlayFileSystem->pushOverlay(InMemoryFileSystem); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), OverlayFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new ToolFileManager(FileSystemOptions(), OverlayFileSystem)); ToolInvocation Invocation( getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileName), FileName), diff --git a/clang/test/Tooling/multiple-source-include-different-header-with-same-relative-path.cpp b/clang/test/Tooling/multiple-source-include-different-header-with-same-relative-path.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Tooling/multiple-source-include-different-header-with-same-relative-path.cpp @@ -0,0 +1,42 @@ +// This test case presents a circumstance that the information related one file +// is misused by another. +// +// The path tree of the test directory is as follors. +// . +// ├── a +// │ ├── a.c +// │ └── config.h +// ├── b +// │ ├── b.c +// │ └── config.h +// └── compile_commands.json +// +// Both source files (a/a.c and b/b.c) includes the config.h file of their own +// directory with `#include "config.h"`. However, the two config.h files are +// different. File a/config.h is longer than b/config.h. Both a/a.c and b/b.c +// are compiled in their own directory, which is recorded in the compilation +// database. +// +// When using ClangTool to parse these two source files one by one, since the +// file name of both header files are the same, the FileManager will confuse +// with them and using the file entry of a/config.h for b/config.h. And the +// wrong file length will lead to a buffer overflow when reading the file. +// +// In this test case, to avoid buffer overflow, we use the leading '\0' in an +// empty buffer to trigger the problem. We set a/config.h as an empty line +// comment, and leave b/config.h empty. Firstly, a/config.h is read and cached, +// then when reading b/config.h, if the size of a/config.h is used, the first +// two chars are read and the first one must be a '\0'. + +// RUN: rm -rf %t +// RUN: mkdir -p %t/a +// RUN: mkdir -p %t/b +// RUN: echo '#include "config.h"' > %t/a/a.c +// RUN: echo '#include "config.h"' > %t/b/b.c +// RUN: echo '//' > %t/a/config.h +// RUN: echo '' > %t/b/config.h +// RUN: echo '[{"arguments": ["cc", "-c", "-o", "a.o", "a.c"], "directory": "%t/a", "file": "a.c"}, {"arguments": ["cc", "-c", "-o", "b.o", "b.c"], "directory": "%t/b", "file": "b.c"}]' | sed -e 's/\\/\\\\/g' > %t/compile_commands.json + +// The following two test RUNs should have no output. +// RUN: cd %t && clang-check a/a.c b/b.c 2>&1 | count 0 +// RUN: cd %t && clang-check b/b.c a/a.c 2>&1 | count 0 diff --git a/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp b/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp --- a/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp +++ b/clang/tools/clang-fuzzer/handle-cxx/handle_cxx.cpp @@ -29,8 +29,8 @@ CC1Args.push_back(A); CC1Args.push_back(FileName); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions())); + llvm::IntrusiveRefCntPtr Files( + new clang::tooling::ToolFileManager(FileSystemOptions())); IgnoringDiagConsumer Diags; IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); DiagnosticsEngine Diagnostics( diff --git a/clang/unittests/Tooling/DependencyScannerTest.cpp b/clang/unittests/Tooling/DependencyScannerTest.cpp --- a/clang/unittests/Tooling/DependencyScannerTest.cpp +++ b/clang/unittests/Tooling/DependencyScannerTest.cpp @@ -51,18 +51,18 @@ TestDependencyScanningAction(std::vector &Deps) : Deps(Deps) {} bool runInvocation(std::shared_ptr Invocation, - FileManager *FileMgr, + ToolFileManager *FileMgr, std::shared_ptr PCHContainerOps, DiagnosticConsumer *DiagConsumer) override { CompilerInstance Compiler(std::move(PCHContainerOps)); Compiler.setInvocation(std::move(Invocation)); - Compiler.setFileManager(FileMgr); + Compiler.setFileManager(FileMgr->getOrCreateFileManager().get()); Compiler.createDiagnostics(DiagConsumer, /*ShouldOwnClient=*/false); if (!Compiler.hasDiagnostics()) return false; - Compiler.createSourceManager(*FileMgr); + Compiler.createSourceManager(*FileMgr->getOrCreateFileManager()); Compiler.addDependencyCollector(std::make_shared( Compiler.getInvocation().getDependencyOutputOpts(), Deps)); diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp --- a/clang/unittests/Tooling/ToolingTest.cpp +++ b/clang/unittests/Tooling/ToolingTest.cpp @@ -179,8 +179,8 @@ llvm::IntrusiveRefCntPtr InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); OverlayFileSystem->pushOverlay(InMemoryFileSystem); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), OverlayFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new ToolFileManager(FileSystemOptions(), OverlayFileSystem)); std::vector Args; Args.push_back("tool-executable"); Args.push_back("-Idef"); @@ -205,8 +205,8 @@ llvm::IntrusiveRefCntPtr InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); OverlayFileSystem->pushOverlay(InMemoryFileSystem); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), OverlayFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new ToolFileManager(FileSystemOptions(), OverlayFileSystem)); std::vector Args; Args.push_back("tool-executable"); Args.push_back("-Idef"); @@ -231,8 +231,8 @@ llvm::IntrusiveRefCntPtr InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); OverlayFileSystem->pushOverlay(InMemoryFileSystem); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), OverlayFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new ToolFileManager(FileSystemOptions(), OverlayFileSystem)); std::vector Args; Args.push_back("tool-executable"); @@ -260,8 +260,8 @@ llvm::IntrusiveRefCntPtr InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); OverlayFileSystem->pushOverlay(InMemoryFileSystem); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), OverlayFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new ToolFileManager(FileSystemOptions(), OverlayFileSystem)); std::vector Args; Args.push_back("tool-executable"); @@ -306,8 +306,8 @@ llvm::IntrusiveRefCntPtr InMemoryFileSystem( new llvm::vfs::InMemoryFileSystem); OverlayFileSystem->pushOverlay(InMemoryFileSystem); - llvm::IntrusiveRefCntPtr Files( - new FileManager(FileSystemOptions(), OverlayFileSystem)); + llvm::IntrusiveRefCntPtr Files( + new ToolFileManager(FileSystemOptions(), OverlayFileSystem)); std::vector Args; Args.push_back("tool-executable"); // Note: intentional error; user probably meant -ferror-limit=0.