summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorKristof Umann <dkszelethus@gmail.com>2019-01-26 20:06:54 +0000
committerKristof Umann <dkszelethus@gmail.com>2019-01-26 20:06:54 +0000
commit0492ebdda5b955e12a8e74d86166f631499ccebc (patch)
treedcf182cff779d75b78b2ff47d991d5933d03d8a0 /utils
parenteb6faaff295526961edd4b76eb28ac88c591948c (diff)
downloadclang-0492ebdda5b955e12a8e74d86166f631499ccebc.tar.gz
[analyzer] Reimplement dependencies between checkers
Unfortunately, up until now, the fact that certain checkers depended on one another was known, but how these actually unfolded was hidden deep within the implementation. For example, many checkers (like RetainCount, Malloc or CString) modelled a certain functionality, and exposed certain reportable bug types to the user. For example, while MallocChecker models many many different types of memory handling, the actual "unix.MallocChecker" checker the user was exposed to was merely and option to this modeling part. Other than this being an ugly mess, this issue made resolving the checker naming issue almost impossible. (The checker naming issue being that if a checker registered more than one checker within its registry function, both checker object recieved the same name) Also, if the user explicitly disabled a checker that was a dependency of another that _was_ explicitly enabled, it implicitly, without "telling" the user, reenabled it. Clearly, changing this to a well structured, declarative form, where the handling of dependencies are done on a higher level is very much preferred. This patch, among the detailed things later, makes checkers declare their dependencies within the TableGen file Checkers.td, and exposes the same functionality to plugins and statically linked non-generated checkers through CheckerRegistry::addDependency. CheckerRegistry now resolves these dependencies, makes sure that checkers are added to CheckerManager in the correct order, and makes sure that if a dependency is disabled, so will be every checker that depends on it. In detail: * Add a new field to the Checker class in CheckerBase.td called Dependencies, which is a list of Checkers. * Move unix checkers before cplusplus, as there is no forward declaration in tblgen :/ * Add the following new checkers: - StackAddrEscapeBase - StackAddrEscapeBase - CStringModeling - DynamicMemoryModeling (base of the MallocChecker family) - IteratorModeling (base of the IteratorChecker family) - ValistBase - SecuritySyntaxChecker (base of bcmp, bcopy, etc...) - NSOrCFErrorDerefChecker (base of NSErrorChecker and CFErrorChecker) - IvarInvalidationModeling (base of IvarInvalidation checker family) - RetainCountBase (base of RetainCount and OSObjectRetainCount) * Clear up and registry functions in MallocChecker, happily remove old FIXMEs. * Add a new addDependency function to CheckerRegistry. * Neatly format RUN lines in files I looked at while debugging. Big thanks to Artem Degrachev for all the guidance through this project! Differential Revision: https://reviews.llvm.org/D54438 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@352287 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'utils')
-rw-r--r--utils/TableGen/ClangSACheckersEmitter.cpp76
1 files changed, 60 insertions, 16 deletions
diff --git a/utils/TableGen/ClangSACheckersEmitter.cpp b/utils/TableGen/ClangSACheckersEmitter.cpp
index ade1d4ee16..259df5b138 100644
--- a/utils/TableGen/ClangSACheckersEmitter.cpp
+++ b/utils/TableGen/ClangSACheckersEmitter.cpp
@@ -90,6 +90,17 @@ static std::string getCheckerDocs(const Record &R) {
.str();
}
+static void printChecker(llvm::raw_ostream &OS, const Record &R) {
+ OS << "CHECKER(" << "\"";
+ OS.write_escaped(getCheckerFullName(&R)) << "\", ";
+ OS << R.getName() << ", ";
+ OS << "\"";
+ OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
+ OS << "\"";
+ OS.write_escaped(getCheckerDocs(R));
+ OS << "\"";
+}
+
namespace clang {
void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
std::vector<Record*> checkers = Records.getAllDerivedDefinitions("Checker");
@@ -100,7 +111,12 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
OS << "// This file is automatically generated. Do not edit this file by "
"hand.\n";
- OS << "\n#ifdef GET_PACKAGES\n";
+ // Emit packages.
+ //
+ // PACKAGE(PACKAGENAME)
+ // - PACKAGENAME: The name of the package.
+ OS << "\n"
+ "#ifdef GET_PACKAGES\n";
{
SortedRecords sortedPackages;
for (unsigned i = 0, e = packages.size(); i != e; ++i)
@@ -115,22 +131,50 @@ void EmitClangSACheckers(RecordKeeper &Records, raw_ostream &OS) {
OS << ")\n";
}
}
- OS << "#endif // GET_PACKAGES\n\n";
-
- OS << "\n#ifdef GET_CHECKERS\n";
- for (unsigned i = 0, e = checkers.size(); i != e; ++i) {
- const Record &R = *checkers[i];
-
- OS << "CHECKER(" << "\"";
- OS.write_escaped(getCheckerFullName(&R)) << "\", ";
- OS << R.getName() << ", ";
- OS << "\"";
- OS.write_escaped(getStringValue(R, "HelpText")) << "\", ";
- OS << "\"";
- OS.write_escaped(getCheckerDocs(R));
- OS << "\"";
+ OS << "#endif // GET_PACKAGES\n"
+ "\n";
+
+ // Emit checkers.
+ //
+ // CHECKER(FULLNAME, CLASS, HELPTEXT)
+ // - FULLNAME: The full name of the checker, including packages, e.g.:
+ // alpha.cplusplus.UninitializedObject
+ // - CLASS: The name of the checker, with "Checker" appended, e.g.:
+ // UninitializedObjectChecker
+ // - HELPTEXT: The description of the checker.
+ OS << "\n"
+ "#ifdef GET_CHECKERS\n"
+ "\n";
+ for (const Record *checker : checkers) {
+ printChecker(OS, *checker);
OS << ")\n";
}
- OS << "#endif // GET_CHECKERS\n\n";
+ OS << "\n"
+ "#endif // GET_CHECKERS\n"
+ "\n";
+
+ // Emit dependencies.
+ //
+ // CHECKER_DEPENDENCY(FULLNAME, DEPENDENCY)
+ // - FULLNAME: The full name of the checker that depends on another checker.
+ // - DEPENDENCY: The full name of the checker FULLNAME depends on.
+ OS << "\n"
+ "#ifdef GET_CHECKER_DEPENDENCIES\n";
+ for (const Record *checker : checkers) {
+ if (checker->isValueUnset("Dependencies"))
+ continue;
+
+ for (const Record *Dependency :
+ checker->getValueAsListOfDefs("Dependencies")) {
+ OS << "CHECKER_DEPENDENCY(";
+ OS << '\"';
+ OS.write_escaped(getCheckerFullName(checker)) << "\", ";
+ OS << '\"';
+ OS.write_escaped(getCheckerFullName(Dependency)) << '\"';
+ OS << ")\n";
+ }
+ }
+ OS << "\n"
+ "#endif // GET_CHECKER_DEPENDENCIES\n";
}
} // end namespace clang