forked from OSchip/llvm-project
[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:
parent
9bab199146
commit
563de799e3
|
@ -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,
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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,9 +230,8 @@ 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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
---
|
---
|
||||||
MainSourceFile: source1.cpp
|
MainSourceFile: source1.cpp
|
||||||
Replacements:
|
Diagnostics:
|
||||||
|
- DiagnosticName: test-basic
|
||||||
|
Replacements:
|
||||||
- FilePath: $(path)/basic.h
|
- FilePath: $(path)/basic.h
|
||||||
Offset: 242
|
Offset: 242
|
||||||
Length: 26
|
Length: 26
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
---
|
---
|
||||||
MainSourceFile: source2.cpp
|
MainSourceFile: source2.cpp
|
||||||
Replacements:
|
Diagnostics:
|
||||||
|
- DiagnosticName: test-basic
|
||||||
|
Replacements:
|
||||||
- FilePath: $(path)/basic.h
|
- FilePath: $(path)/basic.h
|
||||||
Offset: 148
|
Offset: 148
|
||||||
Length: 0
|
Length: 0
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
---
|
---
|
||||||
MainSourceFile: source1.cpp
|
MainSourceFile: source1.cpp
|
||||||
Replacements:
|
Diagnostics:
|
||||||
|
- DiagnosticName: test-conflict
|
||||||
|
Replacements:
|
||||||
- FilePath: $(path)/common.h
|
- FilePath: $(path)/common.h
|
||||||
Offset: 106
|
Offset: 106
|
||||||
Length: 26
|
Length: 26
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
---
|
---
|
||||||
MainSourceFile: source2.cpp
|
MainSourceFile: source2.cpp
|
||||||
Replacements:
|
Diagnostics:
|
||||||
|
- DiagnosticName: test-conflict
|
||||||
|
Replacements:
|
||||||
- FilePath: $(path)/common.h
|
- FilePath: $(path)/common.h
|
||||||
Offset: 106
|
Offset: 106
|
||||||
Length: 26
|
Length: 26
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
---
|
---
|
||||||
MainSourceFile: source1.cpp
|
MainSourceFile: source1.cpp
|
||||||
Replacements:
|
Diagnostics:
|
||||||
|
- DiagnosticName: test-conflict
|
||||||
|
Replacements:
|
||||||
- FilePath: $(path)/common.h
|
- FilePath: $(path)/common.h
|
||||||
Offset: 169
|
Offset: 169
|
||||||
Length: 0
|
Length: 0
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
---
|
---
|
||||||
MainSourceFile: source1.cpp
|
MainSourceFile: source1.cpp
|
||||||
Replacements:
|
Diagnostics:
|
||||||
|
- DiagnosticName: test-crlf
|
||||||
|
Replacements:
|
||||||
- FilePath: $(path)/crlf.cpp
|
- FilePath: $(path)/crlf.cpp
|
||||||
Offset: 79
|
Offset: 79
|
||||||
Length: 1
|
Length: 1
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
---
|
---
|
||||||
MainSourceFile: no.cpp
|
MainSourceFile: no.cpp
|
||||||
Replacements:
|
Diagnostics:
|
||||||
|
- DiagnosticName: test-no
|
||||||
|
Replacements:
|
||||||
- FilePath: $(path)/no.cpp
|
- FilePath: $(path)/no.cpp
|
||||||
Offset: 94
|
Offset: 94
|
||||||
Length: 3
|
Length: 3
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
# so that formatting happens correctly.
|
# so that formatting happens correctly.
|
||||||
---
|
---
|
||||||
MainSourceFile: yes.cpp
|
MainSourceFile: yes.cpp
|
||||||
Replacements:
|
Diagnostics:
|
||||||
|
- DiagnosticName: test-yes
|
||||||
|
Replacements:
|
||||||
- FilePath: $(path)/yes.cpp
|
- FilePath: $(path)/yes.cpp
|
||||||
Offset: 494
|
Offset: 494
|
||||||
Length: 1
|
Length: 1
|
||||||
|
|
Loading…
Reference in New Issue