aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clang-tidy/ClangTidy.cpp134
-rw-r--r--clang-tidy/ClangTidy.h21
-rw-r--r--clang-tidy/ClangTidyModule.cpp20
-rw-r--r--clang-tidy/ClangTidyModule.h11
-rw-r--r--clang-tidy/tool/ClangTidyMain.cpp23
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);