#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 {
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();
}
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 =
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());
}
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));
// 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);
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";
}
// 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!");
}
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;
}
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");
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());
}
// 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");
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());
}