Index: clang-tidy/ClangTidy.cpp =================================================================== --- clang-tidy/ClangTidy.cpp +++ clang-tidy/ClangTidy.cpp @@ -109,6 +109,14 @@ void reportDiagnostic(const ClangTidyError &Error) { const ClangTidyMessage &Message = Error.Message; + // By default, the working directory of file system is the current + // clang-tidy running directory. + // + // Specify the build directory of the source file as current working + // directroy to find source file correctly. + if (!Error.BuildDirectory.empty()) + Files.getVirtualFileSystem()->setCurrentWorkingDirectory( + Error.BuildDirectory); SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset); // Contains a pair for each attempted fix: location and whether the fix was // applied successfully. Index: clang-tidy/ClangTidyDiagnosticConsumer.h =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.h +++ clang-tidy/ClangTidyDiagnosticConsumer.h @@ -57,8 +57,18 @@ Error = DiagnosticsEngine::Error }; - ClangTidyError(StringRef CheckName, Level DiagLevel, bool IsWarningAsError); - + ClangTidyError(StringRef CheckName, Level DiagLevel, bool IsWarningAsError, + const std::string &BuildDirectory); + + // 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 (compile_commands.json). 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 is not exist. + std::string BuildDirectory; std::string CheckName; ClangTidyMessage Message; tooling::Replacements Fix; Index: clang-tidy/ClangTidyDiagnosticConsumer.cpp =================================================================== --- clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -116,9 +116,10 @@ ClangTidyError::ClangTidyError(StringRef CheckName, ClangTidyError::Level DiagLevel, - bool IsWarningAsError) - : CheckName(CheckName), DiagLevel(DiagLevel), - IsWarningAsError(IsWarningAsError) {} + bool IsWarningAsError, + const std::string &BuildDirectory) + : BuildDirectory(std::move(BuildDirectory)), CheckName(CheckName), + DiagLevel(DiagLevel), IsWarningAsError(IsWarningAsError) {} // Returns true if GlobList starts with the negative indicator ('-'), removes it // from the GlobList. @@ -335,7 +336,17 @@ bool IsWarningAsError = DiagLevel == DiagnosticsEngine::Warning && Context.getWarningAsErrorFilter().contains(CheckName); - Errors.push_back(ClangTidyError(CheckName, Level, IsWarningAsError)); + + std::string BuildDirectory; + if (Info.hasSourceManager()) { + auto WorkingDir = Info.getSourceManager() + .getFileManager().getVirtualFileSystem() + ->getCurrentWorkingDirectory(); + if (WorkingDir) + BuildDirectory = WorkingDir.get(); + } + Errors.push_back( + ClangTidyError(CheckName, Level, IsWarningAsError, BuildDirectory)); } // FIXME: Provide correct LangOptions for each file. 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,5 @@ +// RUN: DATABASEDIR=$S/Inputs/compilation-database +// RUN: sed 's|test_dir|%S|g' %S/Inputs/compilation-database/template.json > %S/Inputs/compilation-database/compile_commands.json +// RUN: clang-tidy --checks=-*,modernize-use-nullptr -p %S/Inputs/compilation-database %s -header-filter=.* + +#include "./Inputs/compilation-database/header.h"