diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp | 115 |
1 files changed, 88 insertions, 27 deletions
diff --git a/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp index f9cb7c6..fd5596e 100644 --- a/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp +++ b/contrib/llvm/tools/clang/lib/Tooling/Tooling.cpp @@ -17,6 +17,7 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -31,13 +32,6 @@ #include "llvm/Support/Host.h" #include "llvm/Support/raw_ostream.h" -// For chdir, see the comment in ClangTool::run for more information. -#ifdef LLVM_ON_WIN32 -# include <direct.h> -#else -# include <unistd.h> -#endif - #define DEBUG_TYPE "clang-tooling" namespace clang { @@ -52,10 +46,11 @@ FrontendActionFactory::~FrontendActionFactory() {} // it to be based on the same framework. /// \brief Builds a clang driver initialized for running clang tools. -static clang::driver::Driver *newDriver(clang::DiagnosticsEngine *Diagnostics, - const char *BinaryName) { +static clang::driver::Driver *newDriver( + clang::DiagnosticsEngine *Diagnostics, const char *BinaryName, + IntrusiveRefCntPtr<vfs::FileSystem> VFS) { clang::driver::Driver *CompilerDriver = new clang::driver::Driver( - BinaryName, llvm::sys::getDefaultTargetTriple(), *Diagnostics); + BinaryName, llvm::sys::getDefaultTargetTriple(), *Diagnostics, VFS); CompilerDriver->setTitle("clang_based_tool"); return CompilerDriver; } @@ -130,18 +125,25 @@ bool runToolOnCodeWithArgs( SmallString<16> FileNameStorage; StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage); + llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem( + new vfs::OverlayFileSystem(vfs::getRealFileSystem())); + llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( + new vfs::InMemoryFileSystem); + OverlayFileSystem->pushOverlay(InMemoryFileSystem); llvm::IntrusiveRefCntPtr<FileManager> Files( - new FileManager(FileSystemOptions())); + new FileManager(FileSystemOptions(), OverlayFileSystem)); ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), ToolAction, Files.get(), PCHContainerOps); SmallString<1024> CodeStorage; - Invocation.mapVirtualFile(FileNameRef, - Code.toNullTerminatedStringRef(CodeStorage)); + InMemoryFileSystem->addFile(FileNameRef, 0, + llvm::MemoryBuffer::getMemBuffer( + Code.toNullTerminatedStringRef(CodeStorage))); for (auto &FilenameWithContent : VirtualMappedFiles) { - Invocation.mapVirtualFile(FilenameWithContent.first, - FilenameWithContent.second); + InMemoryFileSystem->addFile( + FilenameWithContent.first, 0, + llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second)); } return Invocation.run(); @@ -162,6 +164,31 @@ std::string getAbsolutePath(StringRef File) { return AbsolutePath.str(); } +void addTargetAndModeForProgramName(std::vector<std::string> &CommandLine, + StringRef InvokedAs) { + if (!CommandLine.empty() && !InvokedAs.empty()) { + bool AlreadyHasTarget = false; + bool AlreadyHasMode = false; + // Skip CommandLine[0]. + for (auto Token = ++CommandLine.begin(); Token != CommandLine.end(); + ++Token) { + StringRef TokenRef(*Token); + AlreadyHasTarget |= + (TokenRef == "-target" || TokenRef.startswith("-target=")); + AlreadyHasMode |= (TokenRef == "--driver-mode" || + TokenRef.startswith("--driver-mode=")); + } + auto TargetMode = + clang::driver::ToolChain::getTargetAndModeFromProgramName(InvokedAs); + if (!AlreadyHasMode && !TargetMode.second.empty()) { + CommandLine.insert(++CommandLine.begin(), TargetMode.second); + } + if (!AlreadyHasTarget && !TargetMode.first.empty()) { + CommandLine.insert(++CommandLine.begin(), {"-target", TargetMode.first}); + } + } +} + namespace { class SingleFrontendActionFactory : public FrontendActionFactory { @@ -212,7 +239,7 @@ bool ToolInvocation::run() { DiagConsumer ? DiagConsumer : &DiagnosticPrinter, false); const std::unique_ptr<clang::driver::Driver> Driver( - newDriver(&Diagnostics, BinaryName)); + newDriver(&Diagnostics, BinaryName, Files->getVirtualFileSystem())); // Since the input might only be virtual, don't check whether it exists. Driver->setCheckInputsExist(false); const std::unique_ptr<clang::driver::Compilation> Compilation( @@ -224,6 +251,7 @@ bool ToolInvocation::run() { } std::unique_ptr<clang::CompilerInvocation> Invocation( newInvocation(&Diagnostics, *CC1Args)); + // FIXME: remove this when all users have migrated! for (const auto &It : MappedFileContents) { // Inject the code as the given file name into the preprocessor options. std::unique_ptr<llvm::MemoryBuffer> Input = @@ -282,7 +310,11 @@ ClangTool::ClangTool(const CompilationDatabase &Compilations, std::shared_ptr<PCHContainerOperations> PCHContainerOps) : Compilations(Compilations), SourcePaths(SourcePaths), PCHContainerOps(PCHContainerOps), - Files(new FileManager(FileSystemOptions())), DiagConsumer(nullptr) { + OverlayFileSystem(new vfs::OverlayFileSystem(vfs::getRealFileSystem())), + InMemoryFileSystem(new vfs::InMemoryFileSystem), + Files(new FileManager(FileSystemOptions(), OverlayFileSystem)), + DiagConsumer(nullptr) { + OverlayFileSystem->pushOverlay(InMemoryFileSystem); appendArgumentsAdjuster(getClangStripOutputAdjuster()); appendArgumentsAdjuster(getClangSyntaxOnlyAdjuster()); } @@ -320,6 +352,16 @@ int ClangTool::run(ToolAction *Action) { if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory)) llvm::report_fatal_error("Cannot detect current path: " + Twine(EC.message())); + + // First insert all absolute paths into the in-memory VFS. These are global + // for all compile commands. + if (SeenWorkingDirectories.insert("/").second) + for (const auto &MappedFile : MappedFileContents) + if (llvm::sys::path::is_absolute(MappedFile.first)) + InMemoryFileSystem->addFile( + MappedFile.first, 0, + llvm::MemoryBuffer::getMemBuffer(MappedFile.second)); + bool ProcessingFailed = false; for (const auto &SourcePath : SourcePaths) { std::string File(getAbsolutePath(SourcePath)); @@ -350,12 +392,24 @@ int ClangTool::run(ToolAction *Action) { // difference for example on network filesystems, where symlinks might be // switched during runtime of the tool. Fixing this depends on having a // file system abstraction that allows openat() style interactions. - if (chdir(CompileCommand.Directory.c_str())) + if (OverlayFileSystem->setCurrentWorkingDirectory( + CompileCommand.Directory)) llvm::report_fatal_error("Cannot chdir into \"" + Twine(CompileCommand.Directory) + "\n!"); + + // Now fill the in-memory VFS with the relative file mappings so it will + // have the correct relative paths. We never remove mappings but that + // should be fine. + if (SeenWorkingDirectories.insert(CompileCommand.Directory).second) + for (const auto &MappedFile : MappedFileContents) + if (!llvm::sys::path::is_absolute(MappedFile.first)) + InMemoryFileSystem->addFile( + MappedFile.first, 0, + llvm::MemoryBuffer::getMemBuffer(MappedFile.second)); + std::vector<std::string> CommandLine = CompileCommand.CommandLine; if (ArgsAdjuster) - CommandLine = ArgsAdjuster(CommandLine); + CommandLine = ArgsAdjuster(CommandLine, CompileCommand.Filename); assert(!CommandLine.empty()); CommandLine[0] = MainExecutable; // FIXME: We need a callback mechanism for the tool writer to output a @@ -364,8 +418,7 @@ int ClangTool::run(ToolAction *Action) { ToolInvocation Invocation(std::move(CommandLine), Action, Files.get(), PCHContainerOps); Invocation.setDiagnosticConsumer(DiagConsumer); - for (const auto &MappedFile : MappedFileContents) - Invocation.mapVirtualFile(MappedFile.first, MappedFile.second); + if (!Invocation.run()) { // FIXME: Diagnostics should be used instead. llvm::errs() << "Error while processing " << File << ".\n"; @@ -373,7 +426,7 @@ int ClangTool::run(ToolAction *Action) { } // Return to the initial directory to correctly resolve next file by // relative path. - if (chdir(InitialDirectory.c_str())) + if (OverlayFileSystem->setCurrentWorkingDirectory(InitialDirectory.c_str())) llvm::report_fatal_error("Cannot chdir into \"" + Twine(InitialDirectory) + "\n!"); } @@ -392,12 +445,12 @@ public: bool runInvocation(CompilerInvocation *Invocation, FileManager *Files, std::shared_ptr<PCHContainerOperations> PCHContainerOps, DiagnosticConsumer *DiagConsumer) override { - // FIXME: This should use the provided FileManager. std::unique_ptr<ASTUnit> AST = ASTUnit::LoadFromCompilerInvocation( Invocation, PCHContainerOps, CompilerInstance::createDiagnostics(&Invocation->getDiagnosticOpts(), DiagConsumer, - /*ShouldOwnClient=*/false)); + /*ShouldOwnClient=*/false), + Files); if (!AST) return false; @@ -429,12 +482,20 @@ std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( std::vector<std::unique_ptr<ASTUnit>> ASTs; ASTBuilderAction Action(ASTs); + llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem( + new vfs::OverlayFileSystem(vfs::getRealFileSystem())); + llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem( + new vfs::InMemoryFileSystem); + OverlayFileSystem->pushOverlay(InMemoryFileSystem); + llvm::IntrusiveRefCntPtr<FileManager> Files( + new FileManager(FileSystemOptions(), OverlayFileSystem)); ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), &Action, - nullptr, PCHContainerOps); + Files.get(), PCHContainerOps); SmallString<1024> CodeStorage; - Invocation.mapVirtualFile(FileNameRef, - Code.toNullTerminatedStringRef(CodeStorage)); + InMemoryFileSystem->addFile(FileNameRef, 0, + llvm::MemoryBuffer::getMemBuffer( + Code.toNullTerminatedStringRef(CodeStorage))); if (!Invocation.run()) return nullptr; |