diff options
author | Alexander Kornienko <alexfh@google.com> | 2013-12-19 19:57:05 +0000 |
---|---|---|
committer | Alexander Kornienko <alexfh@google.com> | 2013-12-19 19:57:05 +0000 |
commit | f0c740b38285ace936401dc735e7e4e511aad8aa (patch) | |
tree | 95c7bee795af8d78ef02a2a2944feb3f06c20408 | |
parent | 6d817272e2e36ec76588f6089fe5d096a82cfb97 (diff) |
Clang-tidy: added --disable-checks, --list-checks options.
Summary:
Allow disabling checks by regex. By default, disable alpha.* checks,
that are not particularly good tested (e.g. IdempotentOperationChecker, see
http://llvm-reviews.chandlerc.com/D2427).
Fixed a bug, that would disable all analyzer checks, when using a regex more
strict, than 'clang-analyzer-', for example --checks='clang-analyzer-deadcode-'.
Added --list-checks to list all enabled checks. This is useful to test specific
values in --checks/--disable-checks.
Reviewers: djasper, klimek
Reviewed By: klimek
CC: cfe-commits, klimek
Differential Revision: http://llvm-reviews.chandlerc.com/D2444
git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@197717 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | clang-tidy/ClangTidy.cpp | 134 | ||||
-rw-r--r-- | clang-tidy/ClangTidy.h | 21 | ||||
-rw-r--r-- | clang-tidy/ClangTidyModule.cpp | 20 | ||||
-rw-r--r-- | clang-tidy/ClangTidyModule.h | 11 | ||||
-rw-r--r-- | clang-tidy/tool/ClangTidyMain.cpp | 23 |
5 files changed, 152 insertions, 57 deletions
diff --git a/clang-tidy/ClangTidy.cpp b/clang-tidy/ClangTidy.cpp index 223f539a..b97a4e99 100644 --- a/clang-tidy/ClangTidy.cpp +++ b/clang-tidy/ClangTidy.cpp @@ -35,6 +35,7 @@ #include "clang/Tooling/Refactoring.h" #include "llvm/Support/Path.h" #include "llvm/Support/Signals.h" +#include <algorithm> #include <vector> using namespace clang::ast_matchers; @@ -78,6 +79,17 @@ private: llvm::OwningPtr<ASTConsumer> Consumer2; }; +static StringRef StaticAnalyzerCheckers[] = { +#define GET_CHECKERS +#define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \ + FULLNAME, +#include "../../../lib/StaticAnalyzer/Checkers/Checkers.inc" +#undef CHECKER +#undef GET_CHECKERS +}; + +static const char *AnalyzerCheckerNamePrefix = "clang-analyzer-"; + /// \brief Action that runs clang-tidy and static analyzer checks. /// /// FIXME: Note that this inherits from \c AnalysisAction as this is the only @@ -86,37 +98,45 @@ private: /// checkers in clang-tidy, but that needs some preparation work first. class ClangTidyAction : public ento::AnalysisAction { public: - ClangTidyAction(StringRef CheckRegexString, + ClangTidyAction(ChecksFilter &Filter, SmallVectorImpl<ClangTidyCheck *> &Checks, ClangTidyContext &Context, MatchFinder &Finder) - : CheckRegexString(CheckRegexString), Checks(Checks), Context(Context), - Finder(Finder) {} + : Filter(Filter), Checks(Checks), Context(Context), Finder(Finder) {} -private: - clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler, - StringRef File) LLVM_OVERRIDE { - AnalyzerOptionsRef Options = Compiler.getAnalyzerOpts(); - llvm::Regex CheckRegex(CheckRegexString); + typedef std::vector<std::pair<std::string, bool> > CheckersList; + void fillCheckersControlList(CheckersList &List) { + ArrayRef<StringRef> Checkers(StaticAnalyzerCheckers); + + bool AnalyzerChecksEnabled = false; + for (unsigned i = 0; i < Checkers.size(); ++i) { + std::string Checker((AnalyzerCheckerNamePrefix + Checkers[i]).str()); + AnalyzerChecksEnabled |= + Filter.IsCheckEnabled(Checker) && !Checkers[i].startswith("debug"); + } + + if (!AnalyzerChecksEnabled) + return; + // Run our regex against all possible static analyzer checkers. + // Note that debug checkers print values / run programs to visualize the CFG + // and are thus not applicable to clang-tidy in general. // Always add all core checkers if any other static analyzer checks are // enabled. This is currently necessary, as other path sensitive checks rely // on the core checkers. - if (CheckRegex.match("clang-analyzer-")) - Options->CheckersControlList.push_back(std::make_pair("core", true)); + for (unsigned i = 0; i < Checkers.size(); ++i) { + std::string Checker((AnalyzerCheckerNamePrefix + Checkers[i]).str()); -// Run our regex against all possible static analyzer checkers. -// Note that debug checkers print values / run programs to visualize the CFG -// and are thus not applicable to clang-tidy in general. -#define GET_CHECKERS -#define CHECKER(FULLNAME, CLASS, DESCFILE, HELPTEXT, GROUPINDEX, HIDDEN) \ - if (!StringRef(FULLNAME).startswith("core") && \ - !StringRef(FULLNAME).startswith("debug") && \ - CheckRegex.match("clang-analyzer-" FULLNAME)) \ - Options->CheckersControlList.push_back(std::make_pair(FULLNAME, true)); -#include "../../../lib/StaticAnalyzer/Checkers/Checkers.inc" -#undef CHECKER -#undef GET_CHECKERS + if (Checkers[i].startswith("core") || + (!Checkers[i].startswith("debug") && Filter.IsCheckEnabled(Checker))) + List.push_back(std::make_pair(Checkers[i], true)); + } + } +private: + clang::ASTConsumer *CreateASTConsumer(clang::CompilerInstance &Compiler, + StringRef File) LLVM_OVERRIDE { + AnalyzerOptionsRef Options = Compiler.getAnalyzerOpts(); + fillCheckersControlList(Options->CheckersControlList); Options->AnalysisStoreOpt = RegionStoreModel; Options->AnalysisDiagOpt = PD_TEXT; Options->AnalyzeNestedBlocks = true; @@ -138,7 +158,7 @@ private: return true; } - std::string CheckRegexString; + ChecksFilter &Filter; SmallVectorImpl<ClangTidyCheck *> &Checks; ClangTidyContext &Context; MatchFinder &Finder; @@ -146,9 +166,10 @@ private: class ClangTidyActionFactory : public FrontendActionFactory { public: - ClangTidyActionFactory(StringRef CheckRegexString, ClangTidyContext &Context) - : CheckRegexString(CheckRegexString), Context(Context) { - ClangTidyCheckFactories CheckFactories; + ClangTidyActionFactory(StringRef EnableChecksRegex, + StringRef DisableChecksRegex, + ClangTidyContext &Context) + : Filter(EnableChecksRegex, DisableChecksRegex), Context(Context) { for (ClangTidyModuleRegistry::iterator I = ClangTidyModuleRegistry::begin(), E = ClangTidyModuleRegistry::end(); I != E; ++I) { @@ -157,7 +178,7 @@ public: } SmallVector<ClangTidyCheck *, 16> Checks; - CheckFactories.createChecks(CheckRegexString, Checks); + CheckFactories.createChecks(Filter, Checks); for (SmallVectorImpl<ClangTidyCheck *>::iterator I = Checks.begin(), E = Checks.end(); @@ -168,18 +189,50 @@ public: } virtual FrontendAction *create() { - return new ClangTidyAction(CheckRegexString, Checks, Context, Finder); + return new ClangTidyAction(Filter, Checks, Context, Finder); + } + + std::vector<std::string> getCheckNames() { + std::vector<std::string> CheckNames; + for (ClangTidyCheckFactories::FactoryMap::const_iterator + I = CheckFactories.begin(), + E = CheckFactories.end(); + I != E; ++I) { + if (Filter.IsCheckEnabled(I->first)) + CheckNames.push_back(I->first); + } + + ClangTidyAction Action(Filter, Checks, Context, Finder); + ClangTidyAction::CheckersList AnalyzerChecks; + Action.fillCheckersControlList(AnalyzerChecks); + for (ClangTidyAction::CheckersList::const_iterator + I = AnalyzerChecks.begin(), + E = AnalyzerChecks.end(); + I != E; ++I) + CheckNames.push_back(AnalyzerCheckerNamePrefix + I->first); + + std::sort(CheckNames.begin(), CheckNames.end()); + return CheckNames; } private: - std::string CheckRegexString; + ChecksFilter Filter; SmallVector<ClangTidyCheck *, 8> Checks; ClangTidyContext &Context; MatchFinder Finder; + ClangTidyCheckFactories CheckFactories; }; } // namespace +ChecksFilter::ChecksFilter(StringRef EnableChecksRegex, + StringRef DisableChecksRegex) + : EnableChecks(EnableChecksRegex), DisableChecks(DisableChecksRegex) {} + +bool ChecksFilter::IsCheckEnabled(StringRef Name) { + return EnableChecks.match(Name) && !DisableChecks.match(Name); +} + ClangTidyMessage::ClangTidyMessage(StringRef Message) : Message(Message) {} ClangTidyMessage::ClangTidyMessage(StringRef Message, @@ -217,12 +270,24 @@ void ClangTidyCheck::run(const ast_matchers::MatchFinder::MatchResult &Result) { check(Result); } -FrontendActionFactory *createClangTidyActionFactory(StringRef CheckRegexString, - ClangTidyContext &Context) { - return new ClangTidyActionFactory(CheckRegexString, Context); +FrontendActionFactory * +createClangTidyActionFactory(StringRef EnableChecksRegex, + StringRef DisableChecksRegex, + ClangTidyContext &Context) { + return new ClangTidyActionFactory(EnableChecksRegex, DisableChecksRegex, + Context); +} + +std::vector<std::string> getCheckNames(StringRef EnableChecksRegex, + StringRef DisableChecksRegex) { + SmallVector<ClangTidyError, 8> Errors; + clang::tidy::ClangTidyContext Context(&Errors); + ClangTidyActionFactory Factory(EnableChecksRegex, DisableChecksRegex, + Context); + return Factory.getCheckNames(); } -void runClangTidy(StringRef CheckRegexString, +void runClangTidy(StringRef EnableChecksRegex, StringRef DisableChecksRegex, const tooling::CompilationDatabase &Compilations, ArrayRef<std::string> Ranges, SmallVectorImpl<ClangTidyError> *Errors) { @@ -233,7 +298,8 @@ void runClangTidy(StringRef CheckRegexString, ClangTidyDiagnosticConsumer DiagConsumer(Context); Tool.setDiagnosticConsumer(&DiagConsumer); - Tool.run(createClangTidyActionFactory(CheckRegexString, Context)); + Tool.run(createClangTidyActionFactory(EnableChecksRegex, DisableChecksRegex, + Context)); } static void reportDiagnostic(const ClangTidyMessage &Message, diff --git a/clang-tidy/ClangTidy.h b/clang-tidy/ClangTidy.h index 1916a524..9426c004 100644 --- a/clang-tidy/ClangTidy.h +++ b/clang-tidy/ClangTidy.h @@ -85,13 +85,30 @@ private: virtual void run(const ast_matchers::MatchFinder::MatchResult &Result); }; +/// \brief Filters checks by name. +class ChecksFilter { +public: + ChecksFilter(StringRef EnableChecksRegex, StringRef DisableChecksRegex); + bool IsCheckEnabled(StringRef Name); + +private: + llvm::Regex EnableChecks; + llvm::Regex DisableChecks; +}; + +/// \brief Fills the list of check names that are enabled when the provided +/// filters are applied. +std::vector<std::string> getCheckNames(StringRef EnableChecksRegex, + StringRef DisableChecksRegex); + /// \brief Returns an action factory that runs the specified clang-tidy checks. tooling::FrontendActionFactory * -createClangTidyActionFactory(StringRef CheckRegexString, +createClangTidyActionFactory(StringRef EnableChecksRegex, + StringRef DisableChecksRegex, ClangTidyContext &Context); /// \brief Run a set of clang-tidy checks on a set of files. -void runClangTidy(StringRef CheckRegexString, +void runClangTidy(StringRef EnableChecksRegex, StringRef DisableChecksRegex, const tooling::CompilationDatabase &Compilations, ArrayRef<std::string> Ranges, SmallVectorImpl<ClangTidyError> *Errors); diff --git a/clang-tidy/ClangTidyModule.cpp b/clang-tidy/ClangTidyModule.cpp index a81213ce..dc3a11d0 100644 --- a/clang-tidy/ClangTidyModule.cpp +++ b/clang-tidy/ClangTidyModule.cpp @@ -12,18 +12,13 @@ //===----------------------------------------------------------------------===// #include "ClangTidyModule.h" -#include "llvm/Support/Regex.h" namespace clang { namespace tidy { -CheckFactoryBase::~CheckFactoryBase() {} - ClangTidyCheckFactories::~ClangTidyCheckFactories() { - for (std::map<std::string, CheckFactoryBase *>::iterator - I = Factories.begin(), - E = Factories.end(); - I != E; ++I) { + for (FactoryMap::iterator I = Factories.begin(), E = Factories.end(); I != E; + ++I) { delete I->second; } } @@ -34,13 +29,10 @@ void ClangTidyCheckFactories::addCheckFactory(StringRef Name, } void ClangTidyCheckFactories::createChecks( - StringRef CheckRegexString, SmallVectorImpl<ClangTidyCheck *> &Checks) { - llvm::Regex CheckRegex(CheckRegexString); - for (std::map<std::string, CheckFactoryBase *>::iterator - I = Factories.begin(), - E = Factories.end(); - I != E; ++I) { - if (CheckRegex.match(I->first)) + ChecksFilter &Filter, SmallVectorImpl<ClangTidyCheck *> &Checks) { + for (FactoryMap::iterator I = Factories.begin(), E = Factories.end(); I != E; + ++I) { + if (Filter.IsCheckEnabled(I->first)) Checks.push_back(I->second->createCheck()); } } diff --git a/clang-tidy/ClangTidyModule.h b/clang-tidy/ClangTidyModule.h index 7008863b..830cbd5b 100644 --- a/clang-tidy/ClangTidyModule.h +++ b/clang-tidy/ClangTidyModule.h @@ -26,7 +26,7 @@ namespace tidy { /// this subclass in \c ClangTidyModule::addCheckFactories(). class CheckFactoryBase { public: - virtual ~CheckFactoryBase(); + virtual ~CheckFactoryBase() {} virtual ClangTidyCheck *createCheck() = 0; }; @@ -84,12 +84,15 @@ public: /// store them in \p Checks. /// /// The caller takes ownership of the return \c ClangTidyChecks. - void createChecks(StringRef CheckRegexString, + void createChecks(ChecksFilter &Filter, SmallVectorImpl<ClangTidyCheck *> &Checks); + typedef std::map<std::string, CheckFactoryBase *> FactoryMap; + FactoryMap::const_iterator begin() const { return Factories.begin(); } + FactoryMap::const_iterator end() const { return Factories.end(); } + private: - StringRef FilterRegex; - std::map<std::string, CheckFactoryBase *> Factories; + FactoryMap Factories; }; } // end namespace tidy diff --git a/clang-tidy/tool/ClangTidyMain.cpp b/clang-tidy/tool/ClangTidyMain.cpp index a71df0c7..5f1c1373 100644 --- a/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tidy/tool/ClangTidyMain.cpp @@ -17,7 +17,6 @@ #include "../ClangTidy.h" #include "clang/Tooling/CommonOptionsParser.h" -#include <vector> using namespace clang::ast_matchers; using namespace clang::driver; @@ -32,16 +31,34 @@ static cl::opt<std::string> Checks( "checks", cl::desc("Regular expression matching the names of the checks to be run."), cl::init(".*"), cl::cat(ClangTidyCategory)); +static cl::opt<std::string> DisableChecks( + "disable-checks", + cl::desc("Regular expression matching the names of the checks to disable."), + cl::init("clang-analyzer-alpha.*"), cl::cat(ClangTidyCategory)); static cl::opt<bool> Fix("fix", cl::desc("Fix detected errors if possible."), cl::init(false), cl::cat(ClangTidyCategory)); -// FIXME: Add option to list name/description of all checks. +static cl::opt<bool> ListChecks("list-checks", + cl::desc("List all enabled checks and exit."), + cl::init(false), cl::cat(ClangTidyCategory)); int main(int argc, const char **argv) { CommonOptionsParser OptionsParser(argc, argv, ClangTidyCategory); + // FIXME: Allow using --list-checks without positional arguments. + if (ListChecks) { + std::vector<std::string> CheckNames = + clang::tidy::getCheckNames(Checks, DisableChecks); + llvm::outs() << "Enabled checks:"; + for (unsigned i = 0; i < CheckNames.size(); ++i) + llvm::outs() << "\n " << CheckNames[i]; + llvm::outs() << "\n\n"; + return 0; + } + SmallVector<clang::tidy::ClangTidyError, 16> Errors; - clang::tidy::runClangTidy(Checks, OptionsParser.getCompilations(), + clang::tidy::runClangTidy(Checks, DisableChecks, + OptionsParser.getCompilations(), OptionsParser.getSourcePathList(), &Errors); clang::tidy::handleErrors(Errors, Fix); |