forked from OSchip/llvm-project
[analyzer] Overhaul of checker registration in preparation for basic plugin support. Removes support for checker groups (we can add them back in later if we decide they are still useful), and -analyzer-checker-help output is a little worse for the time being (no packages).
llvm-svn: 137758
This commit is contained in:
parent
d7c6c9141a
commit
59cce71af6
|
@ -0,0 +1,22 @@
|
|||
//===--- ClangCheckers.h - Provides builtin checkers ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_STATICANALYZER_CHECKERS_CLANGCHECKERS_H
|
||||
#define LLVM_CLANG_STATICANALYZER_CHECKERS_CLANGCHECKERS_H
|
||||
|
||||
namespace clang {
|
||||
namespace ento {
|
||||
class CheckerRegistry;
|
||||
|
||||
void registerBuiltinCheckers(CheckerRegistry ®istry);
|
||||
|
||||
} // end namespace ento
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -0,0 +1,78 @@
|
|||
//===--- CheckerOptInfo.h - Specifies which checkers to use -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
|
||||
#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
|
||||
namespace clang {
|
||||
namespace ento {
|
||||
|
||||
class CheckerOptInfo {
|
||||
StringRef Name;
|
||||
bool Enable;
|
||||
bool Claimed;
|
||||
|
||||
public:
|
||||
CheckerOptInfo(StringRef name, bool enable)
|
||||
: Name(name), Enable(enable), Claimed(false) { }
|
||||
|
||||
StringRef getName() const { return Name; }
|
||||
bool isEnabled() const { return Enable; }
|
||||
bool isDisabled() const { return !isEnabled(); }
|
||||
|
||||
bool isClaimed() const { return Claimed; }
|
||||
bool isUnclaimed() const { return !isClaimed(); }
|
||||
void claim() { Claimed = true; }
|
||||
};
|
||||
|
||||
} // end namespace ento
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
//===--- CheckerOptInfo.h - Specifies which checkers to use -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
|
||||
#define LLVM_CLANG_STATICANALYZER_CORE_CHECKEROPTINFO_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
|
||||
namespace clang {
|
||||
namespace ento {
|
||||
|
||||
class CheckerOptInfo {
|
||||
StringRef Name;
|
||||
bool Enable;
|
||||
bool Claimed;
|
||||
|
||||
public:
|
||||
CheckerOptInfo(StringRef name, bool enable)
|
||||
: Name(name), Enable(enable), Claimed(false) { }
|
||||
|
||||
StringRef getName() const { return Name; }
|
||||
bool isEnabled() const { return Enable; }
|
||||
bool isDisabled() const { return !isEnabled(); }
|
||||
|
||||
bool isClaimed() const { return Claimed; }
|
||||
bool isUnclaimed() const { return !isClaimed(); }
|
||||
void claim() { Claimed = true; }
|
||||
};
|
||||
|
||||
} // end namespace ento
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -1,55 +0,0 @@
|
|||
//===--- CheckerProvider.h - Static Analyzer Checkers Provider --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines the Static Analyzer Checker Provider.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H
|
||||
#define LLVM_CLANG_SA_CORE_CHECKERPROVIDER_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace ento {
|
||||
class CheckerManager;
|
||||
|
||||
class CheckerOptInfo {
|
||||
const char *Name;
|
||||
bool Enable;
|
||||
bool Claimed;
|
||||
|
||||
public:
|
||||
CheckerOptInfo(const char *name, bool enable)
|
||||
: Name(name), Enable(enable), Claimed(false) { }
|
||||
|
||||
const char *getName() const { return Name; }
|
||||
bool isEnabled() const { return Enable; }
|
||||
bool isDisabled() const { return !isEnabled(); }
|
||||
|
||||
bool isClaimed() const { return Claimed; }
|
||||
bool isUnclaimed() const { return !isClaimed(); }
|
||||
void claim() { Claimed = true; }
|
||||
};
|
||||
|
||||
class CheckerProvider {
|
||||
public:
|
||||
virtual ~CheckerProvider();
|
||||
virtual void registerCheckers(CheckerManager &checkerMgr,
|
||||
CheckerOptInfo *checkOpts, unsigned numCheckOpts) = 0;
|
||||
virtual void printHelp(raw_ostream &OS) = 0;
|
||||
};
|
||||
|
||||
} // end ento namespace
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
|
@ -0,0 +1,63 @@
|
|||
//===--- CheckerRegistry.h - Maintains all available checkers ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
|
||||
#define LLVM_CLANG_STATICANALYZER_CORE_CHECKERREGISTRY_H
|
||||
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang {
|
||||
namespace ento {
|
||||
|
||||
class CheckerOptInfo;
|
||||
|
||||
class CheckerRegistry {
|
||||
public:
|
||||
typedef void (*InitializationFunction)(CheckerManager &);
|
||||
struct CheckerInfo {
|
||||
InitializationFunction Initialize;
|
||||
StringRef FullName;
|
||||
StringRef Desc;
|
||||
|
||||
CheckerInfo(InitializationFunction fn, StringRef name, StringRef desc)
|
||||
: Initialize(fn), FullName(name), Desc(desc) {}
|
||||
};
|
||||
|
||||
typedef std::vector<CheckerInfo> CheckerInfoList;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static void initializeManager(CheckerManager &mgr) {
|
||||
mgr.registerChecker<T>();
|
||||
}
|
||||
|
||||
public:
|
||||
void addChecker(InitializationFunction fn, StringRef fullName,
|
||||
StringRef desc);
|
||||
|
||||
template <class T>
|
||||
void addChecker(StringRef fullName, StringRef desc) {
|
||||
addChecker(&initializeManager<T>, fullName, desc);
|
||||
}
|
||||
|
||||
void initializeManager(CheckerManager &mgr,
|
||||
SmallVectorImpl<CheckerOptInfo> &opts) const;
|
||||
void printHelp(raw_ostream &out, size_t maxNameChars = 30) const ;
|
||||
|
||||
private:
|
||||
mutable CheckerInfoList Checkers;
|
||||
mutable llvm::StringMap<size_t> Packages;
|
||||
};
|
||||
|
||||
} // end namespace ento
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
|
@ -1,4 +1,4 @@
|
|||
//===-- CheckerRegistration.h - Checker Registration Function-------*- C++ -*-===//
|
||||
//===-- CheckerRegistration.h - Checker Registration Function ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
|
@ -10,6 +10,9 @@
|
|||
#ifndef LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H
|
||||
#define LLVM_CLANG_SA_FRONTEND_CHECKERREGISTRATION_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
class AnalyzerOptions;
|
||||
class LangOptions;
|
||||
|
@ -18,9 +21,10 @@ namespace clang {
|
|||
namespace ento {
|
||||
class CheckerManager;
|
||||
|
||||
CheckerManager *registerCheckers(const AnalyzerOptions &opts,
|
||||
const LangOptions &langOpts,
|
||||
Diagnostic &diags);
|
||||
CheckerManager *createCheckerManager(const AnalyzerOptions &opts,
|
||||
const LangOptions &langOpts,
|
||||
ArrayRef<std::string> plugins,
|
||||
Diagnostic &diags);
|
||||
|
||||
} // end ento namespace
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ protected:
|
|||
StringRef InFile);
|
||||
};
|
||||
|
||||
void printCheckerHelp(raw_ostream &OS);
|
||||
void printCheckerHelp(raw_ostream &OS, ArrayRef<std::string> plugins);
|
||||
|
||||
} // end GR namespace
|
||||
|
||||
|
|
|
@ -125,12 +125,6 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Honor -analyzer-checker-help.
|
||||
if (Clang->getAnalyzerOpts().ShowCheckerHelp) {
|
||||
ento::printCheckerHelp(llvm::outs());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Honor -version.
|
||||
//
|
||||
// FIXME: Use a better -version message?
|
||||
|
@ -162,6 +156,13 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) {
|
|||
<< Path << Error;
|
||||
}
|
||||
|
||||
// Honor -analyzer-checker-help.
|
||||
// This should happen AFTER plugins have been loaded!
|
||||
if (Clang->getAnalyzerOpts().ShowCheckerHelp) {
|
||||
ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If there were errors in processing arguments, don't do anything else.
|
||||
bool Success = false;
|
||||
if (!Clang->getDiagnostics().hasErrorOccurred()) {
|
||||
|
|
|
@ -22,7 +22,7 @@ add_clang_library(clangStaticAnalyzerCheckers
|
|||
CheckSecuritySyntaxOnly.cpp
|
||||
CheckSizeofPointer.cpp
|
||||
ChrootChecker.cpp
|
||||
ClangSACheckerProvider.cpp
|
||||
ClangCheckers.cpp
|
||||
DeadStoresChecker.cpp
|
||||
DebugCheckers.cpp
|
||||
DereferenceChecker.cpp
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
//===--- ClangCheckers.h - Provides builtin checkers ------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
|
||||
|
||||
// FIXME: This is only necessary as long as there are checker registration
|
||||
// functions that do additional work besides mgr.registerChecker<CLASS>().
|
||||
// The only checkers that currently do this are:
|
||||
// - NSAutoreleasePoolChecker
|
||||
// - NSErrorChecker
|
||||
// - ObjCAtSyncChecker
|
||||
// It's probably worth including this information in Checkers.td to minimize
|
||||
// boilerplate code.
|
||||
#include "ClangSACheckers.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
void ento::registerBuiltinCheckers(CheckerRegistry ®istry) {
|
||||
#define GET_CHECKERS
|
||||
#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \
|
||||
registry.addChecker(register##CLASS, FULLNAME, HELPTEXT);
|
||||
#include "Checkers.inc"
|
||||
#undef GET_CHECKERS
|
||||
}
|
|
@ -1,289 +0,0 @@
|
|||
//===--- ClangSACheckerProvider.cpp - Clang SA Checkers Provider ----------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines the CheckerProvider for the checkers defined in
|
||||
// libclangStaticAnalyzerCheckers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangSACheckerProvider.h"
|
||||
#include "ClangSACheckers.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "map"
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
namespace {
|
||||
|
||||
/// \brief Provider for all the checkers in libclangStaticAnalyzerCheckers.
|
||||
class ClangSACheckerProvider : public CheckerProvider {
|
||||
public:
|
||||
virtual void registerCheckers(CheckerManager &checkerMgr,
|
||||
CheckerOptInfo *checkOpts, unsigned numCheckOpts);
|
||||
virtual void printHelp(raw_ostream &OS);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
CheckerProvider *ento::createClangSACheckerProvider() {
|
||||
return new ClangSACheckerProvider();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct StaticCheckerInfoRec {
|
||||
const char *FullName;
|
||||
void (*RegFunc)(CheckerManager &mgr);
|
||||
const char *HelpText;
|
||||
int GroupIndex;
|
||||
bool Hidden;
|
||||
};
|
||||
|
||||
struct StaticPackageInfoRec {
|
||||
const char *FullName;
|
||||
int GroupIndex;
|
||||
bool Hidden;
|
||||
};
|
||||
|
||||
struct StaticGroupInfoRec {
|
||||
const char *FullName;
|
||||
};
|
||||
|
||||
} // end anonymous namespace.
|
||||
|
||||
static const StaticPackageInfoRec StaticPackageInfo[] = {
|
||||
#define GET_PACKAGES
|
||||
#define PACKAGE(FULLNAME, GROUPINDEX, HIDDEN) \
|
||||
{ FULLNAME, GROUPINDEX, HIDDEN },
|
||||
#include "Checkers.inc"
|
||||
{ 0, -1, 0 }
|
||||
#undef PACKAGE
|
||||
#undef GET_PACKAGES
|
||||
};
|
||||
|
||||
static const unsigned NumPackages = sizeof(StaticPackageInfo)
|
||||
/ sizeof(StaticPackageInfoRec) - 1;
|
||||
|
||||
static const StaticGroupInfoRec StaticGroupInfo[] = {
|
||||
#define GET_GROUPS
|
||||
#define GROUP(FULLNAME) \
|
||||
{ FULLNAME },
|
||||
#include "Checkers.inc"
|
||||
{ 0 }
|
||||
#undef GROUP
|
||||
#undef GET_GROUPS
|
||||
};
|
||||
|
||||
static const unsigned NumGroups = sizeof(StaticGroupInfo)
|
||||
/ sizeof(StaticGroupInfoRec) - 1;
|
||||
|
||||
static const StaticCheckerInfoRec StaticCheckerInfo[] = {
|
||||
#define GET_CHECKERS
|
||||
#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,GROUPINDEX,HIDDEN) \
|
||||
{ FULLNAME, register##CLASS, HELPTEXT, GROUPINDEX, HIDDEN },
|
||||
#include "Checkers.inc"
|
||||
{ 0, 0, 0, -1, 0}
|
||||
#undef CHECKER
|
||||
#undef GET_CHECKERS
|
||||
};
|
||||
|
||||
static const unsigned NumCheckers = sizeof(StaticCheckerInfo)
|
||||
/ sizeof(StaticCheckerInfoRec) - 1;
|
||||
|
||||
namespace {
|
||||
|
||||
struct CheckNameOption {
|
||||
const char *Name;
|
||||
const short *Members;
|
||||
const short *SubGroups;
|
||||
bool Hidden;
|
||||
};
|
||||
|
||||
} // end anonymous namespace.
|
||||
|
||||
#define GET_MEMBER_ARRAYS
|
||||
#include "Checkers.inc"
|
||||
#undef GET_MEMBER_ARRAYS
|
||||
|
||||
// The table of check name options, sorted by name for fast binary lookup.
|
||||
static const CheckNameOption CheckNameTable[] = {
|
||||
#define GET_CHECKNAME_TABLE
|
||||
#include "Checkers.inc"
|
||||
#undef GET_CHECKNAME_TABLE
|
||||
};
|
||||
static const size_t
|
||||
CheckNameTableSize = sizeof(CheckNameTable) / sizeof(CheckNameTable[0]);
|
||||
|
||||
static bool CheckNameOptionCompare(const CheckNameOption &LHS,
|
||||
const CheckNameOption &RHS) {
|
||||
return strcmp(LHS.Name, RHS.Name) < 0;
|
||||
}
|
||||
|
||||
static void collectCheckers(const CheckNameOption *checkName,
|
||||
bool enable,
|
||||
llvm::DenseSet<const StaticCheckerInfoRec *> &checkers,
|
||||
bool collectHidden) {
|
||||
if (checkName->Hidden && !collectHidden)
|
||||
return;
|
||||
|
||||
if (const short *member = checkName->Members) {
|
||||
if (enable) {
|
||||
for (; *member != -1; ++member)
|
||||
if (collectHidden || !StaticCheckerInfo[*member].Hidden)
|
||||
checkers.insert(&StaticCheckerInfo[*member]);
|
||||
} else {
|
||||
for (; *member != -1; ++member)
|
||||
checkers.erase(&StaticCheckerInfo[*member]);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable/disable all subgroups along with this one.
|
||||
if (const short *subGroups = checkName->SubGroups) {
|
||||
for (; *subGroups != -1; ++subGroups) {
|
||||
const CheckNameOption *sub = &CheckNameTable[*subGroups];
|
||||
collectCheckers(sub, enable, checkers, collectHidden && !sub->Hidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void collectCheckers(CheckerOptInfo &opt,
|
||||
llvm::DenseSet<const StaticCheckerInfoRec *> &checkers) {
|
||||
const char *optName = opt.getName();
|
||||
CheckNameOption key = { optName, 0, 0, false };
|
||||
const CheckNameOption *found =
|
||||
std::lower_bound(CheckNameTable, CheckNameTable + CheckNameTableSize, key,
|
||||
CheckNameOptionCompare);
|
||||
if (found == CheckNameTable + CheckNameTableSize ||
|
||||
strcmp(found->Name, optName) != 0)
|
||||
return; // Check name not found.
|
||||
|
||||
opt.claim();
|
||||
collectCheckers(found, opt.isEnabled(), checkers, /*collectHidden=*/true);
|
||||
}
|
||||
|
||||
void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr,
|
||||
CheckerOptInfo *checkOpts, unsigned numCheckOpts) {
|
||||
llvm::DenseSet<const StaticCheckerInfoRec *> enabledCheckers;
|
||||
for (unsigned i = 0; i != numCheckOpts; ++i)
|
||||
collectCheckers(checkOpts[i], enabledCheckers);
|
||||
for (llvm::DenseSet<const StaticCheckerInfoRec *>::iterator
|
||||
I = enabledCheckers.begin(), E = enabledCheckers.end(); I != E; ++I) {
|
||||
(*I)->RegFunc(checkerMgr);
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Printing Help.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void printPackageOption(raw_ostream &OS) {
|
||||
// Find the maximum option length.
|
||||
unsigned OptionFieldWidth = 0;
|
||||
for (unsigned i = 0; i != NumPackages; ++i) {
|
||||
// Limit the amount of padding we are willing to give up for alignment.
|
||||
unsigned Length = strlen(StaticPackageInfo[i].FullName);
|
||||
if (Length <= 30)
|
||||
OptionFieldWidth = std::max(OptionFieldWidth, Length);
|
||||
}
|
||||
|
||||
const unsigned InitialPad = 2;
|
||||
for (unsigned i = 0; i != NumPackages; ++i) {
|
||||
const StaticPackageInfoRec &package = StaticPackageInfo[i];
|
||||
const std::string &Option = package.FullName;
|
||||
int Pad = OptionFieldWidth - int(Option.size());
|
||||
OS.indent(InitialPad) << Option;
|
||||
|
||||
if (package.GroupIndex != -1 || package.Hidden) {
|
||||
// Break on long option names.
|
||||
if (Pad < 0) {
|
||||
OS << "\n";
|
||||
Pad = OptionFieldWidth + InitialPad;
|
||||
}
|
||||
OS.indent(Pad + 1) << "[";
|
||||
if (package.GroupIndex != -1) {
|
||||
OS << "Group=" << StaticGroupInfo[package.GroupIndex].FullName;
|
||||
if (package.Hidden)
|
||||
OS << ", ";
|
||||
}
|
||||
if (package.Hidden)
|
||||
OS << "Hidden";
|
||||
OS << "]";
|
||||
}
|
||||
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
typedef std::map<std::string, const StaticCheckerInfoRec *> SortedCheckers;
|
||||
|
||||
static void printCheckerOption(raw_ostream &OS,SortedCheckers &checkers) {
|
||||
// Find the maximum option length.
|
||||
unsigned OptionFieldWidth = 0;
|
||||
for (SortedCheckers::iterator
|
||||
I = checkers.begin(), E = checkers.end(); I != E; ++I) {
|
||||
// Limit the amount of padding we are willing to give up for alignment.
|
||||
unsigned Length = strlen(I->second->FullName);
|
||||
if (Length <= 30)
|
||||
OptionFieldWidth = std::max(OptionFieldWidth, Length);
|
||||
}
|
||||
|
||||
const unsigned InitialPad = 2;
|
||||
for (SortedCheckers::iterator
|
||||
I = checkers.begin(), E = checkers.end(); I != E; ++I) {
|
||||
const std::string &Option = I->first;
|
||||
const StaticCheckerInfoRec &checker = *I->second;
|
||||
int Pad = OptionFieldWidth - int(Option.size());
|
||||
OS.indent(InitialPad) << Option;
|
||||
|
||||
// Break on long option names.
|
||||
if (Pad < 0) {
|
||||
OS << "\n";
|
||||
Pad = OptionFieldWidth + InitialPad;
|
||||
}
|
||||
OS.indent(Pad + 1) << checker.HelpText;
|
||||
|
||||
if (checker.GroupIndex != -1 || checker.Hidden) {
|
||||
OS << " [";
|
||||
if (checker.GroupIndex != -1) {
|
||||
OS << "Group=" << StaticGroupInfo[checker.GroupIndex].FullName;
|
||||
if (checker.Hidden)
|
||||
OS << ", ";
|
||||
}
|
||||
if (checker.Hidden)
|
||||
OS << "Hidden";
|
||||
OS << "]";
|
||||
}
|
||||
|
||||
OS << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void ClangSACheckerProvider::printHelp(raw_ostream &OS) {
|
||||
OS << "USAGE: -analyzer-checker <CHECKER or PACKAGE or GROUP,...>\n";
|
||||
|
||||
OS << "\nGROUPS:\n";
|
||||
for (unsigned i = 0; i != NumGroups; ++i)
|
||||
OS.indent(2) << StaticGroupInfo[i].FullName << "\n";
|
||||
|
||||
OS << "\nPACKAGES:\n";
|
||||
printPackageOption(OS);
|
||||
|
||||
OS << "\nCHECKERS:\n";
|
||||
|
||||
// Sort checkers according to their full name.
|
||||
SortedCheckers checkers;
|
||||
for (unsigned i = 0; i != NumCheckers; ++i)
|
||||
checkers[StaticCheckerInfo[i].FullName] = &StaticCheckerInfo[i];
|
||||
|
||||
printCheckerOption(OS, checkers);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
//===--- ClangSACheckerProvider.h - Clang SA Checkers Provider --*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines the entry point for creating the provider for the checkers defined
|
||||
// in libclangStaticAnalyzerCheckers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_SA_CHECKERS_CLANGSACHECKERPROVIDER_H
|
||||
#define LLVM_CLANG_SA_CHECKERS_CLANGSACHECKERPROVIDER_H
|
||||
|
||||
namespace clang {
|
||||
|
||||
namespace ento {
|
||||
class CheckerProvider;
|
||||
|
||||
CheckerProvider *createClangSACheckerProvider();
|
||||
|
||||
} // end ento namespace
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
|
@ -19,6 +19,7 @@ namespace clang {
|
|||
|
||||
namespace ento {
|
||||
class CheckerManager;
|
||||
class CheckerRegistry;
|
||||
|
||||
#define GET_CHECKERS
|
||||
#define CHECKER(FULLNAME,CLASS,CXXFILE,HELPTEXT,GROUPINDEX,HIDDEN) \
|
||||
|
|
|
@ -16,6 +16,7 @@ add_clang_library(clangStaticAnalyzerCore
|
|||
CheckerContext.cpp
|
||||
CheckerHelpers.cpp
|
||||
CheckerManager.cpp
|
||||
CheckerRegistry.cpp
|
||||
CoreEngine.cpp
|
||||
Environment.cpp
|
||||
ExplodedGraph.cpp
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
|
||||
#include "clang/Analysis/ProgramPoint.h"
|
||||
|
@ -542,8 +541,5 @@ CheckerManager::~CheckerManager() {
|
|||
CheckerDtors[i]();
|
||||
}
|
||||
|
||||
// Anchor for the vtable.
|
||||
CheckerProvider::~CheckerProvider() { }
|
||||
|
||||
// Anchor for the vtable.
|
||||
GraphExpander::~GraphExpander() { }
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
//===--- CheckerRegistry.cpp - Maintains all available checkers -*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
static const char PackageSeparator = '.';
|
||||
typedef llvm::DenseSet<const CheckerRegistry::CheckerInfo *> CheckerInfoSet;
|
||||
|
||||
|
||||
static bool checkerNameLT(const CheckerRegistry::CheckerInfo &a,
|
||||
const CheckerRegistry::CheckerInfo &b) {
|
||||
return a.FullName < b.FullName;
|
||||
}
|
||||
|
||||
static bool isInPackage(const CheckerRegistry::CheckerInfo &checker,
|
||||
StringRef packageName) {
|
||||
// Does the checker's full name have the package as a prefix?
|
||||
if (!checker.FullName.startswith(packageName))
|
||||
return false;
|
||||
|
||||
// Is the package actually just the name of a specific checker?
|
||||
if (checker.FullName.size() == packageName.size())
|
||||
return true;
|
||||
|
||||
// Is the checker in the package (or a subpackage)?
|
||||
if (checker.FullName[packageName.size()] == PackageSeparator)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void collectCheckers(const CheckerRegistry::CheckerInfoList &checkers,
|
||||
const llvm::StringMap<size_t> &packageSizes,
|
||||
CheckerOptInfo &opt, CheckerInfoSet &collected) {
|
||||
// Use a binary search to find the possible start of the package.
|
||||
CheckerRegistry::CheckerInfo packageInfo(NULL, opt.getName(), "");
|
||||
CheckerRegistry::CheckerInfoList::const_iterator e = checkers.end();
|
||||
CheckerRegistry::CheckerInfoList::const_iterator i =
|
||||
std::lower_bound(checkers.begin(), e, packageInfo, checkerNameLT);
|
||||
|
||||
// If we didn't even find a possible package, give up.
|
||||
if (i == e)
|
||||
return;
|
||||
|
||||
// If what we found doesn't actually start the package, give up.
|
||||
if (!isInPackage(*i, opt.getName()))
|
||||
return;
|
||||
|
||||
// There is at least one checker in the package; claim the option.
|
||||
opt.claim();
|
||||
|
||||
// See how large the package is.
|
||||
// If the package doesn't exist, assume the option refers to a single checker.
|
||||
size_t size = 1;
|
||||
llvm::StringMap<size_t>::const_iterator packageSize =
|
||||
packageSizes.find(opt.getName());
|
||||
if (packageSize != packageSizes.end())
|
||||
size = packageSize->getValue();
|
||||
|
||||
// Step through all the checkers in the package.
|
||||
for (e = i+size; i != e; ++i) {
|
||||
if (opt.isEnabled())
|
||||
collected.insert(&*i);
|
||||
else
|
||||
collected.erase(&*i);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckerRegistry::addChecker(InitializationFunction fn, StringRef name,
|
||||
StringRef desc) {
|
||||
Checkers.push_back(CheckerInfo(fn, name, desc));
|
||||
|
||||
// Record the presence of the checker in its packages.
|
||||
StringRef packageName, leafName;
|
||||
llvm::tie(packageName, leafName) = name.rsplit(PackageSeparator);
|
||||
while (!leafName.empty()) {
|
||||
Packages[packageName] += 1;
|
||||
llvm::tie(packageName, leafName) = packageName.rsplit(PackageSeparator);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckerRegistry::initializeManager(CheckerManager &checkerMgr,
|
||||
SmallVectorImpl<CheckerOptInfo> &opts) const {
|
||||
// Sort checkers for efficient collection.
|
||||
std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
|
||||
|
||||
// Collect checkers enabled by the options.
|
||||
CheckerInfoSet enabledCheckers;
|
||||
for (SmallVectorImpl<CheckerOptInfo>::iterator
|
||||
i = opts.begin(), e = opts.end(); i != e; ++i) {
|
||||
collectCheckers(Checkers, Packages, *i, enabledCheckers);
|
||||
}
|
||||
|
||||
// Initialize the CheckerManager with all enabled checkers.
|
||||
for (CheckerInfoSet::iterator
|
||||
i = enabledCheckers.begin(), e = enabledCheckers.end(); i != e; ++i) {
|
||||
(*i)->Initialize(checkerMgr);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckerRegistry::printHelp(llvm::raw_ostream &out,
|
||||
size_t maxNameChars) const {
|
||||
// FIXME: Alphabetical sort puts 'experimental' in the middle.
|
||||
// Would it be better to name it '~experimental' or something else
|
||||
// that's ASCIIbetically last?
|
||||
std::sort(Checkers.begin(), Checkers.end(), checkerNameLT);
|
||||
|
||||
// FIXME: Print available packages.
|
||||
|
||||
out << "CHECKERS:\n";
|
||||
|
||||
// Find the maximum option length.
|
||||
size_t optionFieldWidth = 0;
|
||||
for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
|
||||
i != e; ++i) {
|
||||
// Limit the amount of padding we are willing to give up for alignment.
|
||||
// Package.Name Description [Hidden]
|
||||
size_t nameLength = i->FullName.size();
|
||||
if (nameLength <= maxNameChars)
|
||||
optionFieldWidth = std::max(optionFieldWidth, nameLength);
|
||||
}
|
||||
|
||||
const size_t initialPad = 2;
|
||||
for (CheckerInfoList::const_iterator i = Checkers.begin(), e = Checkers.end();
|
||||
i != e; ++i) {
|
||||
out.indent(initialPad) << i->FullName;
|
||||
|
||||
int pad = optionFieldWidth - i->FullName.size();
|
||||
|
||||
// Break on long option names.
|
||||
if (pad < 0) {
|
||||
out << '\n';
|
||||
pad = optionFieldWidth + initialPad;
|
||||
}
|
||||
out.indent(pad + 2) << i->Desc;
|
||||
|
||||
out << '\n';
|
||||
}
|
||||
}
|
|
@ -66,6 +66,7 @@ public:
|
|||
const Preprocessor &PP;
|
||||
const std::string OutDir;
|
||||
AnalyzerOptions Opts;
|
||||
ArrayRef<std::string> Plugins;
|
||||
|
||||
// PD is owned by AnalysisManager.
|
||||
PathDiagnosticClient *PD;
|
||||
|
@ -78,9 +79,9 @@ public:
|
|||
|
||||
AnalysisConsumer(const Preprocessor& pp,
|
||||
const std::string& outdir,
|
||||
const AnalyzerOptions& opts)
|
||||
: Ctx(0), PP(pp), OutDir(outdir),
|
||||
Opts(opts), PD(0) {
|
||||
const AnalyzerOptions& opts,
|
||||
ArrayRef<std::string> plugins)
|
||||
: Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins), PD(0) {
|
||||
DigestAnalyzerOptions();
|
||||
}
|
||||
|
||||
|
@ -143,8 +144,8 @@ public:
|
|||
|
||||
virtual void Initialize(ASTContext &Context) {
|
||||
Ctx = &Context;
|
||||
checkerMgr.reset(registerCheckers(Opts, PP.getLangOptions(),
|
||||
PP.getDiagnostics()));
|
||||
checkerMgr.reset(createCheckerManager(Opts, PP.getLangOptions(), Plugins,
|
||||
PP.getDiagnostics()));
|
||||
Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
|
||||
PP.getLangOptions(), PD,
|
||||
CreateStoreMgr, CreateConstraintMgr,
|
||||
|
@ -366,14 +367,13 @@ static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
|
||||
const std::string& OutDir,
|
||||
const AnalyzerOptions& Opts) {
|
||||
llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts));
|
||||
|
||||
// Last, disable the effects of '-Werror' when using the AnalysisConsumer.
|
||||
const std::string& outDir,
|
||||
const AnalyzerOptions& opts,
|
||||
ArrayRef<std::string> plugins) {
|
||||
// Disable the effects of '-Werror' when using the AnalysisConsumer.
|
||||
pp.getDiagnostics().setWarningsAsErrors(false);
|
||||
|
||||
return C.take();
|
||||
return new AnalysisConsumer(pp, outDir, opts, plugins);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef LLVM_CLANG_GR_ANALYSISCONSUMER_H
|
||||
#define LLVM_CLANG_GR_ANALYSISCONSUMER_H
|
||||
|
||||
#include "clang/Basic/LLVM.h"
|
||||
#include <string>
|
||||
|
||||
namespace clang {
|
||||
|
@ -32,7 +33,8 @@ class CheckerManager;
|
|||
/// options.)
|
||||
ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp,
|
||||
const std::string &output,
|
||||
const AnalyzerOptions& Opts);
|
||||
const AnalyzerOptions& opts,
|
||||
ArrayRef<std::string> plugins);
|
||||
|
||||
} // end GR namespace
|
||||
|
||||
|
|
|
@ -13,9 +13,10 @@
|
|||
|
||||
#include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h"
|
||||
#include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
|
||||
#include "../Checkers/ClangSACheckerProvider.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/ClangCheckers.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerOptInfo.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerRegistry.h"
|
||||
#include "clang/Frontend/AnalyzerOptions.h"
|
||||
#include "clang/Frontend/FrontendDiagnostic.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
|
@ -26,9 +27,17 @@
|
|||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts,
|
||||
const LangOptions &langOpts,
|
||||
Diagnostic &diags) {
|
||||
static void registerCheckers(CheckerRegistry ®istry,
|
||||
ArrayRef<std::string> plugins) {
|
||||
registerBuiltinCheckers(registry);
|
||||
|
||||
// FIXME: register plugins.
|
||||
}
|
||||
|
||||
CheckerManager *ento::createCheckerManager(const AnalyzerOptions &opts,
|
||||
const LangOptions &langOpts,
|
||||
ArrayRef<std::string> plugins,
|
||||
Diagnostic &diags) {
|
||||
llvm::OwningPtr<CheckerManager> checkerMgr(new CheckerManager(langOpts));
|
||||
|
||||
SmallVector<CheckerOptInfo, 8> checkerOpts;
|
||||
|
@ -37,11 +46,9 @@ CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts,
|
|||
checkerOpts.push_back(CheckerOptInfo(opt.first.c_str(), opt.second));
|
||||
}
|
||||
|
||||
llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider());
|
||||
provider->registerCheckers(*checkerMgr,
|
||||
checkerOpts.data(), checkerOpts.size());
|
||||
|
||||
// FIXME: Load CheckerProviders from plugins.
|
||||
CheckerRegistry allCheckers;
|
||||
registerCheckers(allCheckers, plugins);
|
||||
allCheckers.initializeManager(*checkerMgr, checkerOpts);
|
||||
|
||||
checkerMgr->finishedCheckerRegistration();
|
||||
|
||||
|
@ -54,12 +61,11 @@ CheckerManager *ento::registerCheckers(const AnalyzerOptions &opts,
|
|||
return checkerMgr.take();
|
||||
}
|
||||
|
||||
void ento::printCheckerHelp(raw_ostream &OS) {
|
||||
OS << "OVERVIEW: Clang Static Analyzer Checkers List\n";
|
||||
OS << '\n';
|
||||
void ento::printCheckerHelp(raw_ostream &out, ArrayRef<std::string> plugins) {
|
||||
out << "OVERVIEW: Clang Static Analyzer Checkers List\n\n";
|
||||
out << "USAGE: -analyzer-checker <CHECKER or PACKAGE,...>\n\n";
|
||||
|
||||
llvm::OwningPtr<CheckerProvider> provider(createClangSACheckerProvider());
|
||||
provider->printHelp(OS);
|
||||
|
||||
// FIXME: Load CheckerProviders from plugins.
|
||||
CheckerRegistry allCheckers;
|
||||
registerCheckers(allCheckers, plugins);
|
||||
allCheckers.printHelp(out);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI,
|
|||
StringRef InFile) {
|
||||
return CreateAnalysisConsumer(CI.getPreprocessor(),
|
||||
CI.getFrontendOpts().OutputFile,
|
||||
CI.getAnalyzerOpts());
|
||||
CI.getAnalyzerOpts(),
|
||||
CI.getFrontendOpts().Plugins);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue