[clang-tidy] Add check name to YAML export (clang-tools-extra part)

Add a field indicating the associated check for every replacement to the YAML
report generated with the '-export-fixes' option.  Update
clang-apply-replacements to handle the new format.

Patch by Alpha Abdoulaye!

Differential revision: https://reviews.llvm.org/D26137

llvm-svn: 290893
This commit is contained in:
Alexander Kornienko 2017-01-03 14:36:13 +00:00
parent 9bab199146
commit 563de799e3
16 changed files with 242 additions and 177 deletions

View File

@ -16,6 +16,7 @@
#ifndef LLVM_CLANG_APPLYREPLACEMENTS_H #ifndef LLVM_CLANG_APPLYREPLACEMENTS_H
#define LLVM_CLANG_APPLYREPLACEMENTS_H #define LLVM_CLANG_APPLYREPLACEMENTS_H
#include "clang/Tooling/Core/Diagnostic.h"
#include "clang/Tooling/Refactoring.h" #include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
@ -43,6 +44,9 @@ typedef std::vector<clang::tooling::TranslationUnitReplacements> TUReplacements;
/// \brief Collection of TranslationUnitReplacement files. /// \brief Collection of TranslationUnitReplacement files.
typedef std::vector<std::string> TUReplacementFiles; typedef std::vector<std::string> TUReplacementFiles;
/// \brief Collection of TranslationUniDiagnostics.
typedef std::vector<clang::tooling::TranslationUnitDiagnostics> TUDiagnostics;
/// \brief Map mapping file name to Replacements targeting that file. /// \brief Map mapping file name to Replacements targeting that file.
typedef llvm::DenseMap<const clang::FileEntry *, typedef llvm::DenseMap<const clang::FileEntry *,
std::vector<clang::tooling::Replacement>> std::vector<clang::tooling::Replacement>>
@ -58,8 +62,8 @@ typedef llvm::DenseMap<const clang::FileEntry *,
/// \param[in] Directory Directory to begin search for serialized /// \param[in] Directory Directory to begin search for serialized
/// TranslationUnitReplacements. /// TranslationUnitReplacements.
/// \param[out] TUs Collection of all found and deserialized /// \param[out] TUs Collection of all found and deserialized
/// TranslationUnitReplacements. /// TranslationUnitReplacements or TranslationUnitDiagnostics.
/// \param[out] TURFiles Collection of all TranslationUnitReplacement files /// \param[out] TUFiles Collection of all TranslationUnitReplacement files
/// found in \c Directory. /// found in \c Directory.
/// \param[in] Diagnostics DiagnosticsEngine used for error output. /// \param[in] Diagnostics DiagnosticsEngine used for error output.
/// ///
@ -67,7 +71,11 @@ typedef llvm::DenseMap<const clang::FileEntry *,
/// directory structure. /// directory structure.
std::error_code collectReplacementsFromDirectory( std::error_code collectReplacementsFromDirectory(
const llvm::StringRef Directory, TUReplacements &TUs, const llvm::StringRef Directory, TUReplacements &TUs,
TUReplacementFiles &TURFiles, clang::DiagnosticsEngine &Diagnostics); TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics);
std::error_code collectReplacementsFromDirectory(
const llvm::StringRef Directory, TUDiagnostics &TUs,
TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics);
/// \brief Deduplicate, check for conflicts, and apply all Replacements stored /// \brief Deduplicate, check for conflicts, and apply all Replacements stored
/// in \c TUs. If conflicts occur, no Replacements are applied. /// in \c TUs. If conflicts occur, no Replacements are applied.
@ -75,7 +83,8 @@ std::error_code collectReplacementsFromDirectory(
/// \post For all (key,value) in GroupedReplacements, value[i].getOffset() <= /// \post For all (key,value) in GroupedReplacements, value[i].getOffset() <=
/// value[i+1].getOffset(). /// value[i+1].getOffset().
/// ///
/// \param[in] TUs Collection of TranslationUnitReplacements to merge, /// \param[in] TUs Collection of TranslationUnitReplacements or
/// TranslationUnitDiagnostics to merge,
/// deduplicate, and test for conflicts. /// deduplicate, and test for conflicts.
/// \param[out] GroupedReplacements Container grouping all Replacements by the /// \param[out] GroupedReplacements Container grouping all Replacements by the
/// file they target. /// file they target.
@ -88,6 +97,10 @@ bool mergeAndDeduplicate(const TUReplacements &TUs,
FileToReplacementsMap &GroupedReplacements, FileToReplacementsMap &GroupedReplacements,
clang::SourceManager &SM); clang::SourceManager &SM);
bool mergeAndDeduplicate(const TUDiagnostics &TUs,
FileToReplacementsMap &GroupedReplacements,
clang::SourceManager &SM);
// FIXME: Remove this function after changing clang-apply-replacements to use // FIXME: Remove this function after changing clang-apply-replacements to use
// Replacements class. // Replacements class.
bool applyAllReplacements(const std::vector<tooling::Replacement> &Replaces, bool applyAllReplacements(const std::vector<tooling::Replacement> &Replaces,

View File

@ -20,6 +20,7 @@
#include "clang/Format/Format.h" #include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h" #include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h" #include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/DiagnosticsYaml.h"
#include "clang/Tooling/ReplacementsYaml.h" #include "clang/Tooling/ReplacementsYaml.h"
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileSystem.h"
@ -37,7 +38,7 @@ namespace replace {
std::error_code collectReplacementsFromDirectory( std::error_code collectReplacementsFromDirectory(
const llvm::StringRef Directory, TUReplacements &TUs, const llvm::StringRef Directory, TUReplacements &TUs,
TUReplacementFiles &TURFiles, clang::DiagnosticsEngine &Diagnostics) { TUReplacementFiles &TUFiles, clang::DiagnosticsEngine &Diagnostics) {
using namespace llvm::sys::fs; using namespace llvm::sys::fs;
using namespace llvm::sys::path; using namespace llvm::sys::path;
@ -54,7 +55,7 @@ std::error_code collectReplacementsFromDirectory(
if (extension(I->path()) != ".yaml") if (extension(I->path()) != ".yaml")
continue; continue;
TURFiles.push_back(I->path()); TUFiles.push_back(I->path());
ErrorOr<std::unique_ptr<MemoryBuffer>> Out = ErrorOr<std::unique_ptr<MemoryBuffer>> Out =
MemoryBuffer::getFile(I->path()); MemoryBuffer::getFile(I->path());
@ -79,6 +80,51 @@ std::error_code collectReplacementsFromDirectory(
return ErrorCode; return ErrorCode;
} }
std::error_code
collectReplacementsFromDirectory(const llvm::StringRef Directory,
TUDiagnostics &TUs, TUReplacementFiles &TUFiles,
clang::DiagnosticsEngine &Diagnostics) {
using namespace llvm::sys::fs;
using namespace llvm::sys::path;
std::error_code ErrorCode;
for (recursive_directory_iterator I(Directory, ErrorCode), E;
I != E && !ErrorCode; I.increment(ErrorCode)) {
if (filename(I->path())[0] == '.') {
// Indicate not to descend into directories beginning with '.'
I.no_push();
continue;
}
if (extension(I->path()) != ".yaml")
continue;
TUFiles.push_back(I->path());
ErrorOr<std::unique_ptr<MemoryBuffer>> Out =
MemoryBuffer::getFile(I->path());
if (std::error_code BufferError = Out.getError()) {
errs() << "Error reading " << I->path() << ": " << BufferError.message()
<< "\n";
continue;
}
yaml::Input YIn(Out.get()->getBuffer(), nullptr, &eatDiagnostics);
tooling::TranslationUnitDiagnostics TU;
YIn >> TU;
if (YIn.error()) {
// File doesn't appear to be a header change description. Ignore it.
continue;
}
// Only keep files that properly parse.
TUs.push_back(TU);
}
return ErrorCode;
}
/// \brief Dumps information for a sequence of conflicting Replacements. /// \brief Dumps information for a sequence of conflicting Replacements.
/// ///
/// \param[in] File FileEntry for the file the conflicting Replacements are /// \param[in] File FileEntry for the file the conflicting Replacements are
@ -256,6 +302,34 @@ bool mergeAndDeduplicate(const TUReplacements &TUs,
return !deduplicateAndDetectConflicts(GroupedReplacements, SM); return !deduplicateAndDetectConflicts(GroupedReplacements, SM);
} }
bool mergeAndDeduplicate(const TUDiagnostics &TUs,
FileToReplacementsMap &GroupedReplacements,
clang::SourceManager &SM) {
// Group all replacements by target file.
std::set<StringRef> Warned;
for (const auto &TU : TUs) {
for (const auto &D : TU.Diagnostics) {
for (const auto &Fix : D.Fix) {
for (const tooling::Replacement &R : Fix.second) {
// Use the file manager to deduplicate paths. FileEntries are
// automatically canonicalized.
const FileEntry *Entry = SM.getFileManager().getFile(R.getFilePath());
if (!Entry && Warned.insert(R.getFilePath()).second) {
errs() << "Described file '" << R.getFilePath()
<< "' doesn't exist. Ignoring...\n";
continue;
}
GroupedReplacements[Entry].push_back(R);
}
}
}
}
// Ask clang to deduplicate and report conflicts.
return !deduplicateAndDetectConflicts(GroupedReplacements, SM);
}
bool applyReplacements(const FileToReplacementsMap &GroupedReplacements, bool applyReplacements(const FileToReplacementsMap &GroupedReplacements,
clang::Rewriter &Rewrites) { clang::Rewriter &Rewrites) {

View File

@ -66,7 +66,7 @@ static cl::opt<std::string>
cl::init("LLVM"), cl::cat(FormattingCategory)); cl::init("LLVM"), cl::cat(FormattingCategory));
namespace { namespace {
// Helper object to remove the TUReplacement files (triggered by // Helper object to remove the TUReplacement and TUDiagnostic (triggered by
// "remove-change-desc-files" command line option) when exiting current scope. // "remove-change-desc-files" command line option) when exiting current scope.
class ScopedFileRemover { class ScopedFileRemover {
public: public:
@ -211,11 +211,16 @@ int main(int argc, char **argv) {
if (DoFormat) if (DoFormat)
FormatStyle = format::getStyle(FormatStyleOpt, FormatStyleConfig, "LLVM"); FormatStyle = format::getStyle(FormatStyleOpt, FormatStyleConfig, "LLVM");
TUReplacements TUs; TUReplacements TURs;
TUReplacementFiles TURFiles; TUReplacementFiles TUFiles;
std::error_code ErrorCode = std::error_code ErrorCode =
collectReplacementsFromDirectory(Directory, TUs, TURFiles, Diagnostics); collectReplacementsFromDirectory(Directory, TURs, TUFiles, Diagnostics);
TUDiagnostics TUDs;
TUFiles.clear();
ErrorCode =
collectReplacementsFromDirectory(Directory, TUDs, TUFiles, Diagnostics);
if (ErrorCode) { if (ErrorCode) {
errs() << "Trouble iterating over directory '" << Directory errs() << "Trouble iterating over directory '" << Directory
@ -227,13 +232,15 @@ int main(int argc, char **argv) {
// command line option) when exiting main(). // command line option) when exiting main().
std::unique_ptr<ScopedFileRemover> Remover; std::unique_ptr<ScopedFileRemover> Remover;
if (RemoveTUReplacementFiles) if (RemoveTUReplacementFiles)
Remover.reset(new ScopedFileRemover(TURFiles, Diagnostics)); Remover.reset(new ScopedFileRemover(TUFiles, Diagnostics));
FileManager Files((FileSystemOptions())); FileManager Files((FileSystemOptions()));
SourceManager SM(Diagnostics, Files); SourceManager SM(Diagnostics, Files);
FileToReplacementsMap GroupedReplacements; FileToReplacementsMap GroupedReplacements;
if (!mergeAndDeduplicate(TUs, GroupedReplacements, SM)) if (!mergeAndDeduplicate(TURs, GroupedReplacements, SM))
return 1;
if (!mergeAndDeduplicate(TUDs, GroupedReplacements, SM))
return 1; return 1;
Rewriter ReplacementsRewriter(SM, LangOptions()); Rewriter ReplacementsRewriter(SM, LangOptions());

View File

@ -35,6 +35,7 @@
#include "clang/Rewrite/Frontend/FrontendActions.h" #include "clang/Rewrite/Frontend/FrontendActions.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
#include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h"
#include "clang/Tooling/DiagnosticsYaml.h"
#include "clang/Tooling/Refactoring.h" #include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/ReplacementsYaml.h" #include "clang/Tooling/ReplacementsYaml.h"
#include "clang/Tooling/Tooling.h" #include "clang/Tooling/Tooling.h"
@ -102,14 +103,14 @@ public:
SourceManager &getSourceManager() { return SourceMgr; } SourceManager &getSourceManager() { return SourceMgr; }
void reportDiagnostic(const ClangTidyError &Error) { void reportDiagnostic(const ClangTidyError &Error) {
const ClangTidyMessage &Message = Error.Message; const tooling::DiagnosticMessage &Message = Error.Message;
SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset); SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
// Contains a pair for each attempted fix: location and whether the fix was // Contains a pair for each attempted fix: location and whether the fix was
// applied successfully. // applied successfully.
SmallVector<std::pair<SourceLocation, bool>, 4> FixLocations; SmallVector<std::pair<SourceLocation, bool>, 4> FixLocations;
{ {
auto Level = static_cast<DiagnosticsEngine::Level>(Error.DiagLevel); auto Level = static_cast<DiagnosticsEngine::Level>(Error.DiagLevel);
std::string Name = Error.CheckName; std::string Name = Error.DiagnosticName;
if (Error.IsWarningAsError) { if (Error.IsWarningAsError) {
Name += ",-warnings-as-errors"; Name += ",-warnings-as-errors";
Level = DiagnosticsEngine::Error; Level = DiagnosticsEngine::Error;
@ -177,7 +178,7 @@ public:
Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied
: diag::note_fixit_failed); : diag::note_fixit_failed);
} }
for (const ClangTidyMessage &Note : Error.Notes) for (const auto &Note : Error.Notes)
reportNote(Note); reportNote(Note);
} }
@ -229,10 +230,9 @@ private:
return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset); return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
} }
void reportNote(const ClangTidyMessage &Message) { void reportNote(const tooling::DiagnosticMessage &Message) {
SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset); SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
DiagnosticBuilder Diag = Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0"))
Diags.Report(Loc, Diags.getCustomDiagID(DiagnosticsEngine::Note, "%0"))
<< Message.Message; << Message.Message;
} }
@ -562,18 +562,18 @@ void handleErrors(const std::vector<ClangTidyError> &Errors, bool Fix,
WarningsAsErrorsCount += Reporter.getWarningsAsErrorsCount(); WarningsAsErrorsCount += Reporter.getWarningsAsErrorsCount();
} }
void exportReplacements(const std::vector<ClangTidyError> &Errors, void exportReplacements(const llvm::StringRef MainFilePath,
const std::vector<ClangTidyError> &Errors,
raw_ostream &OS) { raw_ostream &OS) {
TranslationUnitReplacements TUR; TranslationUnitDiagnostics TUD;
for (const ClangTidyError &Error : Errors) { TUD.MainSourceFile = MainFilePath;
for (const auto &FileAndFixes : Error.Fix) for (const auto &Error : Errors) {
TUR.Replacements.insert(TUR.Replacements.end(), tooling::Diagnostic Diag = Error;
FileAndFixes.second.begin(), TUD.Diagnostics.insert(TUD.Diagnostics.end(), Diag);
FileAndFixes.second.end());
} }
yaml::Output YAML(OS); yaml::Output YAML(OS);
YAML << TUR; YAML << TUD;
} }
} // namespace tidy } // namespace tidy

View File

@ -242,7 +242,8 @@ void handleErrors(const std::vector<ClangTidyError> &Errors, bool Fix,
/// \brief Serializes replacements into YAML and writes them to the specified /// \brief Serializes replacements into YAML and writes them to the specified
/// output stream. /// output stream.
void exportReplacements(const std::vector<ClangTidyError> &Errors, void exportReplacements(StringRef MainFilePath,
const std::vector<ClangTidyError> &Errors,
raw_ostream &OS); raw_ostream &OS);
} // end namespace tidy } // end namespace tidy

View File

@ -7,8 +7,8 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/// ///
/// \file This file implements ClangTidyDiagnosticConsumer, ClangTidyMessage, /// \file This file implements ClangTidyDiagnosticConsumer, ClangTidyContext
/// ClangTidyContext and ClangTidyError classes. /// and ClangTidyError classes.
/// ///
/// This tool uses the Clang Tooling infrastructure, see /// This tool uses the Clang Tooling infrastructure, see
/// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html /// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
@ -45,13 +45,13 @@ protected:
// FIXME: Remove this once there's a better way to pass check names than // FIXME: Remove this once there's a better way to pass check names than
// appending the check name to the message in ClangTidyContext::diag and // appending the check name to the message in ClangTidyContext::diag and
// using getCustomDiagID. // using getCustomDiagID.
std::string CheckNameInMessage = " [" + Error.CheckName + "]"; std::string CheckNameInMessage = " [" + Error.DiagnosticName + "]";
if (Message.endswith(CheckNameInMessage)) if (Message.endswith(CheckNameInMessage))
Message = Message.substr(0, Message.size() - CheckNameInMessage.size()); Message = Message.substr(0, Message.size() - CheckNameInMessage.size());
ClangTidyMessage TidyMessage = Loc.isValid() auto TidyMessage = Loc.isValid()
? ClangTidyMessage(Message, *SM, Loc) ? tooling::DiagnosticMessage(Message, *SM, Loc)
: ClangTidyMessage(Message); : tooling::DiagnosticMessage(Message);
if (Level == DiagnosticsEngine::Note) { if (Level == DiagnosticsEngine::Note) {
Error.Notes.push_back(TidyMessage); Error.Notes.push_back(TidyMessage);
return; return;
@ -110,23 +110,11 @@ private:
}; };
} // end anonymous namespace } // end anonymous namespace
ClangTidyMessage::ClangTidyMessage(StringRef Message)
: Message(Message), FileOffset(0) {}
ClangTidyMessage::ClangTidyMessage(StringRef Message,
const SourceManager &Sources,
SourceLocation Loc)
: Message(Message) {
assert(Loc.isValid() && Loc.isFileID());
FilePath = Sources.getFilename(Loc);
FileOffset = Sources.getFileOffset(Loc);
}
ClangTidyError::ClangTidyError(StringRef CheckName, ClangTidyError::ClangTidyError(StringRef CheckName,
ClangTidyError::Level DiagLevel, ClangTidyError::Level DiagLevel,
bool IsWarningAsError, StringRef BuildDirectory) StringRef BuildDirectory, bool IsWarningAsError)
: CheckName(CheckName), BuildDirectory(BuildDirectory), : tooling::Diagnostic(CheckName, DiagLevel, BuildDirectory),
DiagLevel(DiagLevel), IsWarningAsError(IsWarningAsError) {} IsWarningAsError(IsWarningAsError) {}
// Returns true if GlobList starts with the negative indicator ('-'), removes it // Returns true if GlobList starts with the negative indicator ('-'), removes it
// from the GlobList. // from the GlobList.
@ -260,7 +248,7 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer(ClangTidyContext &Ctx)
void ClangTidyDiagnosticConsumer::finalizeLastError() { void ClangTidyDiagnosticConsumer::finalizeLastError() {
if (!Errors.empty()) { if (!Errors.empty()) {
ClangTidyError &Error = Errors.back(); ClangTidyError &Error = Errors.back();
if (!Context.getChecksFilter().contains(Error.CheckName) && if (!Context.getChecksFilter().contains(Error.DiagnosticName) &&
Error.DiagLevel != ClangTidyError::Error) { Error.DiagLevel != ClangTidyError::Error) {
++Context.Stats.ErrorsIgnoredCheckFilter; ++Context.Stats.ErrorsIgnoredCheckFilter;
Errors.pop_back(); Errors.pop_back();
@ -366,8 +354,8 @@ void ClangTidyDiagnosticConsumer::HandleDiagnostic(
bool IsWarningAsError = bool IsWarningAsError =
DiagLevel == DiagnosticsEngine::Warning && DiagLevel == DiagnosticsEngine::Warning &&
Context.getWarningAsErrorFilter().contains(CheckName); Context.getWarningAsErrorFilter().contains(CheckName);
Errors.push_back(ClangTidyError(CheckName, Level, IsWarningAsError, Errors.emplace_back(CheckName, Level, Context.getCurrentBuildDirectory(),
Context.getCurrentBuildDirectory())); IsWarningAsError);
} }
ClangTidyDiagnosticRenderer Converter( ClangTidyDiagnosticRenderer Converter(
@ -532,10 +520,9 @@ void ClangTidyDiagnosticConsumer::removeIncompatibleErrors(
// FIXME: Handle empty intervals, such as those from insertions. // FIXME: Handle empty intervals, such as those from insertions.
if (Begin == End) if (Begin == End)
continue; continue;
FileEvents[FilePath].push_back( auto &Events = FileEvents[FilePath];
Event(Begin, End, Event::ET_Begin, I, Sizes[I])); Events.emplace_back(Begin, End, Event::ET_Begin, I, Sizes[I]);
FileEvents[FilePath].push_back( Events.emplace_back(Begin, End, Event::ET_End, I, Sizes[I]);
Event(Begin, End, Event::ET_End, I, Sizes[I]));
} }
} }
} }
@ -562,9 +549,8 @@ void ClangTidyDiagnosticConsumer::removeIncompatibleErrors(
for (unsigned I = 0; I < Errors.size(); ++I) { for (unsigned I = 0; I < Errors.size(); ++I) {
if (!Apply[I]) { if (!Apply[I]) {
Errors[I].Fix.clear(); Errors[I].Fix.clear();
Errors[I].Notes.push_back( Errors[I].Notes.emplace_back(
ClangTidyMessage("this fix will not be applied because" "this fix will not be applied because it overlaps with another fix");
" it overlaps with another fix"));
} }
} }
} }
@ -572,8 +558,8 @@ void ClangTidyDiagnosticConsumer::removeIncompatibleErrors(
namespace { namespace {
struct LessClangTidyError { struct LessClangTidyError {
bool operator()(const ClangTidyError &LHS, const ClangTidyError &RHS) const { bool operator()(const ClangTidyError &LHS, const ClangTidyError &RHS) const {
const ClangTidyMessage &M1 = LHS.Message; const tooling::DiagnosticMessage &M1 = LHS.Message;
const ClangTidyMessage &M2 = RHS.Message; const tooling::DiagnosticMessage &M2 = RHS.Message;
return std::tie(M1.FilePath, M1.FileOffset, M1.Message) < return std::tie(M1.FilePath, M1.FileOffset, M1.Message) <
std::tie(M2.FilePath, M2.FileOffset, M2.Message); std::tie(M2.FilePath, M2.FileOffset, M2.Message);

View File

@ -13,6 +13,7 @@
#include "ClangTidyOptions.h" #include "ClangTidyOptions.h"
#include "clang/Basic/Diagnostic.h" #include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManager.h"
#include "clang/Tooling/Core/Diagnostic.h"
#include "clang/Tooling/Refactoring.h" #include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
@ -32,18 +33,6 @@ class CompilationDatabase;
namespace tidy { namespace tidy {
/// \brief A message from a clang-tidy check.
///
/// Note that this is independent of a \c SourceManager.
struct ClangTidyMessage {
ClangTidyMessage(StringRef Message = "");
ClangTidyMessage(StringRef Message, const SourceManager &Sources,
SourceLocation Loc);
std::string Message;
std::string FilePath;
unsigned FileOffset;
};
/// \brief A detected error complete with information to display diagnostic and /// \brief A detected error complete with information to display diagnostic and
/// automatic fix. /// automatic fix.
/// ///
@ -51,31 +40,10 @@ struct ClangTidyMessage {
/// dependency on a SourceManager. /// dependency on a SourceManager.
/// ///
/// FIXME: Make Diagnostics flexible enough to support this directly. /// FIXME: Make Diagnostics flexible enough to support this directly.
struct ClangTidyError { struct ClangTidyError : tooling::Diagnostic {
enum Level { ClangTidyError(StringRef CheckName, Level DiagLevel, StringRef BuildDirectory,
Warning = DiagnosticsEngine::Warning, bool IsWarningAsError);
Error = DiagnosticsEngine::Error
};
ClangTidyError(StringRef CheckName, Level DiagLevel, bool IsWarningAsError,
StringRef BuildDirectory);
std::string CheckName;
ClangTidyMessage Message;
// Fixes grouped by file path.
llvm::StringMap<tooling::Replacements> Fix;
SmallVector<ClangTidyMessage, 1> Notes;
// A build directory of the diagnostic source file.
//
// It's an absolute path which is `directory` field of the source file in
// compilation database. If users don't specify the compilation database
// directory, it is the current directory where clang-tidy runs.
//
// Note: it is empty in unittest.
std::string BuildDirectory;
Level DiagLevel;
bool IsWarningAsError; bool IsWarningAsError;
}; };

View File

@ -403,7 +403,7 @@ static int clangTidyMain(int argc, const char **argv) {
llvm::errs() << "Error opening output file: " << EC.message() << '\n'; llvm::errs() << "Error opening output file: " << EC.message() << '\n';
return 1; return 1;
} }
exportReplacements(Errors, OS); exportReplacements(FilePath.str(), Errors, OS);
} }
printStats(Stats); printStats(Stats);

View File

@ -1,20 +1,22 @@
--- ---
MainSourceFile: source1.cpp MainSourceFile: source1.cpp
Replacements: Diagnostics:
- FilePath: $(path)/basic.h - DiagnosticName: test-basic
Offset: 242 Replacements:
Length: 26 - FilePath: $(path)/basic.h
ReplacementText: 'auto & elem : ints' Offset: 242
- FilePath: $(path)/basic.h Length: 26
Offset: 276 ReplacementText: 'auto & elem : ints'
Length: 22 - FilePath: $(path)/basic.h
ReplacementText: '' Offset: 276
- FilePath: $(path)/basic.h Length: 22
Offset: 298 ReplacementText: ''
Length: 1 - FilePath: $(path)/basic.h
ReplacementText: elem Offset: 298
- FilePath: $(path)/../basic/basic.h Length: 1
Offset: 148 ReplacementText: elem
Length: 0 - FilePath: $(path)/../basic/basic.h
ReplacementText: 'override ' Offset: 148
Length: 0
ReplacementText: 'override '
... ...

View File

@ -1,8 +1,10 @@
--- ---
MainSourceFile: source2.cpp MainSourceFile: source2.cpp
Replacements: Diagnostics:
- FilePath: $(path)/basic.h - DiagnosticName: test-basic
Offset: 148 Replacements:
Length: 0 - FilePath: $(path)/basic.h
ReplacementText: 'override ' Offset: 148
Length: 0
ReplacementText: 'override '
... ...

View File

@ -1,16 +1,18 @@
--- ---
MainSourceFile: source1.cpp MainSourceFile: source1.cpp
Replacements: Diagnostics:
- FilePath: $(path)/common.h - DiagnosticName: test-conflict
Offset: 106 Replacements:
Length: 26 - FilePath: $(path)/common.h
ReplacementText: 'auto & i : ints' Offset: 106
- FilePath: $(path)/common.h Length: 26
Offset: 140 ReplacementText: 'auto & i : ints'
Length: 7 - FilePath: $(path)/common.h
ReplacementText: i Offset: 140
- FilePath: $(path)/common.h Length: 7
Offset: 160 ReplacementText: i
Length: 12 - FilePath: $(path)/common.h
ReplacementText: '' Offset: 160
Length: 12
ReplacementText: ''
... ...

View File

@ -1,16 +1,18 @@
--- ---
MainSourceFile: source2.cpp MainSourceFile: source2.cpp
Replacements: Diagnostics:
- FilePath: $(path)/common.h - DiagnosticName: test-conflict
Offset: 106 Replacements:
Length: 26 - FilePath: $(path)/common.h
ReplacementText: 'int & elem : ints' Offset: 106
- FilePath: $(path)/common.h Length: 26
Offset: 140 ReplacementText: 'int & elem : ints'
Length: 7 - FilePath: $(path)/common.h
ReplacementText: elem Offset: 140
- FilePath: $(path)/common.h Length: 7
Offset: 169 ReplacementText: elem
Length: 1 - FilePath: $(path)/common.h
ReplacementText: nullptr Offset: 169
Length: 1
ReplacementText: nullptr
... ...

View File

@ -1,8 +1,10 @@
--- ---
MainSourceFile: source1.cpp MainSourceFile: source1.cpp
Replacements: Diagnostics:
- FilePath: $(path)/common.h - DiagnosticName: test-conflict
Offset: 169 Replacements:
Length: 0 - FilePath: $(path)/common.h
ReplacementText: "(int*)" Offset: 169
Length: 0
ReplacementText: "(int*)"
... ...

View File

@ -1,8 +1,10 @@
--- ---
MainSourceFile: source1.cpp MainSourceFile: source1.cpp
Replacements: Diagnostics:
- FilePath: $(path)/crlf.cpp - DiagnosticName: test-crlf
Offset: 79 Replacements:
Length: 1 - FilePath: $(path)/crlf.cpp
ReplacementText: nullptr Offset: 79
Length: 1
ReplacementText: nullptr
... ...

View File

@ -1,8 +1,10 @@
--- ---
MainSourceFile: no.cpp MainSourceFile: no.cpp
Replacements: Diagnostics:
- FilePath: $(path)/no.cpp - DiagnosticName: test-no
Offset: 94 Replacements:
Length: 3 - FilePath: $(path)/no.cpp
ReplacementText: 'auto ' Offset: 94
Length: 3
ReplacementText: 'auto '
... ...

View File

@ -2,21 +2,23 @@
# so that formatting happens correctly. # so that formatting happens correctly.
--- ---
MainSourceFile: yes.cpp MainSourceFile: yes.cpp
Replacements: Diagnostics:
- FilePath: $(path)/yes.cpp - DiagnosticName: test-yes
Offset: 494 Replacements:
Length: 1 - FilePath: $(path)/yes.cpp
ReplacementText: nullptr Offset: 494
- FilePath: $(path)/yes.cpp Length: 1
Offset: 410 ReplacementText: nullptr
Length: 1 - FilePath: $(path)/yes.cpp
ReplacementText: nullptr Offset: 410
- FilePath: $(path)/yes.cpp Length: 1
Offset: 454 ReplacementText: nullptr
Length: 1 - FilePath: $(path)/yes.cpp
ReplacementText: nullptr Offset: 454
- FilePath: $(path)/yes.cpp Length: 1
Offset: 108 ReplacementText: nullptr
Length: 38 - FilePath: $(path)/yes.cpp
ReplacementText: 'auto ' Offset: 108
Length: 38
ReplacementText: 'auto '
... ...