From 50a47e93cebdf22dacb95a6e75a5b803fc4c3e04 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 14 Feb 2011 17:58:52 +0000 Subject: [PATCH] Add the ClangSACheckersEmitter tablegen backend which will be used for the clang static analyzer. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@125493 91177308-0d34-0410-b5e6-96231b3b80d8 --- utils/TableGen/CMakeLists.txt | 1 + utils/TableGen/ClangSACheckersEmitter.cpp | 194 ++++++++++++++++++++++ utils/TableGen/ClangSACheckersEmitter.h | 31 ++++ utils/TableGen/TableGen.cpp | 7 + 4 files changed, 233 insertions(+) create mode 100644 utils/TableGen/ClangSACheckersEmitter.cpp create mode 100644 utils/TableGen/ClangSACheckersEmitter.h diff --git a/utils/TableGen/CMakeLists.txt b/utils/TableGen/CMakeLists.txt index 5c10996a96c..ca3413893e0 100644 --- a/utils/TableGen/CMakeLists.txt +++ b/utils/TableGen/CMakeLists.txt @@ -12,6 +12,7 @@ add_executable(tblgen ClangASTNodesEmitter.cpp ClangAttrEmitter.cpp ClangDiagnosticsEmitter.cpp + ClangSACheckersEmitter.cpp CodeEmitterGen.cpp CodeGenDAGPatterns.cpp CodeGenInstruction.cpp diff --git a/utils/TableGen/ClangSACheckersEmitter.cpp b/utils/TableGen/ClangSACheckersEmitter.cpp new file mode 100644 index 00000000000..05d3f5bfa1f --- /dev/null +++ b/utils/TableGen/ClangSACheckersEmitter.cpp @@ -0,0 +1,194 @@ +//=- ClangSACheckersEmitter.cpp - Generate Clang SA checkers tables -*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits Clang Static Analyzer checkers tables. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckersEmitter.h" +#include "Record.h" +#include "llvm/ADT/DenseSet.h" +#include +#include +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Static Analyzer Checkers Tables generation +//===----------------------------------------------------------------------===// + +/// \brief True if it is specified hidden or a parent package is specified +/// as hidden, otherwise false. +static bool isHidden(const Record &R) { + if (R.getValueAsBit("Hidden")) + return true; + // Not declared as hidden, check the parent package if it is hidden. + if (DefInit *DI = dynamic_cast(R.getValueInit("ParentPackage"))) + return isHidden(*DI->getDef()); + + return false; +} + +static std::string getPackageFullName(Record *R); + +static std::string getParentPackageFullName(Record *R) { + std::string name; + if (DefInit *DI = dynamic_cast(R->getValueInit("ParentPackage"))) + name = getPackageFullName(DI->getDef()); + return name; +} + +static std::string getPackageFullName(Record *R) { + std::string name = getParentPackageFullName(R); + if (!name.empty()) name += "."; + return name + R->getValueAsString("PackageName"); +} + +static std::string getCheckerFullName(Record *R) { + std::string name = getParentPackageFullName(R); + if (!name.empty()) name += "."; + return name + R->getValueAsString("CheckerName"); +} + +namespace { +struct GroupInfo { + std::vector Checkers; + llvm::DenseSet SubGroups; + unsigned Index; +}; +} + +void ClangSACheckersEmitter::run(raw_ostream &OS) { + std::vector checkers = Records.getAllDerivedDefinitions("Checker"); + llvm::DenseMap checkerRecIndexMap; + for (unsigned i = 0, e = checkers.size(); i != e; ++i) + checkerRecIndexMap[checkers[i]] = i; + + 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(R.getValueAsString("CheckerName")) << "\", "; + OS << R.getValueAsString("ClassName") << ", "; + OS << R.getValueAsString("DescFile") << ", "; + OS << "\""; + OS.write_escaped(R.getValueAsString("HelpText")) << "\", "; + // Hidden bit + if (isHidden(R)) + OS << "true"; + else + OS << "false"; + OS << ")\n"; + } + OS << "#endif // GET_CHECKERS\n\n"; + + // Invert the mapping of checkers to package/group into a one to many + // mapping of packages/groups to checkers. + std::map groupInfoByName; + llvm::DenseMap recordGroupMap; + + std::vector packages = Records.getAllDerivedDefinitions("Package"); + for (unsigned i = 0, e = packages.size(); i != e; ++i) { + Record *R = packages[i]; + std::string fullName = getPackageFullName(R); + if (!fullName.empty()) { + GroupInfo &info = groupInfoByName[fullName]; + recordGroupMap[R] = &info; + } + } + + std::vector + checkerGroups = Records.getAllDerivedDefinitions("CheckerGroup"); + for (unsigned i = 0, e = checkerGroups.size(); i != e; ++i) { + Record *R = checkerGroups[i]; + std::string name = R->getValueAsString("GroupName"); + if (!name.empty()) { + GroupInfo &info = groupInfoByName[name]; + recordGroupMap[R] = &info; + } + } + + for (unsigned i = 0, e = checkers.size(); i != e; ++i) { + Record *R = checkers[i]; + std::string fullName = getCheckerFullName(R); + if (!fullName.empty()) { + GroupInfo &info = groupInfoByName[fullName]; + recordGroupMap[R] = &info; + info.Checkers.push_back(R); + Record *currR = R; + // Insert the checker and its parent packages into the set of the + // corresponding parent package. + while (DefInit *DI + = dynamic_cast(currR->getValueInit("ParentPackage"))) { + Record *parentPackage = DI->getDef(); + recordGroupMap[parentPackage]->SubGroups.insert(currR); + currR = parentPackage; + } + // Insert the checker into the set of its group. + if (DefInit *DI = dynamic_cast(R->getValueInit("Group"))) + recordGroupMap[DI->getDef()]->SubGroups.insert(R); + } + } + + unsigned index = 0; + for (std::map::iterator + I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) + I->second.Index = index++; + + // Walk through the packages/groups/checkers emitting an array for each + // set of checkers and an array for each set of subpackages. + + OS << "\n#ifdef GET_MEMBER_ARRAYS\n"; + unsigned maxLen = 0; + for (std::map::iterator + I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { + maxLen = std::max(maxLen, (unsigned)I->first.size()); + + std::vector &V = I->second.Checkers; + if (!V.empty()) { + OS << "static const short CheckerArray" << I->second.Index << "[] = { "; + for (unsigned i = 0, e = V.size(); i != e; ++i) + OS << checkerRecIndexMap[V[i]] << ", "; + OS << "-1 };\n"; + } + + llvm::DenseSet &subGroups = I->second.SubGroups; + if (!subGroups.empty()) { + OS << "static const short SubPackageArray" << I->second.Index << "[] = { "; + for (llvm::DenseSet::iterator + I = subGroups.begin(), E = subGroups.end(); I != E; ++I) { + OS << recordGroupMap[*I]->Index << ", "; + } + OS << "-1 };\n"; + } + } + OS << "#endif // GET_MEMBER_ARRAYS\n\n"; + + OS << "\n#ifdef GET_CHECKNAME_TABLE\n"; + for (std::map::iterator + I = groupInfoByName.begin(), E = groupInfoByName.end(); I != E; ++I) { + // Group option string. + OS << " { \""; + OS.write_escaped(I->first) << "\"," + << std::string(maxLen-I->first.size()+1, ' '); + + if (I->second.Checkers.empty()) + OS << "0, "; + else + OS << "CheckerArray" << I->second.Index << ", "; + + // Subgroups. + if (I->second.SubGroups.empty()) + OS << 0; + else + OS << "SubPackageArray" << I->second.Index; + OS << " },\n"; + } + OS << "#endif // GET_CHECKNAME_TABLE\n\n"; +} diff --git a/utils/TableGen/ClangSACheckersEmitter.h b/utils/TableGen/ClangSACheckersEmitter.h new file mode 100644 index 00000000000..6bd16354732 --- /dev/null +++ b/utils/TableGen/ClangSACheckersEmitter.h @@ -0,0 +1,31 @@ +//===- ClangSACheckersEmitter.h - Generate Clang SA checkers tables -*- C++ -*- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits Clang Static Analyzer checkers tables. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANGSACHECKERS_EMITTER_H +#define CLANGSACHECKERS_EMITTER_H + +#include "TableGenBackend.h" + +namespace llvm { + +class ClangSACheckersEmitter : public TableGenBackend { + RecordKeeper &Records; +public: + explicit ClangSACheckersEmitter(RecordKeeper &R) : Records(R) {} + + void run(raw_ostream &OS); +}; + +} // End llvm namespace + +#endif diff --git a/utils/TableGen/TableGen.cpp b/utils/TableGen/TableGen.cpp index b1503d1563b..3b7dc0193b2 100644 --- a/utils/TableGen/TableGen.cpp +++ b/utils/TableGen/TableGen.cpp @@ -21,6 +21,7 @@ #include "ClangASTNodesEmitter.h" #include "ClangAttrEmitter.h" #include "ClangDiagnosticsEmitter.h" +#include "ClangSACheckersEmitter.h" #include "CodeEmitterGen.h" #include "DAGISelEmitter.h" #include "DisassemblerEmitter.h" @@ -66,6 +67,7 @@ enum ActionType { GenClangDiagGroups, GenClangDeclNodes, GenClangStmtNodes, + GenClangSACheckers, GenDAGISel, GenFastISel, GenOptParserDefs, GenOptParserImpl, @@ -141,6 +143,8 @@ namespace { "Generate Clang AST declaration nodes"), clEnumValN(GenClangStmtNodes, "gen-clang-stmt-nodes", "Generate Clang AST statement nodes"), + clEnumValN(GenClangSACheckers, "gen-clang-sa-checkers", + "Generate Clang Static Analyzer checkers"), clEnumValN(GenLLVMCConf, "gen-llvmc", "Generate LLVMC configuration library"), clEnumValN(GenEDInfo, "gen-enhanced-disassembly-info", @@ -298,6 +302,9 @@ int main(int argc, char **argv) { case GenClangStmtNodes: ClangASTNodesEmitter(Records, "Stmt", "").run(Out.os()); break; + case GenClangSACheckers: + ClangSACheckersEmitter(Records).run(Out.os()); + break; case GenDisassembler: DisassemblerEmitter(Records).run(Out.os()); break; -- 2.34.1