Index: clang-tidy/ClangTidy.h =================================================================== --- clang-tidy/ClangTidy.h +++ clang-tidy/ClangTidy.h @@ -223,7 +223,8 @@ /// \brief Displays the found \p Errors to the users. If \p Fix is true, \p /// Errors containing fixes are automatically applied. void handleErrors(const std::vector &Errors, bool Fix, - unsigned &WarningsAsErrorsCount); + unsigned &WarningsAsErrorsCount, + StringRef BuildDirectory); /// \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 @@ -95,7 +95,7 @@ class ErrorReporter { public: - ErrorReporter(bool ApplyFixes) + ErrorReporter(bool ApplyFixes, StringRef BuildDirectory) : Files(FileSystemOptions()), DiagOpts(new DiagnosticOptions()), DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)), Diags(IntrusiveRefCntPtr(new DiagnosticIDs), &*DiagOpts, @@ -103,6 +103,12 @@ SourceMgr(Diags, Files), Rewrite(SourceMgr, LangOpts), ApplyFixes(ApplyFixes), TotalFixes(0), AppliedFixes(0), WarningsAsErrors(0) { + // By default, the working directory of file system is the current + // clang-tidy running directory. + // + // Change the directory to the one used during the analysis. + if (!BuildDirectory.empty()) + Files.getVirtualFileSystem()->setCurrentWorkingDirectory(BuildDirectory); DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors(); DiagPrinter->BeginSourceFile(LangOpts); } @@ -231,6 +237,12 @@ Context.setSourceManager(&Compiler.getSourceManager()); Context.setCurrentFile(File); Context.setASTContext(&Compiler.getASTContext()); + auto WorkingDir = Compiler.getSourceManager() + .getFileManager() + .getVirtualFileSystem() + ->getCurrentWorkingDirectory(); + if (WorkingDir) + Context.setBuildDirectoryForStats(WorkingDir.get()); std::vector> Checks; CheckFactories->createChecks(&Context, Checks); @@ -444,8 +456,9 @@ } void handleErrors(const std::vector &Errors, bool Fix, - unsigned &WarningsAsErrorsCount) { - ErrorReporter Reporter(Fix); + unsigned &WarningsAsErrorsCount, + StringRef BuildDirectory) { + ErrorReporter Reporter(Fix, BuildDirectory); for (const ClangTidyError &Error : Errors) Reporter.reportDiagnostic(Error); Reporter.Finish(); Index: clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.h +++ clang-tidy/ClangTidyDiagnosticConsumer.h @@ -101,6 +101,14 @@ unsigned ErrorsIgnoredNOLINT; unsigned ErrorsIgnoredNonUserCode; unsigned ErrorsIgnoredLineFilter; + // A build directory of the source file containing the error. + // + // It's an absolute path which is `directory` field of the source file in + // compilation database. If users don't specify compilation database + // directory, it is the current directory where clang-tidy runs. + // + // It can be empty in some cases, e.g. the source file does not exist. + std::string BuildDirectory; unsigned errorsIgnored() const { return ErrorsIgnoredNOLINT + ErrorsIgnoredCheckFilter + @@ -185,6 +193,8 @@ /// counters. const ClangTidyStats &getStats() const { return Stats; } + void setBuildDirectoryForStats(StringRef BuildDirectory); + /// \brief Returns all collected errors. const std::vector &getErrors() const { return Errors; } Index: clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -229,6 +229,10 @@ OptionsProvider->getOptions(File)); } +void ClangTidyContext::setBuildDirectoryForStats(StringRef BuildDirectory) { + Stats.BuildDirectory = BuildDirectory; +} + void ClangTidyContext::setCheckProfileData(ProfileData *P) { Profile = P; } GlobList &ClangTidyContext::getChecksFilter() { Index: clang-tidy/tool/ClangTidyMain.cpp =================================================================== --- clang-tidy/tool/ClangTidyMain.cpp +++ clang-tidy/tool/ClangTidyMain.cpp @@ -357,7 +357,8 @@ unsigned WErrorCount = 0; // -fix-errors implies -fix. - handleErrors(Errors, (FixErrors || Fix) && !DisableFixes, WErrorCount); + handleErrors(Errors, (FixErrors || Fix) && !DisableFixes, WErrorCount, + Stats.BuildDirectory); if (!ExportFixes.empty() && !Errors.empty()) { std::error_code EC; Index: test/clang-tidy/Inputs/compilation-database/header.h =================================================================== --- /dev/null +++ test/clang-tidy/Inputs/compilation-database/header.h @@ -0,0 +1,3 @@ +#define NULL 0 + +int *a = NULL; Index: test/clang-tidy/Inputs/compilation-database/template.json =================================================================== --- /dev/null +++ test/clang-tidy/Inputs/compilation-database/template.json @@ -0,0 +1,7 @@ +[ +{ + "directory": "test_dir", + "command": "clang++ -o test.o clang-tidy-run-with-database.cpp", + "file": "test_dir/clang-tidy-run-with-database.cpp" +} +] Index: test/clang-tidy/clang-tidy-run-with-database.cpp =================================================================== --- /dev/null +++ test/clang-tidy/clang-tidy-run-with-database.cpp @@ -0,0 +1,6 @@ +// REQUIRES: shell +// RUN: sed 's|test_dir|%S|g' %S/Inputs/compilation-database/template.json > %T/compile_commands.json +// RUN: clang-tidy --checks=-*,modernize-use-nullptr -p %T %s -header-filter=.* | FileCheck %s -implicit-check-not="{{warning:}}" + +#include "./Inputs/compilation-database/header.h" +// CHECK: warning: use nullptr [modernize-use-nullptr]