[clang-tools-extra] r197717 - Clang-tidy: added --disable-checks, --list-checks options.

Alexander Kornienko alexfh at google.com
Thu Dec 19 11:57:05 PST 2013


Author: alexfh
Date: Thu Dec 19 13:57:05 2013
New Revision: 197717

URL: http://llvm.org/viewvc/llvm-project?rev=197717&view=rev
Log:
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

Modified:
    clang-tools-extra/trunk/clang-tidy/ClangTidy.cpp
    clang-tools-extra/trunk/clang-tidy/ClangTidy.h
    clang-tools-extra/trunk/clang-tidy/ClangTidyModule.cpp
    clang-tools-extra/trunk/clang-tidy/ClangTidyModule.h
    clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidy.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidy.cpp?rev=197717&r1=197716&r2=197717&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidy.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidy.cpp Thu Dec 19 13:57:05 2013
@@ -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_match
   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 CheckRegexSt
   ClangTidyDiagnosticConsumer DiagConsumer(Context);
 
   Tool.setDiagnosticConsumer(&DiagConsumer);
-  Tool.run(createClangTidyActionFactory(CheckRegexString, Context));
+  Tool.run(createClangTidyActionFactory(EnableChecksRegex, DisableChecksRegex,
+                                        Context));
 }
 
 static void reportDiagnostic(const ClangTidyMessage &Message,

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidy.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidy.h?rev=197717&r1=197716&r2=197717&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidy.h (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidy.h Thu Dec 19 13:57:05 2013
@@ -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);

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyModule.cpp?rev=197717&r1=197716&r2=197717&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyModule.cpp Thu Dec 19 13:57:05 2013
@@ -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::addCheckFa
 }
 
 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());
   }
 }

Modified: clang-tools-extra/trunk/clang-tidy/ClangTidyModule.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/ClangTidyModule.h?rev=197717&r1=197716&r2=197717&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/ClangTidyModule.h (original)
+++ clang-tools-extra/trunk/clang-tidy/ClangTidyModule.h Thu Dec 19 13:57:05 2013
@@ -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

Modified: clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp?rev=197717&r1=197716&r2=197717&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/tool/ClangTidyMain.cpp Thu Dec 19 13:57:05 2013
@@ -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);
 





More information about the cfe-commits mailing list