Index: clang-tidy/ClangTidy.h =================================================================== --- clang-tidy/ClangTidy.h +++ clang-tidy/ClangTidy.h @@ -227,6 +227,7 @@ void runClangTidy(clang::tidy::ClangTidyContext &Context, const tooling::CompilationDatabase &Compilations, ArrayRef InputFiles, + llvm::IntrusiveRefCntPtr BaseFS, ProfileData *Profile = nullptr); // FIXME: This interface will need to be significantly extended to be useful. @@ -236,7 +237,8 @@ /// Errors containing fixes are automatically applied and reformatted. If no /// clang-format configuration file is found, the given \P FormatStyle is used. void handleErrors(ClangTidyContext &Context, bool Fix, - unsigned &WarningsAsErrorsCount); + unsigned &WarningsAsErrorsCount, + llvm::IntrusiveRefCntPtr BaseFS); /// \brief Serializes replacements into YAML and writes them to the specified /// output stream. Index: clang-tidy/ClangTidy.cpp =================================================================== --- clang-tidy/ClangTidy.cpp +++ clang-tidy/ClangTidy.cpp @@ -89,8 +89,9 @@ class ErrorReporter { public: - ErrorReporter(ClangTidyContext &Context, bool ApplyFixes) - : Files(FileSystemOptions()), DiagOpts(new DiagnosticOptions()), + ErrorReporter(ClangTidyContext &Context, bool ApplyFixes, + llvm::IntrusiveRefCntPtr BaseFS) + : Files(FileSystemOptions(), BaseFS), DiagOpts(new DiagnosticOptions()), DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)), Diags(IntrusiveRefCntPtr(new DiagnosticIDs), &*DiagOpts, DiagPrinter), @@ -474,8 +475,11 @@ void runClangTidy(clang::tidy::ClangTidyContext &Context, const CompilationDatabase &Compilations, - ArrayRef InputFiles, ProfileData *Profile) { - ClangTool Tool(Compilations, InputFiles); + ArrayRef InputFiles, + llvm::IntrusiveRefCntPtr BaseFS, + ProfileData *Profile) { + ClangTool Tool(Compilations, InputFiles, + std::make_shared(), BaseFS); // Add extra arguments passed by the clang-tidy command-line. ArgumentsAdjuster PerFileExtraArgumentsInserter = @@ -546,8 +550,9 @@ } void handleErrors(ClangTidyContext &Context, bool Fix, - unsigned &WarningsAsErrorsCount) { - ErrorReporter Reporter(Context, Fix); + unsigned &WarningsAsErrorsCount, + llvm::IntrusiveRefCntPtr BaseFS) { + ErrorReporter Reporter(Context, Fix, BaseFS); vfs::FileSystem &FileSystem = *Reporter.getSourceManager().getFileManager().getVirtualFileSystem(); auto InitialWorkingDir = FileSystem.getCurrentWorkingDirectory(); Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -209,6 +209,13 @@ cl::init(false), cl::cat(ClangTidyCategory)); +static cl::opt VfsOverlay("vfsoverlay", cl::desc(R"( +Overlay the virtual filesystem described by file +over the real file system. +)"), + cl::value_desc("filename"), + cl::cat(ClangTidyCategory)); + namespace clang { namespace tidy { @@ -330,6 +337,30 @@ OverrideOptions); } +llvm::IntrusiveRefCntPtr +getVfsOverlayFromFile(const std::string &OverlayFile) { + llvm::IntrusiveRefCntPtr OverlayFS( + new vfs::OverlayFileSystem(vfs::getRealFileSystem())); + llvm::ErrorOr> Buffer = + OverlayFS->getBufferForFile(OverlayFile); + if (!Buffer) { + llvm::errs() << "Can't load virtual filesystem overlay file '" + << OverlayFile << "': " << Buffer.getError().message() + << ".\n"; + return nullptr; + } + + IntrusiveRefCntPtr FS = vfs::getVFSFromYAML( + std::move(Buffer.get()), /*DiagHandler*/ nullptr, OverlayFile); + if (!FS) { + llvm::errs() << "Error: invalid virtual filesystem overlay file '" + << OverlayFile << "'.\n"; + return nullptr; + } + OverlayFS->pushOverlay(FS); + return OverlayFS; +} + static int clangTidyMain(int argc, const char **argv) { CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory, cl::ZeroOrMore); @@ -401,6 +432,11 @@ llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true); return 0; } + llvm::IntrusiveRefCntPtr BaseFS( + VfsOverlay.empty() ? vfs::getRealFileSystem() + : getVfsOverlayFromFile(VfsOverlay)); + if (!BaseFS) + return 1; ProfileData Profile; @@ -409,7 +445,7 @@ llvm::InitializeAllAsmParsers(); ClangTidyContext Context(std::move(OwningOptionsProvider)); - runClangTidy(Context, OptionsParser.getCompilations(), PathList, + runClangTidy(Context, OptionsParser.getCompilations(), PathList, BaseFS, EnableCheckProfile ? &Profile : nullptr); ArrayRef Errors = Context.getErrors(); bool FoundErrors = @@ -422,7 +458,8 @@ unsigned WErrorCount = 0; // -fix-errors implies -fix. - handleErrors(Context, (FixErrors || Fix) && !DisableFixes, WErrorCount); + handleErrors(Context, (FixErrors || Fix) && !DisableFixes, WErrorCount, + BaseFS); if (!ExportFixes.empty() && !Errors.empty()) { std::error_code EC; Index: test/clang-tidy/Inputs/vfsoverlay/actual_header.h =================================================================== --- test/clang-tidy/Inputs/vfsoverlay/actual_header.h +++ test/clang-tidy/Inputs/vfsoverlay/actual_header.h @@ -0,0 +1 @@ +struct X {}; Index: test/clang-tidy/Inputs/vfsoverlay/vfsoverlay.yaml =================================================================== --- test/clang-tidy/Inputs/vfsoverlay/vfsoverlay.yaml +++ test/clang-tidy/Inputs/vfsoverlay/vfsoverlay.yaml @@ -0,0 +1,12 @@ +{ + 'version': 0, + 'roots': [ + { 'name': 'OUT_DIR', 'type': 'directory', + 'contents': [ + { 'name': 'not_real.h', 'type': 'file', + 'external-contents': 'INPUT_DIR/actual_header.h' + } + ] + } + ] +} Index: test/clang-tidy/vfsoverlay.cpp =================================================================== --- test/clang-tidy/vfsoverlay.cpp +++ test/clang-tidy/vfsoverlay.cpp @@ -0,0 +1,8 @@ +// RUN: sed -e "s:INPUT_DIR:%S/Inputs/vfsoverlay:g" -e "s:OUT_DIR:%t:g" %S/Inputs/vfsoverlay/vfsoverlay.yaml > %t.yaml +// RUN: clang-tidy %s -checks='-*,modernize-use-nullptr' -vfsoverlay %t.yaml -- -I %t | FileCheck %s +// REQUIRES: shell + +#include "not_real.h" + +X *ptr = 0; +// CHECK: warning: use nullptr [modernize-use-nullptr]