Add flag --enable-check-profile to clang-tidy.

Summary:
Add flag --enable-check-profile to clang-tidy.
It turns on per-matcher profiles in MatchFinder and prints a report to
stderr at the end.

Reviewers: alexfh

Subscribers: curdeius, cfe-commits

Differential Revision: http://reviews.llvm.org/D5937

llvm-svn: 220491
This commit is contained in:
Samuel Benzaquen 2014-10-23 17:23:20 +00:00
parent adffd01498
commit aedd994560
5 changed files with 89 additions and 5 deletions

View File

@ -216,8 +216,13 @@ ClangTidyASTConsumerFactory::CreateASTConsumer(
std::vector<std::unique_ptr<ClangTidyCheck>> Checks;
CheckFactories->createChecks(&Context, Checks);
ast_matchers::MatchFinder::MatchFinderOptions FinderOptions;
if (auto *P = Context.getCheckProfileData())
FinderOptions.CheckProfiling.emplace(P->Records);
std::unique_ptr<ast_matchers::MatchFinder> Finder(
new ast_matchers::MatchFinder);
new ast_matchers::MatchFinder(std::move(FinderOptions)));
for (auto &Check : Checks) {
Check->registerMatchers(&*Finder);
Check->registerPPCallbacks(Compiler);
@ -356,9 +361,12 @@ ClangTidyStats
runClangTidy(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
const tooling::CompilationDatabase &Compilations,
ArrayRef<std::string> InputFiles,
std::vector<ClangTidyError> *Errors) {
std::vector<ClangTidyError> *Errors, ProfileData *Profile) {
ClangTool Tool(Compilations, InputFiles);
clang::tidy::ClangTidyContext Context(std::move(OptionsProvider));
if (Profile)
Context.setCheckProfileData(Profile);
ClangTidyDiagnosticConsumer DiagConsumer(Context);
Tool.setDiagnosticConsumer(&DiagConsumer);

View File

@ -152,6 +152,7 @@ public:
private:
void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
StringRef getID() const override { return CheckName; }
std::string CheckName;
ClangTidyContext *Context;
@ -196,11 +197,15 @@ std::vector<std::string> getCheckNames(const ClangTidyOptions &Options);
ClangTidyOptions::OptionMap getCheckOptions(const ClangTidyOptions &Options);
/// \brief Run a set of clang-tidy checks on a set of files.
///
/// \param Profile if provided, it enables check profile collection in
/// MatchFinder, and will contain the result of the profile.
ClangTidyStats
runClangTidy(std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider,
const tooling::CompilationDatabase &Compilations,
ArrayRef<std::string> InputFiles,
std::vector<ClangTidyError> *Errors);
std::vector<ClangTidyError> *Errors,
ProfileData *Profile = nullptr);
// FIXME: This interface will need to be significantly extended to be useful.
// FIXME: Implement confidence levels for displaying/fixing errors.

View File

@ -162,7 +162,8 @@ bool GlobList::contains(StringRef S, bool Contains) {
ClangTidyContext::ClangTidyContext(
std::unique_ptr<ClangTidyOptionsProvider> OptionsProvider)
: DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)) {
: DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)),
Profile(nullptr) {
// Before the first translation unit we can get errors related to command-line
// parsing, use empty string for the file name in this case.
setCurrentFile("");
@ -221,6 +222,10 @@ const ClangTidyOptions &ClangTidyContext::getOptions() const {
return CurrentOptions;
}
void ClangTidyContext::setCheckProfileData(ProfileData *P) {
Profile = P;
}
GlobList &ClangTidyContext::getChecksFilter() {
assert(CheckFilter != nullptr);
return *CheckFilter;

View File

@ -15,7 +15,9 @@
#include "clang/Basic/SourceManager.h"
#include "clang/Tooling/Refactoring.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/Timer.h"
namespace clang {
@ -105,6 +107,11 @@ struct ClangTidyStats {
}
};
/// \brief Container for clang-tidy profiling data.
struct ProfileData {
llvm::StringMap<llvm::TimeRecord> Records;
};
/// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticEngine
/// provided by this context.
///
@ -162,6 +169,13 @@ public:
/// \brief Clears collected errors.
void clearErrors() { Errors.clear(); }
/// \brief Set the output struct for profile data.
///
/// Setting a non-null pointer here will enable profile collection in
/// clang-tidy.
void setCheckProfileData(ProfileData* Profile);
ProfileData* getCheckProfileData() const { return Profile; }
private:
// Calls setDiagnosticsEngine() and storeError().
friend class ClangTidyDiagnosticConsumer;
@ -184,6 +198,8 @@ private:
ClangTidyStats Stats;
llvm::DenseMap<unsigned, std::string> CheckNamesByDiagnosticID;
ProfileData *Profile;
};
/// \brief A diagnostic consumer that turns each \c Diagnostic into a

View File

@ -98,6 +98,11 @@ DumpConfig("dump-config",
cl::desc("Dumps configuration in the YAML format to stdout."),
cl::init(false), cl::cat(ClangTidyCategory));
static cl::opt<bool> EnableCheckProfile(
"enable-check-profile",
cl::desc("Enable per-check timing profiles, and print a report to stderr."),
cl::init(false), cl::cat(ClangTidyCategory));
static cl::opt<bool> AnalyzeTemporaryDtors(
"analyze-temporary-dtors",
cl::desc("Enable temporary destructor-aware analysis in\n"
@ -143,6 +148,45 @@ static void printStats(const ClangTidyStats &Stats) {
}
}
static void printProfileData(const ProfileData &Profile,
llvm::raw_ostream &OS) {
// Time is first to allow for sorting by it.
std::vector<std::pair<llvm::TimeRecord, StringRef>> Timers;
TimeRecord Total;
for (const auto& P : Profile.Records) {
Timers.emplace_back(P.getValue(), P.getKey());
Total += P.getValue();
}
std::sort(Timers.begin(), Timers.end());
std::string Line = "===" + std::string(73, '-') + "===\n";
OS << Line;
if (Total.getUserTime())
OS << " ---User Time---";
if (Total.getSystemTime())
OS << " --System Time--";
if (Total.getProcessTime())
OS << " --User+System--";
OS << " ---Wall Time---";
if (Total.getMemUsed())
OS << " ---Mem---";
OS << " --- Name ---\n";
// Loop through all of the timing data, printing it out.
for (auto I = Timers.rbegin(), E = Timers.rend(); I != E; ++I) {
I->first.print(Total, OS);
OS << I->second << '\n';
}
Total.print(Total, OS);
OS << "Total\n";
OS << Line << "\n";
OS.flush();
}
std::unique_ptr<ClangTidyOptionsProvider> createOptionsProvider() {
ClangTidyGlobalOptions GlobalOptions;
if (std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) {
@ -220,10 +264,13 @@ int clangTidyMain(int argc, const char **argv) {
return 1;
}
ProfileData Profile;
std::vector<ClangTidyError> Errors;
ClangTidyStats Stats =
runClangTidy(std::move(OptionsProvider), OptionsParser.getCompilations(),
OptionsParser.getSourcePathList(), &Errors);
OptionsParser.getSourcePathList(), &Errors,
EnableCheckProfile ? &Profile : nullptr);
handleErrors(Errors, Fix);
if (!ExportFixes.empty() && !Errors.empty()) {
@ -237,6 +284,9 @@ int clangTidyMain(int argc, const char **argv) {
}
printStats(Stats);
if (EnableCheckProfile)
printProfileData(Profile, llvm::errs());
return 0;
}