[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:
Benjamin Kramer 2015-10-09 09:54:37 +00:00
parent 859b2ac07d
commit c4cb3b10dc
3 changed files with 80 additions and 29 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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());
}