forked from OSchip/llvm-project
[VFS] Port tooling to use the in-memory file system.
This means file remappings can now be managed by ClangTool (or a ToolInvocation user) instead of by ToolInvocation itself. The ToolInvocation remapping is still in place so users can migrate. Differential Revision: http://reviews.llvm.org/D13474 llvm-svn: 249815
This commit is contained in:
parent
859b2ac07d
commit
c4cb3b10dc
|
@ -243,6 +243,7 @@ public:
|
|||
///
|
||||
/// \param FilePath The path at which the content will be mapped.
|
||||
/// \param Content A null terminated buffer of the file's content.
|
||||
// FIXME: remove this when all users have migrated!
|
||||
void mapVirtualFile(StringRef FilePath, StringRef Content);
|
||||
|
||||
/// \brief Run the clang invocation.
|
||||
|
@ -331,9 +332,12 @@ class ClangTool {
|
|||
std::vector<std::string> SourcePaths;
|
||||
std::shared_ptr<PCHContainerOperations> PCHContainerOps;
|
||||
|
||||
llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> OverlayFileSystem;
|
||||
llvm::IntrusiveRefCntPtr<vfs::InMemoryFileSystem> InMemoryFileSystem;
|
||||
llvm::IntrusiveRefCntPtr<FileManager> Files;
|
||||
// Contains a list of pairs (<file name>, <file content>).
|
||||
std::vector< std::pair<StringRef, StringRef> > MappedFileContents;
|
||||
llvm::StringSet<> SeenWorkingDirectories;
|
||||
|
||||
ArgumentsAdjuster ArgsAdjuster;
|
||||
|
||||
|
|
|
@ -32,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 {
|
||||
|
@ -131,18 +124,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();
|
||||
|
@ -250,6 +250,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 =
|
||||
|
@ -308,7 +309,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());
|
||||
}
|
||||
|
@ -346,6 +351,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));
|
||||
|
@ -376,9 +391,21 @@ 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);
|
||||
|
@ -390,8 +417,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";
|
||||
|
@ -399,7 +425,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!");
|
||||
}
|
||||
|
@ -455,14 +481,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()));
|
||||
new FileManager(FileSystemOptions(), OverlayFileSystem));
|
||||
ToolInvocation Invocation(getSyntaxOnlyToolArgs(Args, FileNameRef), &Action,
|
||||
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;
|
||||
|
||||
|
|
|
@ -149,8 +149,13 @@ TEST(newFrontendActionFactory, CreatesFrontendActionFactoryFromFactoryType) {
|
|||
}
|
||||
|
||||
TEST(ToolInvocation, TestMapVirtualFile) {
|
||||
IntrusiveRefCntPtr<clang::FileManager> Files(
|
||||
new clang::FileManager(clang::FileSystemOptions()));
|
||||
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));
|
||||
std::vector<std::string> Args;
|
||||
Args.push_back("tool-executable");
|
||||
Args.push_back("-Idef");
|
||||
|
@ -158,8 +163,10 @@ TEST(ToolInvocation, TestMapVirtualFile) {
|
|||
Args.push_back("test.cpp");
|
||||
clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
|
||||
Files.get());
|
||||
Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
|
||||
Invocation.mapVirtualFile("def/abc", "\n");
|
||||
InMemoryFileSystem->addFile(
|
||||
"test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("#include <abc>\n"));
|
||||
InMemoryFileSystem->addFile("def/abc", 0,
|
||||
llvm::MemoryBuffer::getMemBuffer("\n"));
|
||||
EXPECT_TRUE(Invocation.run());
|
||||
}
|
||||
|
||||
|
@ -168,8 +175,13 @@ TEST(ToolInvocation, TestVirtualModulesCompilation) {
|
|||
// mapped module.map is found on the include path. In the future, expand this
|
||||
// test to run a full modules enabled compilation, so we make sure we can
|
||||
// rerun modules compilations with a virtual file system.
|
||||
IntrusiveRefCntPtr<clang::FileManager> Files(
|
||||
new clang::FileManager(clang::FileSystemOptions()));
|
||||
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));
|
||||
std::vector<std::string> Args;
|
||||
Args.push_back("tool-executable");
|
||||
Args.push_back("-Idef");
|
||||
|
@ -177,11 +189,14 @@ TEST(ToolInvocation, TestVirtualModulesCompilation) {
|
|||
Args.push_back("test.cpp");
|
||||
clang::tooling::ToolInvocation Invocation(Args, new SyntaxOnlyAction,
|
||||
Files.get());
|
||||
Invocation.mapVirtualFile("test.cpp", "#include <abc>\n");
|
||||
Invocation.mapVirtualFile("def/abc", "\n");
|
||||
InMemoryFileSystem->addFile(
|
||||
"test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("#include <abc>\n"));
|
||||
InMemoryFileSystem->addFile("def/abc", 0,
|
||||
llvm::MemoryBuffer::getMemBuffer("\n"));
|
||||
// Add a module.map file in the include directory of our header, so we trigger
|
||||
// the module.map header search logic.
|
||||
Invocation.mapVirtualFile("def/module.map", "\n");
|
||||
InMemoryFileSystem->addFile("def/module.map", 0,
|
||||
llvm::MemoryBuffer::getMemBuffer("\n"));
|
||||
EXPECT_TRUE(Invocation.run());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue