Hi djasper,
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.
http://llvm-reviews.chandlerc.com/D2444
Files:
clang-tidy/ClangTidy.cpp
clang-tidy/ClangTidy.h
clang-tidy/ClangTidyModule.cpp
clang-tidy/ClangTidyModule.h
clang-tidy/tool/ClangTidyMain.cpp
Index: clang-tidy/ClangTidy.cpp
===================================================================
--- clang-tidy/ClangTidy.cpp
+++ 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,45 +79,64 @@
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
/// way we can currently get to AnalysisAction::CreateASTConsumer. Ideally
/// we'd want to build a more generic way to use \c FrontendAction based
/// 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(Twine(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(Twine(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,26 +158,41 @@
return true;
}
- std::string CheckRegexString;
+ ChecksFilter &Filter;
SmallVectorImpl<ClangTidyCheck *> &Checks;
ClangTidyContext &Context;
MatchFinder &Finder;
};
+class RegexChecksFilter : public ChecksFilter {
+public:
+ RegexChecksFilter(StringRef EnableChecksRegex, StringRef DisableChecksRegex)
+ : EnableChecks(EnableChecksRegex), DisableChecks(DisableChecksRegex) {}
+
+ bool IsCheckEnabled(StringRef Name) LLVM_OVERRIDE {
+ return EnableChecks.match(Name) && !DisableChecks.match(Name);
+ }
+
+private:
+ llvm::Regex EnableChecks;
+ llvm::Regex DisableChecks;
+};
+
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) {
OwningPtr<ClangTidyModule> Module(I->instantiate());
Module->addCheckFactories(CheckFactories);
}
SmallVector<ClangTidyCheck *, 16> Checks;
- CheckFactories.createChecks(CheckRegexString, Checks);
+ CheckFactories.createChecks(Filter, Checks);
for (SmallVectorImpl<ClangTidyCheck *>::iterator I = Checks.begin(),
E = Checks.end();
@@ -168,14 +203,34 @@
}
virtual FrontendAction *create() {
- return new ClangTidyAction(CheckRegexString, Checks, Context, Finder);
+ return new ClangTidyAction(Filter, Checks, Context, Finder);
+ }
+
+ void getCheckNames(SmallVectorImpl<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);
}
private:
- std::string CheckRegexString;
+ RegexChecksFilter Filter;
SmallVector<ClangTidyCheck *, 8> Checks;
ClangTidyContext &Context;
MatchFinder Finder;
+ ClangTidyCheckFactories CheckFactories;
};
} // namespace
@@ -217,12 +272,26 @@
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);
+}
+
+void getCheckNames(StringRef EnableChecksRegex, StringRef DisableChecksRegex,
+ SmallVectorImpl<std::string> &CheckNames) {
+ CheckNames.clear();
+ SmallVector<ClangTidyError, 8> Errors;
+ clang::tidy::ClangTidyContext Context(&Errors);
+ ClangTidyActionFactory Factory(EnableChecksRegex, DisableChecksRegex,
+ Context);
+ Factory.getCheckNames(CheckNames);
+ std::sort(CheckNames.begin(), CheckNames.end());
}
-void runClangTidy(StringRef CheckRegexString,
+void runClangTidy(StringRef EnableChecksRegex, StringRef DisableChecksRegex,
const tooling::CompilationDatabase &Compilations,
ArrayRef<std::string> Ranges,
SmallVectorImpl<ClangTidyError> *Errors) {
@@ -233,7 +302,8 @@
ClangTidyDiagnosticConsumer DiagConsumer(Context);
Tool.setDiagnosticConsumer(&DiagConsumer);
- Tool.run(createClangTidyActionFactory(CheckRegexString, Context));
+ Tool.run(createClangTidyActionFactory(EnableChecksRegex, DisableChecksRegex,
+ Context));
}
static void reportDiagnostic(const ClangTidyMessage &Message,
Index: clang-tidy/ClangTidy.h
===================================================================
--- clang-tidy/ClangTidy.h
+++ clang-tidy/ClangTidy.h
@@ -85,13 +85,19 @@
virtual void run(const ast_matchers::MatchFinder::MatchResult &Result);
};
+/// \brief Fills the list of check names, that are enabled when the provided
+/// filters are applied.
+void getCheckNames(StringRef EnableChecksRegex, StringRef DisableChecksRegex,
+ SmallVectorImpl<std::string> &CheckNames);
+
/// \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);
Index: clang-tidy/ClangTidyModule.cpp
===================================================================
--- clang-tidy/ClangTidyModule.cpp
+++ 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::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());
}
}
Index: clang-tidy/ClangTidyModule.h
===================================================================
--- clang-tidy/ClangTidyModule.h
+++ clang-tidy/ClangTidyModule.h
@@ -26,7 +26,7 @@
/// this subclass in \c ClangTidyModule::addCheckFactories().
class CheckFactoryBase {
public:
- virtual ~CheckFactoryBase();
+ virtual ~CheckFactoryBase() {}
virtual ClangTidyCheck *createCheck() = 0;
};
@@ -66,6 +66,13 @@
virtual void addCheckFactories(ClangTidyCheckFactories &CheckFactories) = 0;
};
+/// \brief Filters checks by name.
+class ChecksFilter {
+public:
+ virtual ~ChecksFilter() {}
+ virtual bool IsCheckEnabled(StringRef CheckName) = 0;
+};
+
/// \brief A collection of \c ClangTidyCheckFactory instances.
///
/// All clang-tidy modules register their check factories with an instance of
@@ -84,12 +91,15 @@
/// 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
Index: clang-tidy/tool/ClangTidyMain.cpp
===================================================================
--- clang-tidy/tool/ClangTidyMain.cpp
+++ 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 @@
"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) {
+ SmallVector<std::string, 8> CheckNames;
+ clang::tidy::getCheckNames(Checks, DisableChecks, CheckNames);
+ 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);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits