diff --git a/clang-tools-extra/clang-tidy/ClangTidy.h b/clang-tools-extra/clang-tidy/ClangTidy.h --- a/clang-tools-extra/clang-tidy/ClangTidy.h +++ b/clang-tools-extra/clang-tidy/ClangTidy.h @@ -83,12 +83,15 @@ /// \param StoreCheckProfile If provided, and EnableCheckProfile is true, /// the profile will not be output to stderr, but will instead be stored /// as a JSON file in the specified directory. +/// \param WillExportFixes If true, add line and column information to messages +/// for fixes later being exported to yaml. std::vector runClangTidy(clang::tidy::ClangTidyContext &Context, const tooling::CompilationDatabase &Compilations, ArrayRef InputFiles, llvm::IntrusiveRefCntPtr BaseFS, bool ApplyAnyFix, bool EnableCheckProfile = false, + bool WillExportFixes = false, llvm::StringRef StoreCheckProfile = StringRef()); /// Controls what kind of fixes clang-tidy is allowed to apply. diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -512,7 +512,7 @@ const CompilationDatabase &Compilations, ArrayRef InputFiles, llvm::IntrusiveRefCntPtr BaseFS, - bool ApplyAnyFix, bool EnableCheckProfile, + bool ApplyAnyFix, bool EnableCheckProfile, bool willExport, llvm::StringRef StoreCheckProfile) { ClangTool Tool(Compilations, InputFiles, std::make_shared(), BaseFS); @@ -583,6 +583,11 @@ ActionFactory Factory(Context, std::move(BaseFS)); Tool.run(&Factory); + + if (willExport) { + // Only compute line and column information if needed for yaml export + DiagConsumer.addLineAndColToDiagnostics(); + } return DiagConsumer.take(); } diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -282,6 +282,9 @@ // Retrieve the diagnostics that were captured. std::vector take(); + // Add Line and Column data to errors so that it is available when exporting yaml. + void addLineAndColToDiagnostics(); + private: void finalizeLastError(); void removeIncompatibleErrors(); diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -25,7 +25,9 @@ #include "clang/Basic/CharInfo.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/FileEntry.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/DiagnosticRenderer.h" #include "clang/Lex/Lexer.h" @@ -742,6 +744,37 @@ }; } // end anonymous namespace +FullSourceLoc getLocation(SourceManager & SourceMgr, StringRef FilePath, unsigned Offset) { + if (FilePath.empty()) + return FullSourceLoc(SourceLocation(), SourceMgr); + + auto File = SourceMgr.getFileManager().getFile(FilePath); + if (!File) + return FullSourceLoc(SourceLocation(), SourceMgr); + + const FileEntry* TheFileEntry = *File; + if (TheFileEntry == nullptr) { + return FullSourceLoc(SourceLocation(), SourceMgr); + } + + FileID ID = SourceMgr.getOrCreateFileID(TheFileEntry, SrcMgr::C_User); + + SourceLocation StartLocation = SourceMgr.getLocForStartOfFile(ID); + return FullSourceLoc(StartLocation.getLocWithOffset(Offset), SourceMgr); +} + +void ClangTidyDiagnosticConsumer::addLineAndColToDiagnostics() { + for (ClangTidyError CTE : Errors) { + tooling::DiagnosticMessage &Message = CTE.Message; + + SourceManager & SM = Context.DiagEngine->getSourceManager(); + + FullSourceLoc Loc = getLocation(SM, Message.FilePath, Message.FileOffset); + CTE.Message.LineNumber = Loc.getLineNumber(); + CTE.Message.ColumnNumber = Loc.getColumnNumber(); + } +} + std::vector ClangTidyDiagnosticConsumer::take() { finalizeLastError(); diff --git a/clang/include/clang/Tooling/Core/Diagnostic.h b/clang/include/clang/Tooling/Core/Diagnostic.h --- a/clang/include/clang/Tooling/Core/Diagnostic.h +++ b/clang/include/clang/Tooling/Core/Diagnostic.h @@ -21,6 +21,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" +#include #include namespace clang { @@ -55,6 +56,11 @@ std::string FilePath; unsigned FileOffset; + /// Diagnostics normally do not store Line and Col numbers but should if + /// exporting to yaml. + std::optional LineNumber; + std::optional ColumnNumber; + /// Fixes for this diagnostic, grouped by file path. llvm::StringMap Fix; diff --git a/clang/include/clang/Tooling/DiagnosticsYaml.h b/clang/include/clang/Tooling/DiagnosticsYaml.h --- a/clang/include/clang/Tooling/DiagnosticsYaml.h +++ b/clang/include/clang/Tooling/DiagnosticsYaml.h @@ -40,6 +40,8 @@ Io.mapRequired("Message", M.Message); Io.mapOptional("FilePath", M.FilePath); Io.mapOptional("FileOffset", M.FileOffset); + Io.mapOptional("LineNumber", M.LineNumber); + Io.mapOptional("ColumnNumber", M.ColumnNumber); std::vector Fixes; for (auto &Replacements : M.Fix) { llvm::append_range(Fixes, Replacements.second);