mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-03-03 16:13:44 +00:00
Output messages when clang-tidy applies fix-its.
Reviewers: djasper, klimek Reviewed By: djasper CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D3192 llvm-svn: 204909
This commit is contained in:
parent
f17da19f34
commit
38d81b41eb
@ -25,6 +25,7 @@
|
||||
#include "clang/Frontend/ASTConsumers.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "clang/Frontend/MultiplexConsumer.h"
|
||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||
#include "clang/Lex/PPCallbacks.h"
|
||||
@ -38,6 +39,7 @@
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
@ -90,6 +92,84 @@ private:
|
||||
ClangTidyContext &Context;
|
||||
};
|
||||
|
||||
class ErrorReporter {
|
||||
public:
|
||||
ErrorReporter(bool ApplyFixes)
|
||||
: Files(FileSystemOptions()), DiagOpts(new DiagnosticOptions()),
|
||||
DiagPrinter(new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts)),
|
||||
Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs), &*DiagOpts,
|
||||
DiagPrinter),
|
||||
SourceMgr(Diags, Files), Rewrite(SourceMgr, LangOpts),
|
||||
ApplyFixes(ApplyFixes) {
|
||||
DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors();
|
||||
DiagPrinter->BeginSourceFile(LangOpts);
|
||||
}
|
||||
|
||||
void reportDiagnostic(const ClangTidyMessage &Message,
|
||||
DiagnosticsEngine::Level Level,
|
||||
const tooling::Replacements *Fixes = nullptr) {
|
||||
SourceLocation Loc = getLocation(Message.FilePath, Message.FileOffset);
|
||||
// Contains a pair for each attempted fix: location and whether the fix was
|
||||
// applied successfully.
|
||||
SmallVector<std::pair<SourceLocation, bool>, 4> FixLocations;
|
||||
{
|
||||
DiagnosticBuilder Diag =
|
||||
Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0"))
|
||||
<< Message.Message;
|
||||
if (Fixes != NULL) {
|
||||
for (const tooling::Replacement &Fix : *Fixes) {
|
||||
SourceLocation FixLoc =
|
||||
getLocation(Fix.getFilePath(), Fix.getOffset());
|
||||
SourceLocation FixEndLoc = FixLoc.getLocWithOffset(Fix.getLength());
|
||||
Diag << FixItHint::CreateReplacement(SourceRange(FixLoc, FixEndLoc),
|
||||
Fix.getReplacementText());
|
||||
++TotalFixes;
|
||||
if (ApplyFixes) {
|
||||
bool Success = Fix.isApplicable() && Fix.apply(Rewrite);
|
||||
if (Success)
|
||||
++AppliedFixes;
|
||||
FixLocations.push_back(std::make_pair(FixLoc, Success));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto Fix : FixLocations) {
|
||||
Diags.Report(Fix.first, Fix.second ? diag::note_fixit_applied
|
||||
: diag::note_fixit_failed);
|
||||
}
|
||||
}
|
||||
|
||||
void Finish() {
|
||||
// FIXME: Run clang-format on changes.
|
||||
if (ApplyFixes && TotalFixes > 0) {
|
||||
llvm::errs() << "clang-tidy applied " << AppliedFixes << " of "
|
||||
<< TotalFixes << " suggested fixes.\n";
|
||||
Rewrite.overwriteChangedFiles();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SourceLocation getLocation(StringRef FilePath, unsigned Offset) {
|
||||
if (FilePath.empty())
|
||||
return SourceLocation();
|
||||
|
||||
const FileEntry *File = SourceMgr.getFileManager().getFile(FilePath);
|
||||
FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
|
||||
return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
|
||||
}
|
||||
|
||||
FileManager Files;
|
||||
LangOptions LangOpts; // FIXME: use langopts from each original file
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts;
|
||||
DiagnosticConsumer *DiagPrinter;
|
||||
DiagnosticsEngine Diags;
|
||||
SourceManager SourceMgr;
|
||||
Rewriter Rewrite;
|
||||
bool ApplyFixes;
|
||||
unsigned TotalFixes = 0;
|
||||
unsigned AppliedFixes = 0;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
ClangTidyASTConsumerFactory::ClangTidyASTConsumerFactory(
|
||||
@ -252,59 +332,15 @@ void runClangTidy(StringRef EnableChecksRegex, StringRef DisableChecksRegex,
|
||||
Tool.run(new ActionFactory(new ClangTidyASTConsumerFactory(Context)));
|
||||
}
|
||||
|
||||
static SourceLocation getLocation(SourceManager &SourceMgr, StringRef FilePath,
|
||||
unsigned Offset) {
|
||||
if (FilePath.empty())
|
||||
return SourceLocation();
|
||||
|
||||
const FileEntry *File = SourceMgr.getFileManager().getFile(FilePath);
|
||||
FileID ID = SourceMgr.createFileID(File, SourceLocation(), SrcMgr::C_User);
|
||||
return SourceMgr.getLocForStartOfFile(ID).getLocWithOffset(Offset);
|
||||
}
|
||||
|
||||
static void reportDiagnostic(const ClangTidyMessage &Message,
|
||||
SourceManager &SourceMgr,
|
||||
DiagnosticsEngine::Level Level,
|
||||
DiagnosticsEngine &Diags,
|
||||
const tooling::Replacements *Fixes = NULL) {
|
||||
SourceLocation Loc =
|
||||
getLocation(SourceMgr, Message.FilePath, Message.FileOffset);
|
||||
DiagnosticBuilder Diag = Diags.Report(Loc, Diags.getCustomDiagID(Level, "%0"))
|
||||
<< Message.Message;
|
||||
if (Fixes != NULL) {
|
||||
for (const tooling::Replacement &Fix : *Fixes) {
|
||||
SourceLocation FixLoc =
|
||||
getLocation(SourceMgr, Fix.getFilePath(), Fix.getOffset());
|
||||
Diag << FixItHint::CreateReplacement(
|
||||
SourceRange(FixLoc, FixLoc.getLocWithOffset(Fix.getLength())),
|
||||
Fix.getReplacementText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleErrors(SmallVectorImpl<ClangTidyError> &Errors, bool Fix) {
|
||||
FileManager Files((FileSystemOptions()));
|
||||
LangOptions LangOpts; // FIXME: use langopts from each original file
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
||||
DiagOpts->ShowColors = llvm::sys::Process::StandardOutHasColors();
|
||||
DiagnosticConsumer *DiagPrinter =
|
||||
new TextDiagnosticPrinter(llvm::outs(), &*DiagOpts);
|
||||
DiagnosticsEngine Diags(IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
|
||||
&*DiagOpts, DiagPrinter);
|
||||
DiagPrinter->BeginSourceFile(LangOpts);
|
||||
SourceManager SourceMgr(Diags, Files);
|
||||
Rewriter Rewrite(SourceMgr, LangOpts);
|
||||
ErrorReporter Reporter(Fix);
|
||||
for (const ClangTidyError &Error : Errors) {
|
||||
reportDiagnostic(Error.Message, SourceMgr, DiagnosticsEngine::Warning, Diags,
|
||||
&Error.Fix);
|
||||
Reporter.reportDiagnostic(Error.Message, DiagnosticsEngine::Warning,
|
||||
&Error.Fix);
|
||||
for (const ClangTidyMessage &Note : Error.Notes)
|
||||
reportDiagnostic(Note, SourceMgr, DiagnosticsEngine::Note, Diags);
|
||||
|
||||
tooling::applyAllReplacements(Error.Fix, Rewrite);
|
||||
Reporter.reportDiagnostic(Note, DiagnosticsEngine::Note);
|
||||
}
|
||||
// FIXME: Run clang-format on changes.
|
||||
if (Fix)
|
||||
Rewrite.overwriteChangedFiles();
|
||||
Reporter.Finish();
|
||||
}
|
||||
|
||||
} // namespace tidy
|
||||
|
@ -1,10 +1,14 @@
|
||||
// RUN: grep -Ev "// *[A-Z-]+:" %s > %t.cpp
|
||||
// RUN: clang-tidy %t.cpp -fix --
|
||||
// RUN: clang-tidy %t.cpp -fix -- > %t.msg 2>&1
|
||||
// RUN: FileCheck -input-file=%t.cpp %s
|
||||
// RUN: FileCheck -input-file=%t.msg -check-prefix=CHECK-MESSAGES %s
|
||||
|
||||
namespace i {
|
||||
}
|
||||
// CHECK: } // namespace i
|
||||
// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
|
||||
|
||||
class A { A(int i); };
|
||||
// CHECK: class A { explicit A(int i); };
|
||||
// CHECK-MESSAGES: note: FIX-IT applied suggested code changes
|
||||
// CHECK-MESSAGES: clang-tidy applied 2 of 2 suggested fixes.
|
||||
|
Loading…
x
Reference in New Issue
Block a user